Merge branch 'origin-master' into ci/delete-merged-caches
|
|
@ -156,6 +156,18 @@ function ccachestatsverbose() {
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
if [[ $RUNNER_OS == macOS ]]; then
|
if [[ $RUNNER_OS == macOS ]]; then
|
||||||
|
# QTDIR is needed for macOS since we actually only use the cached thin Qt binaries instead of the install-qt-action,
|
||||||
|
# which sets a few environment variables
|
||||||
|
if QTDIR=$(find "$GITHUB_WORKSPACE/Qt" -depth -maxdepth 2 -name macos -type d -print -quit); then
|
||||||
|
echo "found QTDIR at $QTDIR"
|
||||||
|
else
|
||||||
|
echo "could not find QTDIR!"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
# the qtdir is located at Qt/[qtversion]/macos
|
||||||
|
# we use find to get the first subfolder with the name "macos"
|
||||||
|
# this works independent of the qt version as there should be only one version installed on the runner at a time
|
||||||
|
export QTDIR
|
||||||
|
|
||||||
if [[ $TARGET_MACOS_VERSION ]]; then
|
if [[ $TARGET_MACOS_VERSION ]]; then
|
||||||
# CMAKE_OSX_DEPLOYMENT_TARGET is a vanilla cmake flag needed to compile to target macOS version
|
# CMAKE_OSX_DEPLOYMENT_TARGET is a vanilla cmake flag needed to compile to target macOS version
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
# used by the ci to rename build artifacts
|
# used by the ci to rename build artifacts
|
||||||
# renames the file to [original name][SUFFIX].[original extension]
|
# renames the file to [original name][SUFFIX].[original extension]
|
||||||
# where SUFFIX is either available in the environment or as the first arg
|
# where SUFFIX is either available in the environment or as the first arg
|
||||||
# if MAKE_ZIP is set instead a zip is made
|
|
||||||
# expected to be run in the build directory unless BUILD_DIR is set
|
# expected to be run in the build directory unless BUILD_DIR is set
|
||||||
# adds output to GITHUB_OUTPUT
|
# adds output to GITHUB_OUTPUT
|
||||||
builddir="${BUILD_DIR:=.}"
|
builddir="${BUILD_DIR:=.}"
|
||||||
|
|
@ -22,8 +21,8 @@ set -e
|
||||||
|
|
||||||
# find file
|
# find file
|
||||||
found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)"
|
found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)"
|
||||||
path="${found%/*}" # remove all after last /
|
path="${found%/*}" # remove all including first "/" from right side
|
||||||
file="${found##*/}" # remove all before last /
|
file="${found##*/}" # remove all including last "/" from left side
|
||||||
if [[ ! $file ]]; then
|
if [[ ! $file ]]; then
|
||||||
echo "::error file=$0::could not find package"
|
echo "::error file=$0::could not find package"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -35,21 +34,16 @@ if ! cd "$path"; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# set filename
|
# set filename
|
||||||
name="${file%.*}" # remove all after last .
|
name="${file%.*}" # remove all including first "." from right side
|
||||||
new_name="$name$SUFFIX."
|
new_name="$name$SUFFIX"
|
||||||
if [[ $MAKE_ZIP ]]; then
|
extension="${file##*.}" # remove all including last "." from left side
|
||||||
filename="${new_name}zip"
|
filename="$new_name.$extension"
|
||||||
echo "creating zip '$filename' from '$file'"
|
echo "renaming '$file' to '$filename'"
|
||||||
zip "$filename" "$file"
|
mv "$file" "$filename"
|
||||||
else
|
|
||||||
extension="${file##*.}" # remove all before last .
|
|
||||||
filename="$new_name$extension"
|
|
||||||
echo "renaming '$file' to '$filename'"
|
|
||||||
mv "$file" "$filename"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$oldpwd"
|
cd "$oldpwd"
|
||||||
relative_path="$path/$filename"
|
relative_path="$path/$filename"
|
||||||
ls -l "$relative_path"
|
ls -l "$relative_path"
|
||||||
echo "path=$relative_path" >>"$GITHUB_OUTPUT"
|
echo "path=$relative_path" >>"$GITHUB_OUTPUT"
|
||||||
echo "name=$filename" >>"$GITHUB_OUTPUT"
|
echo "name=$new_name" >>"$GITHUB_OUTPUT"
|
||||||
|
echo "fullname=$filename" >>"$GITHUB_OUTPUT"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ Available pre-compiled binaries for installation:
|
||||||
|
|
||||||
<b>Windows</b>
|
<b>Windows</b>
|
||||||
• <kbd>Windows 10+</kbd>
|
• <kbd>Windows 10+</kbd>
|
||||||
• <kbd>Windows 7+</kbd>
|
|
||||||
|
|
||||||
<b>macOS</b>
|
<b>macOS</b>
|
||||||
• <kbd>macOS 15+</kbd> <sub><i>Sequoia</i></sub> <sub>Apple M</sub>
|
• <kbd>macOS 15+</kbd> <sub><i>Sequoia</i></sub> <sub>Apple M</sub>
|
||||||
|
|
|
||||||
40
.ci/resolve_latest_aqt_qt_version.sh
Executable file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script is used to resolve the latest patch version of Qt using aqtinstall.
|
||||||
|
# It interprets wildcards to get the latest patch version. E.g. "6.6.*" -> "6.6.3".
|
||||||
|
|
||||||
|
# This script is meant to be used by the ci enironment.
|
||||||
|
# It uses the runner's GITHUB_OUTPUT env variable.
|
||||||
|
|
||||||
|
# Usage example: .ci/resolve_latest_aqt_qt_version.sh "6.6.*"
|
||||||
|
|
||||||
|
qt_spec=$1
|
||||||
|
if [[ ! $qt_spec ]]; then
|
||||||
|
echo "usage: $0 [version]"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If version is already specific (no wildcard), use it as-is
|
||||||
|
if [[ $qt_spec != *"*" ]]; then
|
||||||
|
echo "version $qt_spec is already resolved"
|
||||||
|
echo "version=$qt_spec" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! hash aqt; then
|
||||||
|
echo "aqt could not be found, has aqtinstall been installed?"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Resolve latest patch
|
||||||
|
if ! qt_resolved=$(aqt list-qt mac desktop --spec "$qt_spec" --latest-version); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "resolved $qt_spec to $qt_resolved"
|
||||||
|
if [[ ! $qt_resolved ]]; then
|
||||||
|
echo "Error: Could not resolve Qt version for $qt_spec"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "version=$qt_resolved" >> "$GITHUB_OUTPUT"
|
||||||
25
.ci/thin_macos_qtlib.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# The macos binaries from aqt are fat (universal), so we thin them to the target architecture to reduce the size of
|
||||||
|
# the packages and caches using lipo.
|
||||||
|
|
||||||
|
# This script is meant to be used by the ci enironment on macos runners only.
|
||||||
|
# It uses the runner's GITHUB_WORKSPACE env variable.
|
||||||
|
arch=$(uname -m)
|
||||||
|
nproc=$(sysctl -n hw.ncpu)
|
||||||
|
|
||||||
|
function thin() {
|
||||||
|
local libfile=$1
|
||||||
|
if [[ $(file -b --mime-type "$libfile") == application/x-mach-binary* ]]; then
|
||||||
|
echo "Processing $libfile"
|
||||||
|
lipo "$libfile" -thin "$arch" -output "$libfile"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
export -f thin # export to allow use in xargs
|
||||||
|
export arch
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
echo "::group::Thinning Qt libraries to $arch using $nproc cores"
|
||||||
|
find "$GITHUB_WORKSPACE/Qt" -type f -print0 | xargs -0 -n1 -P"$nproc" -I{} bash -c "thin '{}'"
|
||||||
|
echo "::endgroup::"
|
||||||
6
.github/CONTRIBUTING.md
vendored
|
|
@ -461,7 +461,11 @@ revoke the tag by doing the following:
|
||||||
git push --delete upstream $TAG_NAME
|
git push --delete upstream $TAG_NAME
|
||||||
git tag -d $TAG_NAME
|
git tag -d $TAG_NAME
|
||||||
```
|
```
|
||||||
You can also do this on GitHub, you'll also want to delete the false release.
|
You can also do this on GitHub.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> If you want to push a new release to replace it immediately with the same
|
||||||
|
> name you have to delete the automatically created release first!
|
||||||
|
|
||||||
In the first lines of [CMakeLists.txt](
|
In the first lines of [CMakeLists.txt](
|
||||||
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
||||||
|
|
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,9 +1,12 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
|
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
|
||||||
url: https://discord.gg/3Z9yzmA
|
url: https://discord.com/invite/3Z9yzmA
|
||||||
about: Need help with using the client? Want to find some games? Try the Discord server!
|
about: Need help with using the client? Want to find some games? Try the Discord server!
|
||||||
- name: 🌐 Translations (Help improve the localization of the app)
|
- name: 🌐 Translations (Help improve the localization of the app)
|
||||||
url: https://explore.transifex.com/cockatrice/cockatrice/
|
url: https://explore.transifex.com/cockatrice/cockatrice/
|
||||||
# it is not possible to add a link to the wiki to this description
|
# it is not possible to add a link to the wiki to this description
|
||||||
about: For more information and guidance check our Translation FAQ on our wiki!
|
about: For more information and guidance check our Translation FAQ on our wiki!
|
||||||
|
- name: 📖 Code Documentation
|
||||||
|
url: https://cockatrice.github.io/docs/
|
||||||
|
about: Helpful source focusing on developers, but there are also references for users!
|
||||||
|
|
|
||||||
151
.github/workflows/desktop-build.yml
vendored
|
|
@ -202,6 +202,13 @@ jobs:
|
||||||
--ccache "$CCACHE_SIZE" $NO_CLIENT
|
--ccache "$CCACHE_SIZE" $NO_CLIENT
|
||||||
.ci/name_build.sh
|
.ci/name_build.sh
|
||||||
|
|
||||||
|
# Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342.
|
||||||
|
- name: Delete old compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit && steps.build.outcome == 'success'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
- name: Save compiler cache (ccache)
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
|
|
@ -212,10 +219,10 @@ jobs:
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
id: upload_artifact
|
id: upload_artifact
|
||||||
if: matrix.package != 'skip'
|
if: matrix.package != 'skip'
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.distro}}${{matrix.version}}-package
|
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
|
archive: false
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload to release
|
- name: Upload to release
|
||||||
|
|
@ -225,24 +232,24 @@ jobs:
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
tag_name: ${{needs.configure.outputs.tag}}
|
||||||
|
asset_name: ${{steps.build.outputs.fullname}}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
asset_path: ${{steps.build.outputs.path}}
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
|
||||||
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
||||||
|
|
||||||
- name: Attest binary provenance
|
- name: Attest binary provenance
|
||||||
id: attestation
|
id: attestation
|
||||||
if: steps.upload_release.outcome == 'success'
|
if: steps.upload_release.outcome == 'success'
|
||||||
uses: actions/attest-build-provenance@v3
|
uses: actions/attest@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
subject-path: ${{steps.build.outputs.path}}
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
show-summary: false
|
||||||
|
|
||||||
- name: Verify binary attestation
|
- name: Verify binary attestation
|
||||||
if: steps.attestation.outcome == 'success'
|
if: steps.attestation.outcome == 'success'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
run: gh attestation verify ${{steps.build.outputs.path}} --repo Cockatrice/Cockatrice
|
||||||
|
|
||||||
build-vcpkg:
|
build-vcpkg:
|
||||||
strategy:
|
strategy:
|
||||||
|
|
@ -258,11 +265,9 @@ jobs:
|
||||||
override_target: 13
|
override_target: 13
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS13_Intel"
|
package_suffix: "-macOS13_Intel"
|
||||||
artifact_name: macOS13_Intel-package
|
qt_version: 6.10.*
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cache_qt: false # qt caches take too much space for macOS (1.1Gi)
|
|
||||||
cmake_generator: Ninja
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
|
||||||
|
|
@ -274,11 +279,9 @@ jobs:
|
||||||
type: Release
|
type: Release
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS14"
|
package_suffix: "-macOS14"
|
||||||
artifact_name: macOS14-package
|
qt_version: 6.10.*
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cache_qt: false
|
|
||||||
cmake_generator: Ninja
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
|
||||||
|
|
@ -290,11 +293,9 @@ jobs:
|
||||||
type: Release
|
type: Release
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS15"
|
package_suffix: "-macOS15"
|
||||||
artifact_name: macOS15-package
|
qt_version: 6.10.*
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cache_qt: false
|
|
||||||
cmake_generator: Ninja
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
|
||||||
|
|
@ -304,37 +305,21 @@ jobs:
|
||||||
soc: Apple
|
soc: Apple
|
||||||
xcode: "16.4"
|
xcode: "16.4"
|
||||||
type: Debug
|
type: Debug
|
||||||
qt_version: 6.6.*
|
qt_version: 6.10.*
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cache_qt: false
|
|
||||||
cmake_generator: Ninja
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
|
||||||
- os: Windows
|
|
||||||
target: 7
|
|
||||||
runner: windows-2022
|
|
||||||
type: Release
|
|
||||||
make_package: 1
|
|
||||||
package_suffix: "-Win7"
|
|
||||||
artifact_name: Windows7-installer
|
|
||||||
qt_version: 5.15.*
|
|
||||||
qt_arch: win64_msvc2019_64
|
|
||||||
cache_qt: true
|
|
||||||
cmake_generator: "Visual Studio 17 2022"
|
|
||||||
cmake_generator_platform: x64
|
|
||||||
|
|
||||||
- os: Windows
|
- os: Windows
|
||||||
target: 10
|
target: 10
|
||||||
runner: windows-2022
|
runner: windows-2025
|
||||||
type: Release
|
type: Release
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-Win10"
|
package_suffix: "-Win10"
|
||||||
artifact_name: Windows10-installer
|
qt_version: 6.10.*
|
||||||
qt_version: 6.6.*
|
qt_arch: win64_msvc2022_64
|
||||||
qt_arch: win64_msvc2019_64
|
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cache_qt: true
|
|
||||||
cmake_generator: "Visual Studio 17 2022"
|
cmake_generator: "Visual Studio 17 2022"
|
||||||
cmake_generator_platform: x64
|
cmake_generator_platform: x64
|
||||||
|
|
||||||
|
|
@ -375,13 +360,62 @@ jobs:
|
||||||
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
||||||
restore-keys: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-
|
restore-keys: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-
|
||||||
|
|
||||||
- name: Install Qt ${{matrix.qt_version}}
|
- name: Install aqtinstall
|
||||||
|
if: matrix.os == 'macOS'
|
||||||
|
run: pipx install aqtinstall
|
||||||
|
|
||||||
|
# Checking if there's a newer, uncached version of Qt available to install via aqtinstall
|
||||||
|
- name: Resolve latest Qt patch version
|
||||||
|
if: matrix.os == 'macOS'
|
||||||
|
id: resolve_qt_version
|
||||||
|
shell: bash
|
||||||
|
# Ouputs the version of Qt to install via aqtinstall
|
||||||
|
run: .ci/resolve_latest_aqt_qt_version.sh "${{matrix.qt_version}}"
|
||||||
|
|
||||||
|
- name: Restore thin Qt ${{ steps.resolve_qt_version.outputs.version }} libraries (${{ matrix.soc }} macOS)
|
||||||
|
if: matrix.os == 'macOS'
|
||||||
|
id: restore_qt
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/Qt
|
||||||
|
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
|
||||||
|
|
||||||
|
# Using jurplel/install-qt-action to install Qt without using brew
|
||||||
|
# qt build using vcpkg either just fails or takes too long to build
|
||||||
|
- name: Install fat Qt ${{ steps.resolve_qt_version.outputs.version }} (${{ matrix.soc }} macOS)
|
||||||
|
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
||||||
|
uses: jurplel/install-qt-action@v4
|
||||||
|
with:
|
||||||
|
cache: false
|
||||||
|
version: ${{ steps.resolve_qt_version.outputs.version }}
|
||||||
|
arch: ${{matrix.qt_arch}}
|
||||||
|
modules: ${{matrix.qt_modules}}
|
||||||
|
dir: ${{github.workspace}}
|
||||||
|
|
||||||
|
- name: Thin Qt libraries (${{ matrix.soc }} macOS)
|
||||||
|
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
||||||
|
run: .ci/thin_macos_qtlib.sh
|
||||||
|
|
||||||
|
- name: Cache thin Qt libraries (${{ matrix.soc }} macOS)
|
||||||
|
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
||||||
|
uses: actions/cache/save@v5
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/Qt
|
||||||
|
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Install Qt ${{matrix.qt_version}} (Windows)
|
||||||
|
if: matrix.os == 'Windows'
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{matrix.qt_version}}
|
version: ${{matrix.qt_version}}
|
||||||
arch: ${{matrix.qt_arch}}
|
arch: ${{matrix.qt_arch}}
|
||||||
modules: ${{matrix.qt_modules}}
|
modules: ${{matrix.qt_modules}}
|
||||||
cache: ${{matrix.cache_qt}}
|
cache: true
|
||||||
|
|
||||||
|
- name: Install NSIS
|
||||||
|
if: matrix.os == 'Windows'
|
||||||
|
shell: bash
|
||||||
|
run: choco install nsis
|
||||||
|
|
||||||
- name: Setup vcpkg cache
|
- name: Setup vcpkg cache
|
||||||
id: vcpkg-cache
|
id: vcpkg-cache
|
||||||
|
|
@ -411,6 +445,13 @@ jobs:
|
||||||
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
||||||
run: .ci/compile.sh --server --test --vcpkg
|
run: .ci/compile.sh --server --test --vcpkg
|
||||||
|
|
||||||
|
# Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342.
|
||||||
|
- name: Delete old compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1 && steps.ccache_restore.outputs.cache-hit && steps.build.outcome == 'success'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
- name: Save compiler cache (ccache)
|
||||||
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
|
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
|
|
@ -421,7 +462,8 @@ jobs:
|
||||||
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
||||||
|
|
||||||
- name: Sign app bundle
|
- name: Sign app bundle
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
if: matrix.os == 'macOS' && matrix.make_package && needs.configure.outputs.tag != null
|
||||||
|
id: sign_macos
|
||||||
env:
|
env:
|
||||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
|
|
@ -433,7 +475,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Notarize app bundle
|
- name: Notarize app bundle
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
if: steps.sign_macos.outcome == 'success'
|
||||||
env:
|
env:
|
||||||
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
||||||
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
||||||
|
|
@ -465,46 +507,47 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
id: upload_artifact
|
|
||||||
if: matrix.make_package
|
if: matrix.make_package
|
||||||
uses: actions/upload-artifact@v6
|
id: upload_artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.artifact_name}}
|
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
|
archive: false
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload pdb database
|
- name: Upload PDBs (Program Databases)
|
||||||
if: matrix.os == 'Windows'
|
if: matrix.os == 'Windows' && github.ref_type != 'tag'
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: Windows${{matrix.target}}-debug-pdbs
|
name: ${{steps.build.outputs.name}}-PDBs
|
||||||
path: |
|
path: |
|
||||||
build/cockatrice/Release/*.pdb
|
build/cockatrice/Release/*.pdb
|
||||||
|
build/oracle/Release/*.pdb
|
||||||
build/servatrice/Release/*.pdb
|
build/servatrice/Release/*.pdb
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload to release
|
- name: Upload to release
|
||||||
|
if: needs.configure.outputs.tag != null && matrix.make_package == '1'
|
||||||
id: upload_release
|
id: upload_release
|
||||||
if: needs.configure.outputs.tag != null
|
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
tag_name: ${{needs.configure.outputs.tag}}
|
||||||
|
asset_name: ${{steps.build.outputs.fullname}}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
asset_path: ${{steps.build.outputs.path}}
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
|
||||||
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
||||||
|
|
||||||
- name: Attest binary provenance
|
- name: Attest binary provenance
|
||||||
id: attestation
|
|
||||||
if: steps.upload_release.outcome == 'success'
|
if: steps.upload_release.outcome == 'success'
|
||||||
uses: actions/attest-build-provenance@v3
|
id: attestation
|
||||||
|
uses: actions/attest@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
subject-path: ${{steps.build.outputs.path}}
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
show-summary: false
|
||||||
|
|
||||||
- name: Verify binary attestation
|
- name: Verify binary attestation
|
||||||
if: steps.attestation.outcome == 'success'
|
if: steps.attestation.outcome == 'success'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
run: gh attestation verify ${{steps.build.outputs.path}} --repo Cockatrice/Cockatrice
|
||||||
|
|
|
||||||
9
.github/workflows/docker-release.yml
vendored
|
|
@ -41,10 +41,10 @@ jobs:
|
||||||
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
|
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker buildx
|
- name: Set up Docker buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
if: github.ref_type == 'tag'
|
if: github.ref_type == 'tag'
|
||||||
|
|
@ -62,5 +62,6 @@ jobs:
|
||||||
push: ${{ github.ref_type == 'tag' }}
|
push: ${{ github.ref_type == 'tag' }}
|
||||||
tags: ${{ steps.metadata.outputs.tags }}
|
tags: ${{ steps.metadata.outputs.tags }}
|
||||||
labels: ${{ steps.metadata.outputs.labels }}
|
labels: ${{ steps.metadata.outputs.labels }}
|
||||||
cache-from: type=gha
|
annotations: ${{ steps.metadata.outputs.annotations }}
|
||||||
cache-to: type=gha,mode=max
|
cache-from: type=gha,scope=servatrice
|
||||||
|
cache-to: type=gha,mode=max,scope=servatrice
|
||||||
|
|
|
||||||
4
.github/workflows/documentation-build.yml
vendored
|
|
@ -22,6 +22,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install Graphviz
|
- name: Install Graphviz
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -29,7 +31,7 @@ jobs:
|
||||||
dot -V
|
dot -V
|
||||||
|
|
||||||
- name: Install Doxygen
|
- name: Install Doxygen
|
||||||
uses: ssciwr/doxygen-install@v1
|
uses: ssciwr/doxygen-install@v2
|
||||||
with:
|
with:
|
||||||
version: "1.14.0"
|
version: "1.14.0"
|
||||||
|
|
||||||
|
|
|
||||||
3
.gitmodules
vendored
|
|
@ -1,3 +1,6 @@
|
||||||
[submodule "vcpkg"]
|
[submodule "vcpkg"]
|
||||||
path = vcpkg
|
path = vcpkg
|
||||||
url = https://github.com/microsoft/vcpkg.git
|
url = https://github.com/microsoft/vcpkg.git
|
||||||
|
[submodule "doxygen-awesome-css"]
|
||||||
|
path = doc/doxygen/theme
|
||||||
|
url = https://github.com/jothepro/doxygen-awesome-css.git
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ endif()
|
||||||
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zach@cockatrice.us>")
|
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zach@cockatrice.us>")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}")
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}")
|
||||||
set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team")
|
set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
|
set(CPACK_PACKAGE_DESCRIPTION "Cockatrice is an open-source, multiplatform application for playing tabletop card games over a network. The program's server design prevents users from manipulating the game for unfair advantage. The client also provides a single-player mode, which allows users to brew while offline.")
|
||||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||||
|
|
|
||||||
12
Doxyfile
|
|
@ -54,7 +54,7 @@ PROJECT_NUMBER = $(COCKATRICE_REF)
|
||||||
# for a project that appears at the top of each page and should give viewers a
|
# for a project that appears at the top of each page and should give viewers a
|
||||||
# quick idea about the purpose of the project. Keep the description short.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF = "A cross-platform virtual tabletop for multiplayer card games"
|
PROJECT_BRIEF = "A virtual tabletop for multiplayer card games"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||||
# in the documentation. The maximum height of the logo should not exceed 55
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
|
|
@ -1068,6 +1068,8 @@ RECURSIVE = YES
|
||||||
|
|
||||||
EXCLUDE = build/ \
|
EXCLUDE = build/ \
|
||||||
cmake/ \
|
cmake/ \
|
||||||
|
doc/doxygen/theme/docs/ \
|
||||||
|
doc/doxygen/theme/include/ \
|
||||||
vcpkg/ \
|
vcpkg/ \
|
||||||
webclient/
|
webclient/
|
||||||
|
|
||||||
|
|
@ -1430,7 +1432,9 @@ HTML_STYLESHEET =
|
||||||
# documentation.
|
# documentation.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_EXTRA_STYLESHEET = doc/doxygen/css/doxygen_style.css
|
HTML_EXTRA_STYLESHEET = doc/doxygen/theme/doxygen-awesome.css \
|
||||||
|
doc/doxygen/css/hide_nav_sync.css \
|
||||||
|
doc/doxygen/css/cockatrice_docs_style.css
|
||||||
|
|
||||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
||||||
# other source files which should be copied to the HTML output directory. Note
|
# other source files which should be copied to the HTML output directory. Note
|
||||||
|
|
@ -1453,7 +1457,7 @@ HTML_EXTRA_FILES = doc/doxygen/js/graph_toggle.js
|
||||||
# The default value is: AUTO_LIGHT.
|
# The default value is: AUTO_LIGHT.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_COLORSTYLE = AUTO_DARK
|
HTML_COLORSTYLE = LIGHT
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||||
# will adjust the colors in the style sheet and background images according to
|
# will adjust the colors in the style sheet and background images according to
|
||||||
|
|
@ -1764,7 +1768,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
DISABLE_INDEX = YES
|
DISABLE_INDEX = NO
|
||||||
|
|
||||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||||
# structure should be generated to display hierarchical information. If the tag
|
# structure should be generated to display hierarchical information. If the tag
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ Latest <kbd>beta</kbd> version:
|
||||||
|
|
||||||
# Community Resources [](https://discord.gg/3Z9yzmA)
|
# Community Resources [](https://discord.gg/3Z9yzmA)
|
||||||
|
|
||||||
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other projet contributors (`#dev` channel) or fellow users of the app. Come here to talk about the application, features, or just to hang out.
|
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other project contributors (`#dev` channel) or fellow users of the app. Come here to talk about the application, features, or just to hang out.
|
||||||
- [Official Website](https://cockatrice.github.io)
|
- [Official Website](https://cockatrice.github.io)
|
||||||
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
||||||
- [Official Discord](https://discord.gg/3Z9yzmA)
|
- [Official Discord](https://discord.gg/3Z9yzmA)
|
||||||
|
|
@ -109,7 +109,7 @@ Cockatrice tries to use the [Google Developer Documentation Style Guide](https:/
|
||||||
|
|
||||||
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd>, <kbd>Oracle</kbd> and <kbd>Webatrice</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/).<br>
|
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd>, <kbd>Oracle</kbd> and <kbd>Webatrice</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/).<br>
|
||||||
|
|
||||||
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about getting invovled, and join a group of hundreds of others!<br>
|
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about getting involved, and join a group of hundreds of others!<br>
|
||||||
|
|
||||||
|
|
||||||
# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/docker-release.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
|
# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/docker-release.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ Var PortableMode
|
||||||
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue."
|
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue."
|
||||||
!define MUI_FINISHPAGE_RUN "$INSTDIR/cockatrice.exe"
|
!define MUI_FINISHPAGE_RUN "$INSTDIR/cockatrice.exe"
|
||||||
!define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now"
|
!define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now"
|
||||||
|
!define MUI_ICON "${NSIS_SOURCE_PATH}\cockatrice\resources\appicon.ico"
|
||||||
|
|
||||||
!insertmacro MUI_PAGE_WELCOME
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
!insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\LICENSE"
|
!insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\LICENSE"
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.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_deck_from_website.cpp
|
||||||
src/interface/widgets/dialogs/dlg_load_remote_deck.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_manage_sets.cpp
|
||||||
src/interface/widgets/dialogs/dlg_register.cpp
|
src/interface/widgets/dialogs/dlg_register.cpp
|
||||||
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
|
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
|
||||||
|
|
@ -47,6 +48,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
||||||
src/interface/widgets/dialogs/dlg_update.cpp
|
src/interface/widgets/dialogs/dlg_update.cpp
|
||||||
src/interface/widgets/dialogs/dlg_view_log.cpp
|
src/interface/widgets/dialogs/dlg_view_log.cpp
|
||||||
|
src/interface/widgets/dialogs/override_printing_warning.cpp
|
||||||
src/interface/widgets/dialogs/tip_of_the_day.cpp
|
src/interface/widgets/dialogs/tip_of_the_day.cpp
|
||||||
src/filters/deck_filter_string.cpp
|
src/filters/deck_filter_string.cpp
|
||||||
src/filters/filter_builder.cpp
|
src/filters/filter_builder.cpp
|
||||||
|
|
@ -170,6 +172,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp
|
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp
|
||||||
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp
|
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
|
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
|
||||||
|
src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
||||||
|
|
@ -177,6 +180,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
|
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
|
||||||
src/interface/widgets/deck_editor/deck_state_manager.cpp
|
src/interface/widgets/deck_editor/deck_state_manager.cpp
|
||||||
|
src/interface/widgets/deck_editor/printing_disabled_info_widget.cpp
|
||||||
src/interface/widgets/general/background_sources.cpp
|
src/interface/widgets/general/background_sources.cpp
|
||||||
src/interface/widgets/general/display/background_plate_widget.cpp
|
src/interface/widgets/general/display/background_plate_widget.cpp
|
||||||
src/interface/widgets/general/display/banner_widget.cpp
|
src/interface/widgets/general/display/banner_widget.cpp
|
||||||
|
|
@ -202,6 +206,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/printing_selector/printing_selector.cpp
|
src/interface/widgets/printing_selector/printing_selector.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_display_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_display_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
|
||||||
|
src/interface/widgets/printing_selector/printing_selector_placeholder_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_search_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_search_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp
|
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/printing_selector_card_sorting_widget.cpp
|
||||||
|
|
@ -225,8 +230,11 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/utility/custom_line_edit.cpp
|
src/interface/widgets/utility/custom_line_edit.cpp
|
||||||
src/interface/widgets/utility/get_text_with_max.cpp
|
src/interface/widgets/utility/get_text_with_max.cpp
|
||||||
src/interface/widgets/utility/sequence_edit.cpp
|
src/interface/widgets/utility/sequence_edit.cpp
|
||||||
|
src/interface/widgets/utility/visibility_change_listener.cpp
|
||||||
|
src/interface/widgets/utility/visibility_change_listener.h
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
||||||
|
src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
|
||||||
|
|
@ -235,6 +243,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
||||||
src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp
|
src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp
|
||||||
src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
|
src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
|
||||||
src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
||||||
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,24 @@
|
||||||
<file>resources/icons/arrow_top_green.svg</file>
|
<file>resources/icons/arrow_top_green.svg</file>
|
||||||
<file>resources/icons/arrow_up_green.svg</file>
|
<file>resources/icons/arrow_up_green.svg</file>
|
||||||
<file>resources/icons/arrow_undo.svg</file>
|
<file>resources/icons/arrow_undo.svg</file>
|
||||||
|
<file>resources/icons/circle_half_stroke.svg</file>
|
||||||
<file>resources/icons/clearsearch.svg</file>
|
<file>resources/icons/clearsearch.svg</file>
|
||||||
<file>resources/icons/cogwheel.svg</file>
|
<file>resources/icons/cogwheel.svg</file>
|
||||||
<file>resources/icons/conceded.svg</file>
|
<file>resources/icons/conceded.svg</file>
|
||||||
<file>resources/icons/decrement.svg</file>
|
<file>resources/icons/decrement.svg</file>
|
||||||
<file>resources/icons/delete.svg</file>
|
<file>resources/icons/delete.svg</file>
|
||||||
|
<file>resources/icons/dragon.svg</file>
|
||||||
<file>resources/icons/dropdown_collapsed.svg</file>
|
<file>resources/icons/dropdown_collapsed.svg</file>
|
||||||
<file>resources/icons/dropdown_expanded.svg</file>
|
<file>resources/icons/dropdown_expanded.svg</file>
|
||||||
|
<file>resources/icons/filter.svg</file>
|
||||||
|
<file>resources/icons/floppy_disk.svg</file>
|
||||||
<file>resources/icons/forgot_password.svg</file>
|
<file>resources/icons/forgot_password.svg</file>
|
||||||
|
<file>resources/icons/gear.svg</file>
|
||||||
<file>resources/icons/increment.svg</file>
|
<file>resources/icons/increment.svg</file>
|
||||||
<file>resources/icons/info.svg</file>
|
<file>resources/icons/info.svg</file>
|
||||||
<file>resources/icons/lock.svg</file>
|
<file>resources/icons/lock.svg</file>
|
||||||
<file>resources/icons/not_ready_start.svg</file>
|
<file>resources/icons/not_ready_start.svg</file>
|
||||||
|
<file>resources/icons/pen_to_square.svg</file>
|
||||||
<file>resources/icons/pencil.svg</file>
|
<file>resources/icons/pencil.svg</file>
|
||||||
<file>resources/icons/pin.svg</file>
|
<file>resources/icons/pin.svg</file>
|
||||||
<file>resources/icons/player.svg</file>
|
<file>resources/icons/player.svg</file>
|
||||||
|
|
@ -34,10 +40,13 @@
|
||||||
<file>resources/icons/reload.svg</file>
|
<file>resources/icons/reload.svg</file>
|
||||||
<file>resources/icons/remove_row.svg</file>
|
<file>resources/icons/remove_row.svg</file>
|
||||||
<file>resources/icons/rename.svg</file>
|
<file>resources/icons/rename.svg</file>
|
||||||
|
<file>resources/icons/scale_balanced.svg</file>
|
||||||
<file>resources/icons/scales.svg</file>
|
<file>resources/icons/scales.svg</file>
|
||||||
|
<file>resources/icons/scroll.svg</file>
|
||||||
<file>resources/icons/search.svg</file>
|
<file>resources/icons/search.svg</file>
|
||||||
<file>resources/icons/settings.svg</file>
|
<file>resources/icons/settings.svg</file>
|
||||||
<file>resources/icons/share.svg</file>
|
<file>resources/icons/share.svg</file>
|
||||||
|
<file>resources/icons/sort_arrow_down.svg</file>
|
||||||
<file>resources/icons/spectator.svg</file>
|
<file>resources/icons/spectator.svg</file>
|
||||||
<file>resources/icons/swap.svg</file>
|
<file>resources/icons/swap.svg</file>
|
||||||
<file>resources/icons/sync.svg</file>
|
<file>resources/icons/sync.svg</file>
|
||||||
|
|
@ -52,6 +61,8 @@
|
||||||
<file>resources/icons/mana/W.svg</file>
|
<file>resources/icons/mana/W.svg</file>
|
||||||
|
|
||||||
<file>resources/backgrounds/home.png</file>
|
<file>resources/backgrounds/home.png</file>
|
||||||
|
<file>resources/backgrounds/card_triplet.svg</file>
|
||||||
|
<file>resources/backgrounds/placeholder_printing_selector.svg</file>
|
||||||
|
|
||||||
<file>resources/config/general.svg</file>
|
<file>resources/config/general.svg</file>
|
||||||
<file>resources/config/appearance.svg</file>
|
<file>resources/config/appearance.svg</file>
|
||||||
|
|
|
||||||
31
cockatrice/resources/backgrounds/card_triplet.svg
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
width="250"
|
||||||
|
id="svg13"
|
||||||
|
height="231.66667"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs13" />
|
||||||
|
<g
|
||||||
|
transform="matrix(1.705559,0,0,1.705559,-18.310328,-4.2419088)"
|
||||||
|
id="g13">
|
||||||
|
<path
|
||||||
|
d="M 90.069854,3.479957 C 89.356513,1.2235709 86.980392,-0.01102897 84.723451,0.70218215 L 3.4767601,26.377781 C 1.2199188,27.090982 -0.01486587,29.46663 0.69839437,31.723116 L 33.512365,135.52112 c 0.713341,2.25639 3.089462,3.49099 5.346403,2.77777 l 81.246672,-25.6756 c 2.25684,-0.71319 3.49163,-3.08884 2.77837,-5.34533 L 90.074852,3.479957 Z"
|
||||||
|
style="display:none;fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
d="m 110.61293,7.4983294 c -0.36657,-2.337853 -2.53055,-3.9150142 -4.86886,-3.5484627 L 21.563382,17.14452 c -2.338314,0.366502 -3.915784,2.529976 -3.549207,4.867929 L 34.876507,129.55893 c 0.366577,2.33786 2.530549,3.91502 4.868863,3.54847 l 84.18069,-13.19466 c 2.33831,-0.3665 3.91578,-2.52997 3.5492,-4.86793 L 110.61093,7.4983294 Z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
d="m 130.53623,15.555064 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 41.067426 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 V 124.41102 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208344 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7" />
|
||||||
|
<path
|
||||||
|
d="m 149.43988,26.480639 c 0.38018,-2.335754 -1.1846,-4.508374 -3.52082,-4.88852 L 61.817351,7.9076636 C 59.481136,7.5275576 57.308066,9.0920839 56.927894,11.427736 L 39.439773,118.87426 c -0.380182,2.33576 1.184602,4.50838 3.520816,4.88852 l 84.102711,13.68346 c 2.33622,0.38011 4.50929,-1.18442 4.88946,-3.52007 L 149.43688,26.479639 Z"
|
||||||
|
style="display:inline;fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path10" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.-->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
width="172.65051"
|
||||||
|
id="svg13"
|
||||||
|
height="213.30714"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs13" /><g
|
||||||
|
transform="matrix(1.705559,0,0,1.705559,-97.653345,-68.741256)"
|
||||||
|
id="g13"><path
|
||||||
|
d="m 151.48519,45.063813 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 62.016385 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 V 153.91977 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208345 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7" /><path
|
||||||
|
d="m 154.70135,48.441704 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 65.232545 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 V 157.29767 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208345 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7-5" /><path
|
||||||
|
d="m 157.98403,51.75453 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 68.515228 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 v 108.85596 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208342 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7-6" /></g><path
|
||||||
|
d="m 196.24576,207.42361 c 0,0.11213 0,0.22413 0,0.33621 -0.0498,4.54511 -4.18399,7.63329 -8.72909,7.63329 h -12.19086 c -3.29988,0 -5.97713,2.67727 -5.97713,5.97712 0,0.4234 0.0498,0.83433 0.12449,1.23279 0.26149,1.27014 0.80939,2.49046 1.34485,3.72325 0.75959,1.71843 1.50674,3.4244 1.50674,5.22998 0,3.95986 -2.68971,7.55859 -6.64956,7.72046 -0.43583,0.0128 -0.87166,0.025 -1.31995,0.025 -17.60761,0 -31.878,-14.27038 -31.878,-31.878 0,-17.60761 14.28284,-31.878 31.89046,-31.878 17.60762,0 31.87801,14.27039 31.87801,31.878 z m -47.81703,3.98475 c 0,-2.20407 -1.78067,-3.98475 -3.98473,-3.98475 -2.20407,0 -3.98477,1.78068 -3.98477,3.98475 0,2.20406 1.7807,3.98475 3.98477,3.98475 2.20406,0 3.98473,-1.78069 3.98473,-3.98475 z m 0,-11.95426 c 2.20407,0 3.98477,-1.78068 3.98477,-3.98475 0,-2.20407 -1.7807,-3.98475 -3.98477,-3.98475 -2.20405,0 -3.98473,1.78068 -3.98473,3.98475 0,2.20407 1.78068,3.98475 3.98473,3.98475 z m 19.92376,-11.95424 c 0,-2.20408 -1.78068,-3.98477 -3.98473,-3.98477 -2.20407,0 -3.98477,1.78069 -3.98477,3.98477 0,2.20405 1.7807,3.98474 3.98477,3.98474 2.20405,0 3.98473,-1.78069 3.98473,-3.98474 z m 11.95426,11.95424 c 2.20407,0 3.98475,-1.78068 3.98475,-3.98475 0,-2.20407 -1.78068,-3.98475 -3.98475,-3.98475 -2.20406,0 -3.98475,1.78068 -3.98475,3.98475 0,2.20407 1.78069,3.98475 3.98475,3.98475 z"
|
||||||
|
id="path1"
|
||||||
|
style="display:none;fill:#3b3b3b;fill-opacity:1;stroke:#000000;stroke-width:2.53798;stroke-dasharray:none;stroke-opacity:1" /><path
|
||||||
|
d="M 126.20915,54.574783 82.324247,83.8512 c -5.76807,3.845383 -9.435059,10.089163 -10.029703,16.90777 12.348823,2.53716 22.081191,12.26955 24.638191,24.63819 6.838435,-0.59465 13.062395,-4.26163 16.907775,-10.0297 l 29.2566,-43.904722 c 1.32804,-2.001984 2.04162,-4.340923 2.04162,-6.75915 0,-6.719506 -5.45092,-12.170428 -12.17043,-12.170428 -2.3984,0 -4.75718,0.713573 -6.75915,2.041623 z M 88.052677,131.81933 c 0,-12.26953 -9.930593,-22.20012 -22.200138,-22.20012 -12.269532,0 -22.200126,9.93059 -22.200126,22.20012 0,0.77305 0.03966,1.54609 0.118929,2.2993 0.356787,3.46877 -2.021792,7.21505 -5.510393,7.21505 h -0.951431 c -3.508409,0 -6.342895,2.83447 -6.342895,6.3429 0,3.5084 2.834486,6.34289 6.342895,6.34289 h 28.543021 c 12.269545,0 22.200138,-9.93059 22.200138,-22.20014 z"
|
||||||
|
id="path1-2"
|
||||||
|
style="fill:#989898;fill-opacity:1;stroke-width:0.198215" /></svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
|
|
@ -29,6 +29,11 @@ searches are case insensitive.
|
||||||
<dt><u>F</u>ormat:</dt>
|
<dt><u>F</u>ormat:</dt>
|
||||||
<dd>[f:standard](#f:standard) <small>(Any deck with format set to standard)</small></dd>
|
<dd>[f:standard](#f:standard) <small>(Any deck with format set to standard)</small></dd>
|
||||||
|
|
||||||
|
<dt><u>C</u>omments:</dt>
|
||||||
|
<dd>[c:good](#c:good) <small>(Any deck with comments containing the word good)</small></dd>
|
||||||
|
<dd>[c:good c:deck](#c:good c:deck) <small>(Any deck with comments containing the words good and deck)</small></dd>
|
||||||
|
<dd>[c:"good deck"](#c:%22good deck%22) <small>(Any deck with comments containing the exact phrase "good deck")</small></dd>
|
||||||
|
|
||||||
<dt>Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):</dt>
|
<dt>Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):</dt>
|
||||||
<dd><a href="#[[plains]]">[[plains]]</a> <small>(Any deck that contains at least one card with "plains" in its name)</small></dd>
|
<dd><a href="#[[plains]]">[[plains]]</a> <small>(Any deck that contains at least one card with "plains" in its name)</small></dd>
|
||||||
<dd><a href="#[[t:legendary]]">[[t:legendary]]</a> <small>(Any deck that contains at least one legendary)</small></dd>
|
<dd><a href="#[[t:legendary]]">[[t:legendary]]</a> <small>(Any deck that contains at least one legendary)</small></dd>
|
||||||
|
|
@ -42,6 +47,6 @@ searches are case insensitive.
|
||||||
<dd>[t:aggro OR o:control](#t:aggro OR o:control) <small>(Any deck filename that contains either aggro or control)</small></dd>
|
<dd>[t:aggro OR o:control](#t:aggro OR o:control) <small>(Any deck filename that contains either aggro or control)</small></dd>
|
||||||
|
|
||||||
<dt>Grouping:</dt>
|
<dt>Grouping:</dt>
|
||||||
<dd><a href="#red -([[]]:100 or aggro)">red -([[]]:100 or aggro)</a> <small>(Any deck that has red in its filename but is not 100 cards or has aggro in its filename)</small></dd>
|
<dd><a href="#red -([[]]:100 OR aggro)">red -([[]]:100 OR aggro)</a> <small>(Any deck that has red in its filename but is not 100 cards or has aggro in its filename)</small></dd>
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
@ -51,16 +51,16 @@ In this list of examples below, each entry has an explanation and can be clicked
|
||||||
|
|
||||||
<dt><u>E</u>dition:</dt>
|
<dt><u>E</u>dition:</dt>
|
||||||
<dd>[set:lea](#set:lea) <small>(Cards that appear in Alpha, which has the set code LEA)</small></dd>
|
<dd>[set:lea](#set:lea) <small>(Cards that appear in Alpha, which has the set code LEA)</small></dd>
|
||||||
<dd>[e:lea or e:leb](#e:lea or e:leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
|
<dd>[e:lea OR e:leb](#e:lea OR e:leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
|
||||||
|
|
||||||
<dt>Negate:</dt>
|
<dt>Negate:</dt>
|
||||||
<dd>[c:wu -c:m](#c:wu -c:m) <small>(Any card that is white or blue, but not multicolored)</small></dd>
|
<dd>[c:wu -c:m](#c:wu -c:m) <small>(Any card that is white or blue, but not multicolored)</small></dd>
|
||||||
|
|
||||||
<dt>Branching:</dt>
|
<dt>Branching:</dt>
|
||||||
<dd>[t:sliver or o:changeling](#t:sliver or o:changeling) <small>(Any card that is either a sliver or has changeling)</small></dd>
|
<dd>[t:sliver OR o:changeling](#t:sliver OR o:changeling) <small>(Any card that is either a sliver or has changeling)</small></dd>
|
||||||
|
|
||||||
<dt>Grouping:</dt>
|
<dt>Grouping:</dt>
|
||||||
<dd><a href="#t:angel -(angel or c:w)">t:angel -(angel or c:w)</a> <small>(Any angel that doesn't have angel in its name and isn't white)</small></dd>
|
<dd><a href="#t:angel -(angel OR c:w)">t:angel -(angel OR c:w)</a> <small>(Any angel that doesn't have angel in its name and isn't white)</small></dd>
|
||||||
|
|
||||||
<dt>Regular Expression:</dt>
|
<dt>Regular Expression:</dt>
|
||||||
<dd>[/^fell/](#/^fell/) <small>(Any card name that begins with "fell")</small></dd>
|
<dd>[/^fell/](#/^fell/) <small>(Any card name that begins with "fell")</small></dd>
|
||||||
|
|
|
||||||
1
cockatrice/resources/icons/circle_half_stroke.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M512 320C512 214 426 128 320 128L320 512C426 512 512 426 512 320zM64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320z"/></svg>
|
||||||
|
After Width: | Height: | Size: 410 B |
1
cockatrice/resources/icons/dragon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M352 188.5L300.1 175.5C293.6 173.9 288.8 168.4 288.1 161.7C287.4 155 290.9 148.6 296.8 145.6L337.6 125.2L294.3 92.7C288.8 88.6 286.5 81.4 288.7 74.8C290.9 68.2 297.1 64 304 64L464 64C494.2 64 522.7 78.2 540.8 102.4L598.4 179.2C604.6 187.5 608 197.6 608 208C608 234.5 586.5 256 560 256L538.5 256C521.5 256 505.2 249.3 493.2 237.3L479.9 224L447.9 224L447.9 245.5C447.9 270.3 460.7 293.4 481.7 306.6L588.3 373.2C620.4 393.3 639.9 428.4 639.9 466.3C639.9 526.9 590.8 576.1 530.1 576.1L32.3 576C29 576 25.7 575.6 22.7 574.6C13.5 571.8 6 565 2.3 556C1 552.7 .1 549.1 0 545.3C-.2 541.6 .3 538 1.3 534.6C4.1 525.4 10.9 517.9 19.9 514.2C22.9 513 26.1 512.2 29.4 512L433.3 476C441.6 475.3 448 468.3 448 459.9C448 455.6 446.3 451.5 443.3 448.5L398.9 404.1C368.9 374.1 352 333.4 352 291L352 188.5zM512 136.3C512 136.2 512 136.1 512 136C512 135.9 512 135.8 512 135.7L512 136.3zM510.7 143.7L464.3 132.1C464.1 133.4 464 134.7 464 136C464 149.3 474.7 160 488 160C498.6 160 507.5 153.2 510.7 143.7zM130.9 180.5C147.2 166 171.3 164.3 189.4 176.4L320 263.4L320 290.9C320 323.7 328.4 355.7 344 383.9L112 383.9C105.3 383.9 99.3 379.7 97 373.5C94.7 367.3 96.5 360.2 101.6 355.8L171 296.3L18.4 319.8C11.4 320.9 4.5 317.2 1.5 310.8C-1.5 304.4 .1 296.8 5.4 292L130.9 180.5z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
12
cockatrice/resources/icons/filter.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="800px" height="800px" viewBox="0 0 971.986 971.986"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M370.216,459.3c10.2,11.1,15.8,25.6,15.8,40.6v442c0,26.601,32.1,40.101,51.1,21.4l123.3-141.3
|
||||||
|
c16.5-19.8,25.6-29.601,25.6-49.2V500c0-15,5.7-29.5,15.8-40.601L955.615,75.5c26.5-28.8,6.101-75.5-33.1-75.5h-873
|
||||||
|
c-39.2,0-59.7,46.6-33.1,75.5L370.216,459.3z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 676 B |
1
cockatrice/resources/icons/floppy_disk.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M160 96C124.7 96 96 124.7 96 160L96 480C96 515.3 124.7 544 160 544L480 544C515.3 544 544 515.3 544 480L544 237.3C544 220.3 537.3 204 525.3 192L448 114.7C436 102.7 419.7 96 402.7 96L160 96zM192 192C192 174.3 206.3 160 224 160L384 160C401.7 160 416 174.3 416 192L416 256C416 273.7 401.7 288 384 288L224 288C206.3 288 192 273.7 192 256L192 192zM320 352C355.3 352 384 380.7 384 416C384 451.3 355.3 480 320 480C284.7 480 256 451.3 256 416C256 380.7 284.7 352 320 352z"/></svg>
|
||||||
|
After Width: | Height: | Size: 693 B |
1
cockatrice/resources/icons/gear.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M259.1 73.5C262.1 58.7 275.2 48 290.4 48L350.2 48C365.4 48 378.5 58.7 381.5 73.5L396 143.5C410.1 149.5 423.3 157.2 435.3 166.3L503.1 143.8C517.5 139 533.3 145 540.9 158.2L570.8 210C578.4 223.2 575.7 239.8 564.3 249.9L511 297.3C511.9 304.7 512.3 312.3 512.3 320C512.3 327.7 511.8 335.3 511 342.7L564.4 390.2C575.8 400.3 578.4 417 570.9 430.1L541 481.9C533.4 495 517.6 501.1 503.2 496.3L435.4 473.8C423.3 482.9 410.1 490.5 396.1 496.6L381.7 566.5C378.6 581.4 365.5 592 350.4 592L290.6 592C275.4 592 262.3 581.3 259.3 566.5L244.9 496.6C230.8 490.6 217.7 482.9 205.6 473.8L137.5 496.3C123.1 501.1 107.3 495.1 99.7 481.9L69.8 430.1C62.2 416.9 64.9 400.3 76.3 390.2L129.7 342.7C128.8 335.3 128.4 327.7 128.4 320C128.4 312.3 128.9 304.7 129.7 297.3L76.3 249.8C64.9 239.7 62.3 223 69.8 209.9L99.7 158.1C107.3 144.9 123.1 138.9 137.5 143.7L205.3 166.2C217.4 157.1 230.6 149.5 244.6 143.4L259.1 73.5zM320.3 400C364.5 399.8 400.2 363.9 400 319.7C399.8 275.5 363.9 239.8 319.7 240C275.5 240.2 239.8 276.1 240 320.3C240.2 364.5 276.1 400.2 320.3 400z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
1
cockatrice/resources/icons/pen_to_square.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M535.6 85.7C513.7 63.8 478.3 63.8 456.4 85.7L432 110.1L529.9 208L554.3 183.6C576.2 161.7 576.2 126.3 554.3 104.4L535.6 85.7zM236.4 305.7C230.3 311.8 225.6 319.3 222.9 327.6L193.3 416.4C190.4 425 192.7 434.5 199.1 441C205.5 447.5 215 449.7 223.7 446.8L312.5 417.2C320.7 414.5 328.2 409.8 334.4 403.7L496 241.9L398.1 144L236.4 305.7zM160 128C107 128 64 171 64 224L64 480C64 533 107 576 160 576L416 576C469 576 512 533 512 480L512 384C512 366.3 497.7 352 480 352C462.3 352 448 366.3 448 384L448 480C448 497.7 433.7 512 416 512L160 512C142.3 512 128 497.7 128 480L128 224C128 206.3 142.3 192 160 192L256 192C273.7 192 288 177.7 288 160C288 142.3 273.7 128 256 128L160 128z"/></svg>
|
||||||
|
After Width: | Height: | Size: 899 B |
1
cockatrice/resources/icons/scale_balanced.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M384 96L512 96C529.7 96 544 110.3 544 128C544 145.7 529.7 160 512 160L398.4 160C393.2 185.8 375.5 207.1 352 217.3L352 512L512 512C529.7 512 544 526.3 544 544C544 561.7 529.7 576 512 576L128 576C110.3 576 96 561.7 96 544C96 526.3 110.3 512 128 512L288 512L288 217.3C264.5 207 246.8 185.7 241.6 160L128 160C110.3 160 96 145.7 96 128C96 110.3 110.3 96 128 96L256 96C270.6 76.6 293.8 64 320 64C346.2 64 369.4 76.6 384 96zM439.6 384L584.4 384L512 259.8L439.6 384zM512 480C449.1 480 396.8 446 386 401.1C383.4 390.1 387 378.8 392.7 369L487.9 205.8C492.9 197.2 502.1 192 512 192C521.9 192 531.1 197.3 536.1 205.8L631.3 369C637 378.8 640.6 390.1 638 401.1C627.2 445.9 574.9 480 512 480zM126.8 259.8L54.4 384L199.3 384L126.8 259.8zM.9 401.1C-1.7 390.1 1.9 378.8 7.6 369L102.8 205.8C107.8 197.2 117 192 126.9 192C136.8 192 146 197.3 151 205.8L246.2 369C251.9 378.8 255.5 390.1 252.9 401.1C242.1 445.9 189.8 480 126.9 480C64 480 11.7 446 .9 401.1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
1
cockatrice/resources/icons/scroll.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M32 176C32 134.5 63.6 100.4 104 96.4L104 96L384 96C437 96 480 139 480 192L480 368L304 368C264.2 368 232 400.2 232 440L232 500C232 524.3 212.3 544 188 544C163.7 544 144 524.3 144 500L144 272L80 272C53.5 272 32 250.5 32 224L32 176zM268.8 544C275.9 530.9 280 515.9 280 500L280 440C280 426.7 290.7 416 304 416L552 416C565.3 416 576 426.7 576 440L576 464C576 508.2 540.2 544 496 544L268.8 544zM112 144C94.3 144 80 158.3 80 176L80 224L144 224L144 176C144 158.3 129.7 144 112 144z"/></svg>
|
||||||
|
After Width: | Height: | Size: 704 B |
1
cockatrice/resources/icons/sort_arrow_down.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M278.6 438.6L182.6 534.6C170.1 547.1 149.8 547.1 137.3 534.6L41.3 438.6C28.8 426.1 28.8 405.8 41.3 393.3C53.8 380.8 74.1 380.8 86.6 393.3L128 434.7L128 128C128 110.3 142.3 96 160 96C177.7 96 192 110.3 192 128L192 434.7L233.4 393.3C245.9 380.8 266.2 380.8 278.7 393.3C291.2 405.8 291.2 426.1 278.7 438.6zM352 544C334.3 544 320 529.7 320 512C320 494.3 334.3 480 352 480L384 480C401.7 480 416 494.3 416 512C416 529.7 401.7 544 384 544L352 544zM352 416C334.3 416 320 401.7 320 384C320 366.3 334.3 352 352 352L448 352C465.7 352 480 366.3 480 384C480 401.7 465.7 416 448 416L352 416zM352 288C334.3 288 320 273.7 320 256C320 238.3 334.3 224 352 224L512 224C529.7 224 544 238.3 544 256C544 273.7 529.7 288 512 288L352 288zM352 160C334.3 160 320 145.7 320 128C320 110.3 334.3 96 352 96L576 96C593.7 96 608 110.3 608 128C608 145.7 593.7 160 576 160L352 160z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -8,10 +8,11 @@
|
||||||
#define INTERFACE_JSON_DECK_PARSER_H
|
#define INTERFACE_JSON_DECK_PARSER_H
|
||||||
|
|
||||||
#include "../../../interface/deck_loader/card_node_function.h"
|
#include "../../../interface/deck_loader/card_node_function.h"
|
||||||
#include "../../../interface/deck_loader/deck_loader.h"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <libcockatrice/card/import/card_name_normalizer.h>
|
||||||
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
|
||||||
class IJsonDeckParser
|
class IJsonDeckParser
|
||||||
{
|
{
|
||||||
|
|
@ -49,7 +50,7 @@ public:
|
||||||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
deckList.loadFromStream_Plain(outStream, false);
|
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
return deckList;
|
return deckList;
|
||||||
|
|
@ -96,7 +97,7 @@ public:
|
||||||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
deckList.loadFromStream_Plain(outStream, false);
|
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
QJsonObject commandersObj = obj.value("commanders").toObject();
|
QJsonObject commandersObj = obj.value("commanders").toObject();
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,7 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
homeTabBackgroundSource = settings->value("home/background", "themed").toString();
|
homeTabBackgroundSource = settings->value("home/background", "themed").toString();
|
||||||
homeTabBackgroundShuffleFrequency = settings->value("home/background/shuffleTimer", 0).toInt();
|
homeTabBackgroundShuffleFrequency = settings->value("home/background/shuffleTimer", 0).toInt();
|
||||||
|
homeTabDisplayCardName = settings->value("home/background/displayCardName", true).toBool();
|
||||||
|
|
||||||
tabVisualDeckStorageOpen = settings->value("tabs/visualDeckStorage", true).toBool();
|
tabVisualDeckStorageOpen = settings->value("tabs/visualDeckStorage", true).toBool();
|
||||||
tabServerOpen = settings->value("tabs/server", true).toBool();
|
tabServerOpen = settings->value("tabs/server", true).toBool();
|
||||||
|
|
@ -267,9 +268,6 @@ SettingsCache::SettingsCache()
|
||||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||||
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
|
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
|
||||||
|
|
||||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
|
||||||
tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray();
|
|
||||||
setsDialogGeometry = settings->value("interface/sets_dialog_geometry").toByteArray();
|
|
||||||
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
||||||
spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
|
spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
|
||||||
buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
|
buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
|
||||||
|
|
@ -279,7 +277,6 @@ SettingsCache::SettingsCache()
|
||||||
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
||||||
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
||||||
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
||||||
tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray();
|
|
||||||
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
||||||
useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
|
useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
|
||||||
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
|
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
|
||||||
|
|
@ -309,6 +306,7 @@ SettingsCache::SettingsCache()
|
||||||
visualDeckStorageDefaultTagsList =
|
visualDeckStorageDefaultTagsList =
|
||||||
settings->value("interface/visualdeckstoragedefaulttagslist", defaultTags).toStringList();
|
settings->value("interface/visualdeckstoragedefaulttagslist", defaultTags).toStringList();
|
||||||
visualDeckStorageSearchFolderNames = settings->value("interface/visualdeckstoragesearchfoldernames", true).toBool();
|
visualDeckStorageSearchFolderNames = settings->value("interface/visualdeckstoragesearchfoldernames", true).toBool();
|
||||||
|
visualDeckStorageShowColorIdentity = settings->value("interface/visualdeckstorageshowcoloridentity", true).toBool();
|
||||||
visualDeckStorageShowBannerCardComboBox =
|
visualDeckStorageShowBannerCardComboBox =
|
||||||
settings->value("interface/visualdeckstorageshowbannercardcombobox", true).toBool();
|
settings->value("interface/visualdeckstorageshowbannercardcombobox", true).toBool();
|
||||||
visualDeckStorageShowTagsOnDeckPreviews =
|
visualDeckStorageShowTagsOnDeckPreviews =
|
||||||
|
|
@ -387,6 +385,13 @@ SettingsCache::SettingsCache()
|
||||||
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
||||||
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
|
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
|
||||||
rememberGameSettings = settings->value("game/remembergamesettings", true).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();
|
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
|
||||||
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
||||||
}
|
}
|
||||||
|
|
@ -594,6 +599,13 @@ void SettingsCache::setHomeTabBackgroundShuffleFrequency(int _frequency)
|
||||||
emit homeTabBackgroundShuffleFrequencyChanged();
|
emit homeTabBackgroundShuffleFrequencyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setHomeTabDisplayCardName(QT_STATE_CHANGED_T _displayCardName)
|
||||||
|
{
|
||||||
|
homeTabDisplayCardName = static_cast<bool>(_displayCardName);
|
||||||
|
settings->setValue("home/background/displayCardName", homeTabDisplayCardName);
|
||||||
|
emit homeTabDisplayCardNameChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
||||||
{
|
{
|
||||||
tabVisualDeckStorageOpen = value;
|
tabVisualDeckStorageOpen = value;
|
||||||
|
|
@ -704,12 +716,6 @@ void SettingsCache::setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens)
|
||||||
settings->setValue("interface/annotatetokens", annotateTokens);
|
settings->setValue("interface/annotatetokens", annotateTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes)
|
|
||||||
{
|
|
||||||
tabGameSplitterSizes = _tabGameSplitterSizes;
|
|
||||||
settings->setValue("interface/tabgame_splittersizes", tabGameSplitterSizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
|
void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
|
||||||
{
|
{
|
||||||
showShortcuts = static_cast<bool>(_showShortcuts);
|
showShortcuts = static_cast<bool>(_showShortcuts);
|
||||||
|
|
@ -821,6 +827,13 @@ void SettingsCache::setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T val
|
||||||
settings->setValue("interface/visualdeckstoragesearchfoldernames", visualDeckStorageSearchFolderNames);
|
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)
|
void SettingsCache::setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox)
|
||||||
{
|
{
|
||||||
visualDeckStorageShowBannerCardComboBox = _showBannerCardComboBox;
|
visualDeckStorageShowBannerCardComboBox = _showBannerCardComboBox;
|
||||||
|
|
@ -1074,24 +1087,6 @@ void SettingsCache::setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignore
|
||||||
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setMainWindowGeometry(const QByteArray &_mainWindowGeometry)
|
|
||||||
{
|
|
||||||
mainWindowGeometry = _mainWindowGeometry;
|
|
||||||
settings->setValue("interface/main_window_geometry", mainWindowGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setTokenDialogGeometry(const QByteArray &_tokenDialogGeometry)
|
|
||||||
{
|
|
||||||
tokenDialogGeometry = _tokenDialogGeometry;
|
|
||||||
settings->setValue("interface/token_dialog_geometry", tokenDialogGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setSetsDialogGeometry(const QByteArray &_setsDialogGeometry)
|
|
||||||
{
|
|
||||||
setsDialogGeometry = _setsDialogGeometry;
|
|
||||||
settings->setValue("interface/sets_dialog_geometry", setsDialogGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
||||||
{
|
{
|
||||||
pixmapCacheSize = _pixmapCacheSize;
|
pixmapCacheSize = _pixmapCacheSize;
|
||||||
|
|
@ -1127,257 +1122,21 @@ void SettingsCache::setClientVersion(const QString &_clientVersion)
|
||||||
|
|
||||||
QStringList SettingsCache::getCountries() const
|
QStringList SettingsCache::getCountries() const
|
||||||
{
|
{
|
||||||
static QStringList countries = QStringList() << "ad"
|
static const QStringList countries = {
|
||||||
<< "ae"
|
"ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb",
|
||||||
<< "af"
|
"bd", "be", "bf", "bg", "bh", "bi", "bj", "bl", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bv", "bw", "by",
|
||||||
<< "ag"
|
"bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cw", "cx",
|
||||||
<< "ai"
|
"cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj",
|
||||||
<< "al"
|
"fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr",
|
||||||
<< "am"
|
"gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq",
|
||||||
<< "ao"
|
"ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz",
|
||||||
<< "aq"
|
"la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mf", "mg", "mh",
|
||||||
<< "ar"
|
"mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc",
|
||||||
<< "as"
|
"ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl",
|
||||||
<< "at"
|
"pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se",
|
||||||
<< "au"
|
"sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "sv", "sx", "sy", "sz", "tc", "td",
|
||||||
<< "aw"
|
"tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "um", "us",
|
||||||
<< "ax"
|
"uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "xk", "ye", "yt", "za", "zm", "zw"};
|
||||||
<< "az"
|
|
||||||
<< "ba"
|
|
||||||
<< "bb"
|
|
||||||
<< "bd"
|
|
||||||
<< "be"
|
|
||||||
<< "bf"
|
|
||||||
<< "bg"
|
|
||||||
<< "bh"
|
|
||||||
<< "bi"
|
|
||||||
<< "bj"
|
|
||||||
<< "bl"
|
|
||||||
<< "bm"
|
|
||||||
<< "bn"
|
|
||||||
<< "bo"
|
|
||||||
<< "bq"
|
|
||||||
<< "br"
|
|
||||||
<< "bs"
|
|
||||||
<< "bt"
|
|
||||||
<< "bv"
|
|
||||||
<< "bw"
|
|
||||||
<< "by"
|
|
||||||
<< "bz"
|
|
||||||
<< "ca"
|
|
||||||
<< "cc"
|
|
||||||
<< "cd"
|
|
||||||
<< "cf"
|
|
||||||
<< "cg"
|
|
||||||
<< "ch"
|
|
||||||
<< "ci"
|
|
||||||
<< "ck"
|
|
||||||
<< "cl"
|
|
||||||
<< "cm"
|
|
||||||
<< "cn"
|
|
||||||
<< "co"
|
|
||||||
<< "cr"
|
|
||||||
<< "cu"
|
|
||||||
<< "cv"
|
|
||||||
<< "cw"
|
|
||||||
<< "cx"
|
|
||||||
<< "cy"
|
|
||||||
<< "cz"
|
|
||||||
<< "de"
|
|
||||||
<< "dj"
|
|
||||||
<< "dk"
|
|
||||||
<< "dm"
|
|
||||||
<< "do"
|
|
||||||
<< "dz"
|
|
||||||
<< "ec"
|
|
||||||
<< "ee"
|
|
||||||
<< "eg"
|
|
||||||
<< "eh"
|
|
||||||
<< "er"
|
|
||||||
<< "es"
|
|
||||||
<< "et"
|
|
||||||
<< "eu"
|
|
||||||
<< "fi"
|
|
||||||
<< "fj"
|
|
||||||
<< "fk"
|
|
||||||
<< "fm"
|
|
||||||
<< "fo"
|
|
||||||
<< "fr"
|
|
||||||
<< "ga"
|
|
||||||
<< "gb"
|
|
||||||
<< "gd"
|
|
||||||
<< "ge"
|
|
||||||
<< "gf"
|
|
||||||
<< "gg"
|
|
||||||
<< "gh"
|
|
||||||
<< "gi"
|
|
||||||
<< "gl"
|
|
||||||
<< "gm"
|
|
||||||
<< "gn"
|
|
||||||
<< "gp"
|
|
||||||
<< "gq"
|
|
||||||
<< "gr"
|
|
||||||
<< "gs"
|
|
||||||
<< "gt"
|
|
||||||
<< "gu"
|
|
||||||
<< "gw"
|
|
||||||
<< "gy"
|
|
||||||
<< "hk"
|
|
||||||
<< "hm"
|
|
||||||
<< "hn"
|
|
||||||
<< "hr"
|
|
||||||
<< "ht"
|
|
||||||
<< "hu"
|
|
||||||
<< "id"
|
|
||||||
<< "ie"
|
|
||||||
<< "il"
|
|
||||||
<< "im"
|
|
||||||
<< "in"
|
|
||||||
<< "io"
|
|
||||||
<< "iq"
|
|
||||||
<< "ir"
|
|
||||||
<< "is"
|
|
||||||
<< "it"
|
|
||||||
<< "je"
|
|
||||||
<< "jm"
|
|
||||||
<< "jo"
|
|
||||||
<< "jp"
|
|
||||||
<< "ke"
|
|
||||||
<< "kg"
|
|
||||||
<< "kh"
|
|
||||||
<< "ki"
|
|
||||||
<< "km"
|
|
||||||
<< "kn"
|
|
||||||
<< "kp"
|
|
||||||
<< "kr"
|
|
||||||
<< "kw"
|
|
||||||
<< "ky"
|
|
||||||
<< "kz"
|
|
||||||
<< "la"
|
|
||||||
<< "lb"
|
|
||||||
<< "lc"
|
|
||||||
<< "li"
|
|
||||||
<< "lk"
|
|
||||||
<< "lr"
|
|
||||||
<< "ls"
|
|
||||||
<< "lt"
|
|
||||||
<< "lu"
|
|
||||||
<< "lv"
|
|
||||||
<< "ly"
|
|
||||||
<< "ma"
|
|
||||||
<< "mc"
|
|
||||||
<< "md"
|
|
||||||
<< "me"
|
|
||||||
<< "mf"
|
|
||||||
<< "mg"
|
|
||||||
<< "mh"
|
|
||||||
<< "mk"
|
|
||||||
<< "ml"
|
|
||||||
<< "mm"
|
|
||||||
<< "mn"
|
|
||||||
<< "mo"
|
|
||||||
<< "mp"
|
|
||||||
<< "mq"
|
|
||||||
<< "mr"
|
|
||||||
<< "ms"
|
|
||||||
<< "mt"
|
|
||||||
<< "mu"
|
|
||||||
<< "mv"
|
|
||||||
<< "mw"
|
|
||||||
<< "mx"
|
|
||||||
<< "my"
|
|
||||||
<< "mz"
|
|
||||||
<< "na"
|
|
||||||
<< "nc"
|
|
||||||
<< "ne"
|
|
||||||
<< "nf"
|
|
||||||
<< "ng"
|
|
||||||
<< "ni"
|
|
||||||
<< "nl"
|
|
||||||
<< "no"
|
|
||||||
<< "np"
|
|
||||||
<< "nr"
|
|
||||||
<< "nu"
|
|
||||||
<< "nz"
|
|
||||||
<< "om"
|
|
||||||
<< "pa"
|
|
||||||
<< "pe"
|
|
||||||
<< "pf"
|
|
||||||
<< "pg"
|
|
||||||
<< "ph"
|
|
||||||
<< "pk"
|
|
||||||
<< "pl"
|
|
||||||
<< "pm"
|
|
||||||
<< "pn"
|
|
||||||
<< "pr"
|
|
||||||
<< "ps"
|
|
||||||
<< "pt"
|
|
||||||
<< "pw"
|
|
||||||
<< "py"
|
|
||||||
<< "qa"
|
|
||||||
<< "re"
|
|
||||||
<< "ro"
|
|
||||||
<< "rs"
|
|
||||||
<< "ru"
|
|
||||||
<< "rw"
|
|
||||||
<< "sa"
|
|
||||||
<< "sb"
|
|
||||||
<< "sc"
|
|
||||||
<< "sd"
|
|
||||||
<< "se"
|
|
||||||
<< "sg"
|
|
||||||
<< "sh"
|
|
||||||
<< "si"
|
|
||||||
<< "sj"
|
|
||||||
<< "sk"
|
|
||||||
<< "sl"
|
|
||||||
<< "sm"
|
|
||||||
<< "sn"
|
|
||||||
<< "so"
|
|
||||||
<< "sr"
|
|
||||||
<< "ss"
|
|
||||||
<< "st"
|
|
||||||
<< "sv"
|
|
||||||
<< "sx"
|
|
||||||
<< "sy"
|
|
||||||
<< "sz"
|
|
||||||
<< "tc"
|
|
||||||
<< "td"
|
|
||||||
<< "tf"
|
|
||||||
<< "tg"
|
|
||||||
<< "th"
|
|
||||||
<< "tj"
|
|
||||||
<< "tk"
|
|
||||||
<< "tl"
|
|
||||||
<< "tm"
|
|
||||||
<< "tn"
|
|
||||||
<< "to"
|
|
||||||
<< "tr"
|
|
||||||
<< "tt"
|
|
||||||
<< "tv"
|
|
||||||
<< "tw"
|
|
||||||
<< "tz"
|
|
||||||
<< "ua"
|
|
||||||
<< "ug"
|
|
||||||
<< "um"
|
|
||||||
<< "us"
|
|
||||||
<< "uy"
|
|
||||||
<< "uz"
|
|
||||||
<< "va"
|
|
||||||
<< "vc"
|
|
||||||
<< "ve"
|
|
||||||
<< "vg"
|
|
||||||
<< "vi"
|
|
||||||
<< "vn"
|
|
||||||
<< "vu"
|
|
||||||
<< "wf"
|
|
||||||
<< "ws"
|
|
||||||
<< "xk"
|
|
||||||
<< "ye"
|
|
||||||
<< "yt"
|
|
||||||
<< "za"
|
|
||||||
<< "zm"
|
|
||||||
<< "zw";
|
|
||||||
|
|
||||||
return countries;
|
return countries;
|
||||||
}
|
}
|
||||||
|
|
@ -1490,6 +1249,24 @@ void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
||||||
settings->setValue("game/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)
|
void SettingsCache::setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate)
|
||||||
{
|
{
|
||||||
notifyAboutUpdates = static_cast<bool>(_notifyaboutupdate);
|
notifyAboutUpdates = static_cast<bool>(_notifyaboutupdate);
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ signals:
|
||||||
void themeChanged();
|
void themeChanged();
|
||||||
void homeTabBackgroundSourceChanged();
|
void homeTabBackgroundSourceChanged();
|
||||||
void homeTabBackgroundShuffleFrequencyChanged();
|
void homeTabBackgroundShuffleFrequencyChanged();
|
||||||
|
void homeTabDisplayCardNameChanged();
|
||||||
void picDownloadChanged();
|
void picDownloadChanged();
|
||||||
void showStatusBarChanged(bool state);
|
void showStatusBarChanged(bool state);
|
||||||
void showGameSelectorFilterToolbarChanged(bool state);
|
void showGameSelectorFilterToolbarChanged(bool state);
|
||||||
|
|
@ -157,6 +158,7 @@ signals:
|
||||||
void deckEditorTagsWidgetVisibleChanged(bool _visible);
|
void deckEditorTagsWidgetVisibleChanged(bool _visible);
|
||||||
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
||||||
void visualDeckStorageDefaultTagsListChanged();
|
void visualDeckStorageDefaultTagsListChanged();
|
||||||
|
void visualDeckStorageShowColorIdentityChanged(bool _visible);
|
||||||
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
||||||
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
||||||
void visualDeckStorageCardSizeChanged();
|
void visualDeckStorageCardSizeChanged();
|
||||||
|
|
@ -203,9 +205,6 @@ private:
|
||||||
DebugSettings *debugSettings;
|
DebugSettings *debugSettings;
|
||||||
CardCounterSettings *cardCounterSettings;
|
CardCounterSettings *cardCounterSettings;
|
||||||
|
|
||||||
QByteArray mainWindowGeometry;
|
|
||||||
QByteArray tokenDialogGeometry;
|
|
||||||
QByteArray setsDialogGeometry;
|
|
||||||
QString lang;
|
QString lang;
|
||||||
QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
|
QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
|
||||||
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
||||||
|
|
@ -222,6 +221,7 @@ private:
|
||||||
bool showTipsOnStartup;
|
bool showTipsOnStartup;
|
||||||
QList<int> seenTips;
|
QList<int> seenTips;
|
||||||
int homeTabBackgroundShuffleFrequency;
|
int homeTabBackgroundShuffleFrequency;
|
||||||
|
bool homeTabDisplayCardName;
|
||||||
bool mbDownloadSpoilers;
|
bool mbDownloadSpoilers;
|
||||||
int updateReleaseChannel;
|
int updateReleaseChannel;
|
||||||
int maxFontSize;
|
int maxFontSize;
|
||||||
|
|
@ -235,7 +235,6 @@ private:
|
||||||
bool doNotDeleteArrowsInSubPhases;
|
bool doNotDeleteArrowsInSubPhases;
|
||||||
int startingHandSize;
|
int startingHandSize;
|
||||||
bool annotateTokens;
|
bool annotateTokens;
|
||||||
QByteArray tabGameSplitterSizes;
|
|
||||||
bool showShortcuts;
|
bool showShortcuts;
|
||||||
bool showGameSelectorFilterToolbar;
|
bool showGameSelectorFilterToolbar;
|
||||||
bool displayCardNames;
|
bool displayCardNames;
|
||||||
|
|
@ -249,6 +248,7 @@ private:
|
||||||
bool deckEditorTagsWidgetVisible;
|
bool deckEditorTagsWidgetVisible;
|
||||||
int visualDeckStorageSortingOrder;
|
int visualDeckStorageSortingOrder;
|
||||||
bool visualDeckStorageShowFolders;
|
bool visualDeckStorageShowFolders;
|
||||||
|
bool visualDeckStorageShowColorIdentity;
|
||||||
bool visualDeckStorageShowBannerCardComboBox;
|
bool visualDeckStorageShowBannerCardComboBox;
|
||||||
bool visualDeckStorageShowTagsOnDeckPreviews;
|
bool visualDeckStorageShowTagsOnDeckPreviews;
|
||||||
bool visualDeckStorageShowTagFilter;
|
bool visualDeckStorageShowTagFilter;
|
||||||
|
|
@ -330,6 +330,12 @@ private:
|
||||||
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
||||||
void loadPaths();
|
void loadPaths();
|
||||||
bool rememberGameSettings;
|
bool rememberGameSettings;
|
||||||
|
|
||||||
|
// Local game settings (separate from server game settings in game/*)
|
||||||
|
bool localGameRememberSettings;
|
||||||
|
int localGameMaxPlayers;
|
||||||
|
int localGameStartingLifeTotal;
|
||||||
|
|
||||||
QList<ReleaseChannel *> releaseChannels;
|
QList<ReleaseChannel *> releaseChannels;
|
||||||
bool isPortableBuild;
|
bool isPortableBuild;
|
||||||
bool roundCardCorners;
|
bool roundCardCorners;
|
||||||
|
|
@ -341,18 +347,6 @@ public:
|
||||||
QString getSettingsPath();
|
QString getSettingsPath();
|
||||||
[[nodiscard]] QString getCachePath() const;
|
[[nodiscard]] QString getCachePath() const;
|
||||||
[[nodiscard]] QString getNetworkCachePath() const;
|
[[nodiscard]] QString getNetworkCachePath() const;
|
||||||
[[nodiscard]] const QByteArray &getMainWindowGeometry() const
|
|
||||||
{
|
|
||||||
return mainWindowGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QByteArray &getTokenDialogGeometry() const
|
|
||||||
{
|
|
||||||
return tokenDialogGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QByteArray &getSetsDialogGeometry() const
|
|
||||||
{
|
|
||||||
return setsDialogGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] QString getLang() const
|
[[nodiscard]] QString getLang() const
|
||||||
{
|
{
|
||||||
return lang;
|
return lang;
|
||||||
|
|
@ -413,6 +407,10 @@ public:
|
||||||
{
|
{
|
||||||
return homeTabBackgroundShuffleFrequency;
|
return homeTabBackgroundShuffleFrequency;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getHomeTabDisplayCardName() const
|
||||||
|
{
|
||||||
|
return homeTabDisplayCardName;
|
||||||
|
}
|
||||||
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
|
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
|
||||||
{
|
{
|
||||||
return tabVisualDeckStorageOpen;
|
return tabVisualDeckStorageOpen;
|
||||||
|
|
@ -547,10 +545,6 @@ public:
|
||||||
{
|
{
|
||||||
return annotateTokens;
|
return annotateTokens;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QByteArray getTabGameSplitterSizes() const
|
|
||||||
{
|
|
||||||
return tabGameSplitterSizes;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool getShowShortcuts() const
|
[[nodiscard]] bool getShowShortcuts() const
|
||||||
{
|
{
|
||||||
return showShortcuts;
|
return showShortcuts;
|
||||||
|
|
@ -615,6 +609,10 @@ public:
|
||||||
{
|
{
|
||||||
return visualDeckStorageSearchFolderNames;
|
return visualDeckStorageSearchFolderNames;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getVisualDeckStorageShowColorIdentity() const
|
||||||
|
{
|
||||||
|
return visualDeckStorageShowColorIdentity;
|
||||||
|
}
|
||||||
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
|
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowBannerCardComboBox;
|
return visualDeckStorageShowBannerCardComboBox;
|
||||||
|
|
@ -870,6 +868,18 @@ public:
|
||||||
{
|
{
|
||||||
return rememberGameSettings;
|
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
|
[[nodiscard]] int getKeepAlive() const override
|
||||||
{
|
{
|
||||||
return keepalive;
|
return keepalive;
|
||||||
|
|
@ -983,9 +993,6 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void setDownloadSpoilerStatus(bool _spoilerStatus);
|
void setDownloadSpoilerStatus(bool _spoilerStatus);
|
||||||
|
|
||||||
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
|
|
||||||
void setTokenDialogGeometry(const QByteArray &_tokenDialog);
|
|
||||||
void setSetsDialogGeometry(const QByteArray &_setsDialog);
|
|
||||||
void setLang(const QString &_lang);
|
void setLang(const QString &_lang);
|
||||||
void setShowTipsOnStartup(bool _showTipsOnStartup);
|
void setShowTipsOnStartup(bool _showTipsOnStartup);
|
||||||
void setSeenTips(const QList<int> &_seenTips);
|
void setSeenTips(const QList<int> &_seenTips);
|
||||||
|
|
@ -1001,6 +1008,7 @@ public slots:
|
||||||
void setThemeName(const QString &_themeName);
|
void setThemeName(const QString &_themeName);
|
||||||
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
||||||
void setHomeTabBackgroundShuffleFrequency(int _frequency);
|
void setHomeTabBackgroundShuffleFrequency(int _frequency);
|
||||||
|
void setHomeTabDisplayCardName(QT_STATE_CHANGED_T _displayCardName);
|
||||||
void setTabVisualDeckStorageOpen(bool value);
|
void setTabVisualDeckStorageOpen(bool value);
|
||||||
void setTabServerOpen(bool value);
|
void setTabServerOpen(bool value);
|
||||||
void setTabAccountOpen(bool value);
|
void setTabAccountOpen(bool value);
|
||||||
|
|
@ -1021,7 +1029,6 @@ public slots:
|
||||||
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
||||||
void setStartingHandSize(int _startingHandSize);
|
void setStartingHandSize(int _startingHandSize);
|
||||||
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
||||||
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
|
|
||||||
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
|
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
|
||||||
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
|
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
|
||||||
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
|
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
|
||||||
|
|
@ -1038,6 +1045,7 @@ public slots:
|
||||||
void setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags);
|
void setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags);
|
||||||
void setVisualDeckStorageDefaultTagsList(QStringList _defaultTagsList);
|
void setVisualDeckStorageDefaultTagsList(QStringList _defaultTagsList);
|
||||||
void setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T value);
|
void setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T value);
|
||||||
|
void setVisualDeckStorageShowColorIdentity(QT_STATE_CHANGED_T value);
|
||||||
void setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox);
|
void setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox);
|
||||||
void setVisualDeckStorageShowTagsOnDeckPreviews(QT_STATE_CHANGED_T _showTags);
|
void setVisualDeckStorageShowTagsOnDeckPreviews(QT_STATE_CHANGED_T _showTags);
|
||||||
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
||||||
|
|
@ -1099,6 +1107,9 @@ public slots:
|
||||||
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
||||||
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
|
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
|
||||||
void setRememberGameSettings(const bool _rememberGameSettings);
|
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 setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
|
||||||
void setStartupCardUpdateCheckPromptForUpdate(bool value);
|
void setStartupCardUpdateCheckPromptForUpdate(bool value);
|
||||||
void setStartupCardUpdateCheckAlwaysUpdate(bool value);
|
void setStartupCardUpdateCheckAlwaysUpdate(bool value);
|
||||||
|
|
@ -1110,5 +1121,4 @@ public slots:
|
||||||
void setMaxFontSize(int _max);
|
void setMaxFontSize(int _max);
|
||||||
void setRoundCardCorners(bool _roundCardCorners);
|
void setRoundCardCorners(bool _roundCardCorners);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -598,11 +598,19 @@ private:
|
||||||
{"Player/aMoveTopCardsToGraveyard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
{"Player/aMoveTopCardsToGraveyard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
||||||
parseSequenceString("Alt+M"),
|
parseSequenceString("Alt+M"),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
{"Player/aMoveTopCardsToGraveyardFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_top)},
|
||||||
{"Player/aMoveTopCardToExile",
|
{"Player/aMoveTopCardToExile",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_top)},
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_top)},
|
||||||
{"Player/aMoveTopCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
{"Player/aMoveTopCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
{"Player/aMoveTopCardsToExileFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_top)},
|
||||||
{"Player/aMoveTopCardsUntil", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack Until Found"),
|
{"Player/aMoveTopCardsUntil", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack Until Found"),
|
||||||
parseSequenceString("Ctrl+Shift+Y"),
|
parseSequenceString("Ctrl+Shift+Y"),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
|
@ -620,11 +628,19 @@ private:
|
||||||
{"Player/aMoveBottomCardsToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
{"Player/aMoveBottomCardsToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardsToGraveFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardToExile",
|
{"Player/aMoveBottomCardToExile",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_bottom)},
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
{"Player/aMoveBottomCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardsToExileFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardToTop", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
{"Player/aMoveBottomCardToTop", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
|
||||||
ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
|
ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
|
||||||
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
||||||
|
|
||||||
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / FormatQuery / GenericQuery
|
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / FormatQuery / CommentQuery / GenericQuery
|
||||||
|
|
||||||
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
||||||
|
|
||||||
|
|
@ -25,12 +25,13 @@ DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String
|
||||||
FileNameQuery <- [Ff] ([Nn] / 'ile' ([Nn] 'ame')?) [:] String
|
FileNameQuery <- [Ff] ([Nn] / 'ile' ([Nn] 'ame')?) [:] String
|
||||||
PathQuery <- [Pp] 'ath'? [:] String
|
PathQuery <- [Pp] 'ath'? [:] String
|
||||||
FormatQuery <- [Ff] 'ormat'? [:] String
|
FormatQuery <- [Ff] 'ormat'? [:] String
|
||||||
|
CommentQuery <- [Cc] ('omment' 's'?)? [:] String
|
||||||
|
|
||||||
GenericQuery <- String
|
GenericQuery <- String
|
||||||
|
|
||||||
NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["].
|
NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["].
|
||||||
NonSingleQuoteUnlessEscaped <- "\\\'". / !['].
|
NonSingleQuoteUnlessEscaped <- "\\\'". / !['].
|
||||||
UnescapedStringListPart <- !['":<>=! ].
|
UnescapedStringListPart <- !['":<>()=! ].
|
||||||
SingleApostropheString <- (UnescapedStringListPart+ ws*)* ['] (UnescapedStringListPart+ ws*)*
|
SingleApostropheString <- (UnescapedStringListPart+ ws*)* ['] (UnescapedStringListPart+ ws*)*
|
||||||
|
|
||||||
String <- SingleApostropheString / UnescapedStringListPart+ / ["] <NonDoubleQuoteUnlessEscaped*> ["] / ['] <NonSingleQuoteUnlessEscaped*> [']
|
String <- SingleApostropheString / UnescapedStringListPart+ / ["] <NonDoubleQuoteUnlessEscaped*> ["] / ['] <NonSingleQuoteUnlessEscaped*> [']
|
||||||
|
|
@ -166,6 +167,14 @@ static void setupParserRules()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
search["CommentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
auto value = std::any_cast<QString>(sv[0]);
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||||
|
auto comments = deck->deckLoader->getDeck().deckList.getComments();
|
||||||
|
return comments.contains(value, Qt::CaseInsensitive);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
auto name = std::any_cast<QString>(sv[0]);
|
auto name = std::any_cast<QString>(sv[0]);
|
||||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
#include "abstract_card_drag_item.h"
|
#include "abstract_card_drag_item.h"
|
||||||
|
|
||||||
#include "../../client/settings/cache_settings.h"
|
#include "../../client/settings/cache_settings.h"
|
||||||
|
#include "../z_values.h"
|
||||||
|
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QGraphicsSceneMouseEvent>
|
#include <QGraphicsSceneMouseEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
static const float CARD_WIDTH_HALF = CARD_WIDTH / 2;
|
|
||||||
static const float CARD_HEIGHT_HALF = CARD_HEIGHT / 2;
|
|
||||||
const QColor GHOST_MASK = QColor(255, 255, 255, 50);
|
const QColor GHOST_MASK = QColor(255, 255, 255, 50);
|
||||||
|
|
||||||
AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
|
|
@ -18,19 +17,19 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
{
|
{
|
||||||
if (parentDrag) {
|
if (parentDrag) {
|
||||||
parentDrag->addChildDrag(this);
|
parentDrag->addChildDrag(this);
|
||||||
setZValue(2000000007 + hotSpot.x() * 1000000 + hotSpot.y() * 1000 + 1000);
|
setZValue(ZValues::childDragZValue(hotSpot.x(), hotSpot.y()));
|
||||||
connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
||||||
} else {
|
} else {
|
||||||
hotSpot = QPointF{qBound(0.0, hotSpot.x(), static_cast<qreal>(CARD_WIDTH - 1)),
|
hotSpot = QPointF{qBound(0.0, hotSpot.x(), CardDimensions::WIDTH_F - 1),
|
||||||
qBound(0.0, hotSpot.y(), static_cast<qreal>(CARD_HEIGHT - 1))};
|
qBound(0.0, hotSpot.y(), CardDimensions::HEIGHT_F - 1)};
|
||||||
setCursor(Qt::ClosedHandCursor);
|
setCursor(Qt::ClosedHandCursor);
|
||||||
setZValue(2000000007);
|
setZValue(ZValues::DRAG_ITEM);
|
||||||
}
|
}
|
||||||
if (item->getTapped())
|
if (item->getTapped())
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(90)
|
.rotate(90)
|
||||||
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
|
|
||||||
setCacheMode(DeviceCoordinateCache);
|
setCacheMode(DeviceCoordinateCache);
|
||||||
|
|
||||||
|
|
@ -47,7 +46,7 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
QPainterPath AbstractCardDragItem::shape() const
|
QPainterPath AbstractCardDragItem::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public:
|
||||||
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
|
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
|
||||||
[[nodiscard]] QRectF boundingRect() const override
|
[[nodiscard]] QRectF boundingRect() const override
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
|
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
[[nodiscard]] QPainterPath shape() const override;
|
[[nodiscard]] QPainterPath shape() const override;
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../../client/settings/cache_settings.h"
|
#include "../../client/settings/cache_settings.h"
|
||||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||||
#include "../game_scene.h"
|
#include "../game_scene.h"
|
||||||
|
#include "../z_values.h"
|
||||||
|
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
|
|
@ -38,13 +39,13 @@ AbstractCardItem::~AbstractCardItem()
|
||||||
|
|
||||||
QRectF AbstractCardItem::boundingRect() const
|
QRectF AbstractCardItem::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
|
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainterPath AbstractCardItem::shape() const
|
QPainterPath AbstractCardItem::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
@ -215,9 +216,9 @@ void AbstractCardItem::setHovered(bool _hovered)
|
||||||
if (_hovered)
|
if (_hovered)
|
||||||
processHoverEvent();
|
processHoverEvent();
|
||||||
isHovered = _hovered;
|
isHovered = _hovered;
|
||||||
setZValue(_hovered ? 2000000004 : realZValue);
|
setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue);
|
||||||
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
|
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
|
||||||
setTransformOriginPoint(_hovered ? CARD_WIDTH / 2 : 0, _hovered ? CARD_HEIGHT / 2 : 0);
|
setTransformOriginPoint(_hovered ? CardDimensions::WIDTH_HALF_F : 0, _hovered ? CardDimensions::HEIGHT_HALF_F : 0);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,9 +274,9 @@ void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
|
||||||
else {
|
else {
|
||||||
tapAngle = tapped ? 90 : 0;
|
tapAngle = tapped ? 90 : 0;
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(tapAngle)
|
.rotate(tapAngle)
|
||||||
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define ABSTRACTCARDITEM_H
|
#define ABSTRACTCARDITEM_H
|
||||||
|
|
||||||
#include "../../game_graphics/board/graphics_item_type.h"
|
#include "../../game_graphics/board/graphics_item_type.h"
|
||||||
|
#include "../card_dimensions.h"
|
||||||
#include "arrow_target.h"
|
#include "arrow_target.h"
|
||||||
|
|
||||||
#include <libcockatrice/card/printing/exact_card.h>
|
#include <libcockatrice/card/printing/exact_card.h>
|
||||||
|
|
@ -15,9 +16,6 @@
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
|
|
||||||
const int CARD_WIDTH = 72;
|
|
||||||
const int CARD_HEIGHT = 102;
|
|
||||||
|
|
||||||
class AbstractCardItem : public ArrowTarget
|
class AbstractCardItem : public ArrowTarget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../player/player_actions.h"
|
#include "../player/player_actions.h"
|
||||||
#include "../player/player_target.h"
|
#include "../player/player_target.h"
|
||||||
|
#include "../z_values.h"
|
||||||
#include "../zones/card_zone.h"
|
#include "../zones/card_zone.h"
|
||||||
#include "card_item.h"
|
#include "card_item.h"
|
||||||
|
|
||||||
|
|
@ -18,12 +19,13 @@
|
||||||
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
|
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
|
||||||
#include <libcockatrice/utility/color.h>
|
#include <libcockatrice/utility/color.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
|
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
|
||||||
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false),
|
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false),
|
||||||
color(_color), fullColor(true)
|
color(_color), fullColor(true)
|
||||||
{
|
{
|
||||||
setZValue(2000000005);
|
setZValue(ZValues::ARROWS);
|
||||||
|
|
||||||
if (startItem)
|
if (startItem)
|
||||||
startItem->addArrowFrom(this);
|
startItem->addArrowFrom(this);
|
||||||
|
|
@ -238,16 +240,16 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
|
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
|
||||||
if (startZone->getName() == "hand") {
|
if (startZone->getName() == ZoneNames::HAND) {
|
||||||
startCard->playCard(false);
|
startCard->playCard(false);
|
||||||
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
||||||
bool playToStack = SettingsCache::instance().getPlayToStack();
|
bool playToStack = SettingsCache::instance().getPlayToStack();
|
||||||
if (ci &&
|
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
||||||
((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
(playToStack && ci->getUiAttributes().tableRow != 0 &&
|
||||||
(playToStack && ci->getUiAttributes().tableRow != 0 && startCard->getZone()->getName() != "stack")))
|
startCard->getZone()->getName() != ZoneNames::STACK)))
|
||||||
cmd.set_start_zone("stack");
|
cmd.set_start_zone(ZoneNames::STACK);
|
||||||
else
|
else
|
||||||
cmd.set_start_zone(playToStack ? "stack" : "table");
|
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteInPhase != 0) {
|
if (deleteInPhase != 0) {
|
||||||
|
|
@ -317,7 +319,7 @@ void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
|
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
|
||||||
{
|
{
|
||||||
// do nothing if target is already attached to another card or is not in play
|
// do nothing if target is already attached to another card or is not in play
|
||||||
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != "table") {
|
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,12 +327,12 @@ void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCar
|
||||||
CardZoneLogic *targetZone = targetCard->getZone();
|
CardZoneLogic *targetZone = targetCard->getZone();
|
||||||
|
|
||||||
// move card onto table first if attaching from some other zone
|
// move card onto table first if attaching from some other zone
|
||||||
if (startZone->getName() != "table") {
|
if (startZone->getName() != ZoneNames::TABLE) {
|
||||||
player->getPlayerActions()->playCardToTable(startCard, false);
|
player->getPlayerActions()->playCardToTable(startCard, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_AttachCard cmd;
|
Command_AttachCard cmd;
|
||||||
cmd.set_start_zone("table");
|
cmd.set_start_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_id(startCard->getId());
|
cmd.set_card_id(startCard->getId());
|
||||||
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
|
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone(targetZone->getName().toStdString());
|
cmd.set_target_zone(targetZone->getName().toStdString());
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@
|
||||||
CardDragItem::CardDragItem(CardItem *_item,
|
CardDragItem::CardDragItem(CardItem *_item,
|
||||||
int _id,
|
int _id,
|
||||||
const QPointF &_hotSpot,
|
const QPointF &_hotSpot,
|
||||||
bool _faceDown,
|
bool _forceFaceDown,
|
||||||
AbstractCardDragItem *parentDrag)
|
AbstractCardDragItem *parentDrag)
|
||||||
: AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), faceDown(_faceDown), occupied(false), currentZone(0)
|
: AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), forceFaceDown(_forceFaceDown), occupied(false),
|
||||||
|
currentZone(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class CardDragItem : public AbstractCardDragItem
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
int id;
|
int id;
|
||||||
bool faceDown;
|
bool forceFaceDown;
|
||||||
bool occupied;
|
bool occupied;
|
||||||
CardZone *currentZone;
|
CardZone *currentZone;
|
||||||
|
|
||||||
|
|
@ -24,15 +24,15 @@ public:
|
||||||
CardDragItem(CardItem *_item,
|
CardDragItem(CardItem *_item,
|
||||||
int _id,
|
int _id,
|
||||||
const QPointF &_hotSpot,
|
const QPointF &_hotSpot,
|
||||||
bool _faceDown,
|
bool _forceFaceDown,
|
||||||
AbstractCardDragItem *parentDrag = 0);
|
AbstractCardDragItem *parentDrag = 0);
|
||||||
int getId() const
|
int getId() const
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
bool getFaceDown() const
|
bool isForceFaceDown() const
|
||||||
{
|
{
|
||||||
return faceDown;
|
return forceFaceDown;
|
||||||
}
|
}
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
void updatePosition(const QPointF &cursorScenePos) override;
|
void updatePosition(const QPointF &cursorScenePos) override;
|
||||||
|
|
|
||||||
|
|
@ -212,10 +212,12 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets the fields that should be reset after a zone transition
|
||||||
|
*/
|
||||||
void CardItem::resetState(bool keepAnnotations)
|
void CardItem::resetState(bool keepAnnotations)
|
||||||
{
|
{
|
||||||
attacking = false;
|
attacking = false;
|
||||||
facedown = false;
|
|
||||||
counters.clear();
|
counters.clear();
|
||||||
pt.clear();
|
pt.clear();
|
||||||
if (!keepAnnotations) {
|
if (!keepAnnotations) {
|
||||||
|
|
@ -251,10 +253,10 @@ void CardItem::processCardInfo(const ServerInfo_Card &_info)
|
||||||
setDoesntUntap(_info.doesnt_untap());
|
setDoesntUntap(_info.doesnt_untap());
|
||||||
}
|
}
|
||||||
|
|
||||||
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown)
|
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown)
|
||||||
{
|
{
|
||||||
deleteDragItem();
|
deleteDragItem();
|
||||||
dragItem = new CardDragItem(this, _id, _pos, faceDown);
|
dragItem = new CardDragItem(this, _id, _pos, forceFaceDown);
|
||||||
dragItem->setVisible(false);
|
dragItem->setVisible(false);
|
||||||
scene()->addItem(dragItem);
|
scene()->addItem(dragItem);
|
||||||
dragItem->updatePosition(_scenePos);
|
dragItem->updatePosition(_scenePos);
|
||||||
|
|
@ -352,7 +354,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
|
||||||
// Use the buttonDownPos to align the hot spot with the position when
|
// Use the buttonDownPos to align the hot spot with the position when
|
||||||
// the user originally clicked
|
// the user originally clicked
|
||||||
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), facedown || forceFaceDown);
|
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), forceFaceDown);
|
||||||
dragItem->grabMouse();
|
dragItem->grabMouse();
|
||||||
|
|
||||||
int childIndex = 0;
|
int childIndex = 0;
|
||||||
|
|
@ -365,7 +367,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (zone->getHasCardAttr())
|
if (zone->getHasCardAttr())
|
||||||
childPos = card->pos() - pos();
|
childPos = card->pos() - pos();
|
||||||
else
|
else
|
||||||
childPos = QPointF(childIndex * CARD_WIDTH / 2, 0);
|
childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0);
|
||||||
CardDragItem *drag =
|
CardDragItem *drag =
|
||||||
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
|
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
|
||||||
drag->setPos(dragItem->pos() + childPos);
|
drag->setPos(dragItem->pos() + childPos);
|
||||||
|
|
@ -474,9 +476,9 @@ bool CardItem::animationEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(tapAngle)
|
.rotate(tapAngle)
|
||||||
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
setHovered(false);
|
setHovered(false);
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ class QAction;
|
||||||
class QColor;
|
class QColor;
|
||||||
|
|
||||||
const int MAX_COUNTERS_ON_CARD = 999;
|
const int MAX_COUNTERS_ON_CARD = 999;
|
||||||
const float CARD_WIDTH_HALF = CARD_WIDTH / 2;
|
|
||||||
const float CARD_HEIGHT_HALF = CARD_HEIGHT / 2;
|
|
||||||
const int ROTATION_DEGREES_PER_FRAME = 10;
|
const int ROTATION_DEGREES_PER_FRAME = 10;
|
||||||
|
|
||||||
class CardItem : public AbstractCardItem
|
class CardItem : public AbstractCardItem
|
||||||
|
|
@ -142,7 +140,7 @@ public:
|
||||||
void processCardInfo(const ServerInfo_Card &_info);
|
void processCardInfo(const ServerInfo_Card &_info);
|
||||||
|
|
||||||
bool animationEvent();
|
bool animationEvent();
|
||||||
CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown);
|
CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown);
|
||||||
void deleteDragItem();
|
void deleteDragItem();
|
||||||
void drawArrow(const QColor &arrowColor);
|
void drawArrow(const QColor &arrowColor);
|
||||||
void drawAttachArrow();
|
void drawAttachArrow();
|
||||||
|
|
|
||||||
29
cockatrice/src/game/card_dimensions.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef CARD_DIMENSIONS_H
|
||||||
|
#define CARD_DIMENSIONS_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file card_dimensions.h
|
||||||
|
* @brief Canonical card dimension constants for layout and Z-value calculations.
|
||||||
|
*
|
||||||
|
* These values represent the logical pixel dimensions of a standard card graphic.
|
||||||
|
* They are used throughout the game scene for layout, rendering, and Z-value computation.
|
||||||
|
*/
|
||||||
|
namespace CardDimensions
|
||||||
|
{
|
||||||
|
/// Card width in pixels
|
||||||
|
constexpr int WIDTH = 72;
|
||||||
|
/// Card height in pixels
|
||||||
|
constexpr int HEIGHT = 102;
|
||||||
|
|
||||||
|
/// Pre-converted for floating-point contexts (Z-value calculations)
|
||||||
|
constexpr qreal WIDTH_F = static_cast<qreal>(WIDTH);
|
||||||
|
constexpr qreal HEIGHT_F = static_cast<qreal>(HEIGHT);
|
||||||
|
|
||||||
|
/// Half-dimensions for centering and rotation transforms
|
||||||
|
constexpr qreal WIDTH_HALF_F = WIDTH_F / 2;
|
||||||
|
constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2;
|
||||||
|
} // namespace CardDimensions
|
||||||
|
|
||||||
|
#endif // CARD_DIMENSIONS_H
|
||||||
|
|
@ -95,8 +95,9 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||||
pen.setJoinStyle(Qt::MiterJoin);
|
pen.setJoinStyle(Qt::MiterJoin);
|
||||||
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
||||||
painter->setPen(pen);
|
painter->setPen(pen);
|
||||||
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CARD_WIDTH - 3) : 0.0;
|
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CardDimensions::WIDTH_F - 3) : 0.0;
|
||||||
painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius);
|
painter->drawRoundedRect(QRectF(1.5, 1.5, CardDimensions::WIDTH_F - 3, CardDimensions::HEIGHT_F - 3), cardRadius,
|
||||||
|
cardRadius);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +123,7 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (c == this)
|
if (c == this)
|
||||||
continue;
|
continue;
|
||||||
++j;
|
++j;
|
||||||
auto childPos = QPointF(j * CARD_WIDTH / 2, 0);
|
auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0);
|
||||||
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
||||||
drag->setPos(dragItem->pos() + childPos);
|
drag->setPos(dragItem->pos() + childPos);
|
||||||
scene()->addItem(drag);
|
scene()->addItem(drag);
|
||||||
|
|
@ -204,7 +205,7 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI
|
||||||
painter->setPen(QColor(255, 255, 255, 100));
|
painter->setPen(QColor(255, 255, 255, 100));
|
||||||
painter->drawLine(QPointF(0, yUntilNow - paddingY / 2), QPointF(width, yUntilNow - paddingY / 2));
|
painter->drawLine(QPointF(0, yUntilNow - paddingY / 2), QPointF(width, yUntilNow - paddingY / 2));
|
||||||
}
|
}
|
||||||
qreal thisRowHeight = CARD_HEIGHT * currentRowsAndCols[i].first;
|
qreal thisRowHeight = CardDimensions::HEIGHT_F * currentRowsAndCols[i].first;
|
||||||
QRectF textRect(0, yUntilNow, totalTextWidth, thisRowHeight);
|
QRectF textRect(0, yUntilNow, totalTextWidth, thisRowHeight);
|
||||||
yUntilNow += thisRowHeight + paddingY;
|
yUntilNow += thisRowHeight + paddingY;
|
||||||
|
|
||||||
|
|
@ -260,9 +261,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>>
|
||||||
|
|
||||||
// Calculate space needed for cards
|
// Calculate space needed for cards
|
||||||
for (int i = 0; i < rowsAndCols.size(); ++i) {
|
for (int i = 0; i < rowsAndCols.size(); ++i) {
|
||||||
totalHeight += CARD_HEIGHT * rowsAndCols[i].first + paddingY;
|
totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY;
|
||||||
if (CARD_WIDTH * rowsAndCols[i].second > totalWidth)
|
if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth)
|
||||||
totalWidth = CARD_WIDTH * rowsAndCols[i].second;
|
totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
|
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
|
||||||
|
|
@ -289,9 +290,10 @@ void DeckViewCardContainer::rearrangeItems(const QList<QPair<int, int>> &rowsAnd
|
||||||
std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
|
std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
|
||||||
for (int j = 0; j < row.size(); ++j) {
|
for (int j = 0; j < row.size(); ++j) {
|
||||||
DeckViewCard *card = row[j];
|
DeckViewCard *card = row[j];
|
||||||
card->setPos(x + (j % tempCols) * CARD_WIDTH, yUntilNow + (j / tempCols) * CARD_HEIGHT);
|
card->setPos(x + (j % tempCols) * CardDimensions::WIDTH_F,
|
||||||
|
yUntilNow + (j / tempCols) * CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
yUntilNow += tempRows * CARD_HEIGHT + paddingY;
|
yUntilNow += tempRows * CardDimensions::HEIGHT_F + paddingY;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
@ -392,7 +394,7 @@ void DeckViewScene::applySideboardPlan(const QList<MoveCard_ToZone> &plan)
|
||||||
|
|
||||||
void DeckViewScene::rearrangeItems()
|
void DeckViewScene::rearrangeItems()
|
||||||
{
|
{
|
||||||
const int spacing = CARD_HEIGHT / 3;
|
const int spacing = CardDimensions::HEIGHT / 3;
|
||||||
QList<DeckViewCardContainer *> contList = cardContainers.values();
|
QList<DeckViewCardContainer *> contList = cardContainers.values();
|
||||||
|
|
||||||
// Initialize space requirements
|
// Initialize space requirements
|
||||||
|
|
|
||||||
|
|
@ -260,16 +260,15 @@ void DeckViewContainer::loadLocalDeck()
|
||||||
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||||
{
|
{
|
||||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath);
|
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath);
|
||||||
DeckLoader deck(this);
|
|
||||||
|
|
||||||
bool success = deck.loadFromFile(filePath, fmt, true);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, fmt, true);
|
||||||
|
|
||||||
if (!success) {
|
if (!deckOpt) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDeckFromDeckList(deck.getDeck().deckList);
|
loadDeckFromDeckList(deckOpt.value().deckList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
||||||
|
|
|
||||||
|
|
@ -146,13 +146,13 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
||||||
setWindowTitle(tr("Create token"));
|
setWindowTitle(tr("Create token"));
|
||||||
|
|
||||||
resize(600, 500);
|
resize(600, 500);
|
||||||
restoreGeometry(SettingsCache::instance().getTokenDialogGeometry());
|
restoreGeometry(SettingsCache::instance().layouts().getTokenDialogGeometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgCreateToken::closeEvent(QCloseEvent *event)
|
void DlgCreateToken::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
|
void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
|
||||||
|
|
@ -225,13 +225,13 @@ void DlgCreateToken::actChooseTokenFromDeck(bool checked)
|
||||||
|
|
||||||
void DlgCreateToken::actOk()
|
void DlgCreateToken::actOk()
|
||||||
{
|
{
|
||||||
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgCreateToken::actReject()
|
void DlgCreateToken::actReject()
|
||||||
{
|
{
|
||||||
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
|
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -410,9 +411,9 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
|
||||||
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
|
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
|
||||||
addItem(item);
|
addItem(item);
|
||||||
|
|
||||||
if (zoneName == "grave")
|
if (zoneName == ZoneNames::GRAVE)
|
||||||
item->setPos(360, 100);
|
item->setPos(360, 100);
|
||||||
else if (zoneName == "rfg")
|
else if (zoneName == ZoneNames::EXILE)
|
||||||
item->setPos(380, 120);
|
item->setPos(380, 120);
|
||||||
else
|
else
|
||||||
item->setPos(340, 80);
|
item->setPos(340, 80);
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,9 @@
|
||||||
#include <../../client/settings/card_counter_settings.h>
|
#include <../../client/settings/card_counter_settings.h>
|
||||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
|
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
static const QString TABLE_ZONE_NAME = "table";
|
|
||||||
static const QString GRAVE_ZONE_NAME = "grave";
|
|
||||||
static const QString EXILE_ZONE_NAME = "rfg";
|
|
||||||
static const QString HAND_ZONE_NAME = "hand";
|
|
||||||
static const QString DECK_ZONE_NAME = "deck";
|
|
||||||
static const QString SIDEBOARD_ZONE_NAME = "sb";
|
|
||||||
static const QString STACK_ZONE_NAME = "stack";
|
|
||||||
|
|
||||||
static QString sanitizeHtml(QString dirty)
|
static QString sanitizeHtml(QString dirty)
|
||||||
{
|
{
|
||||||
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
||||||
|
|
@ -37,15 +30,15 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position
|
||||||
QString fromStr;
|
QString fromStr;
|
||||||
QString zoneName = zone->getName();
|
QString zoneName = zone->getName();
|
||||||
|
|
||||||
if (zoneName == TABLE_ZONE_NAME) {
|
if (zoneName == ZoneNames::TABLE) {
|
||||||
fromStr = tr(" from play");
|
fromStr = tr(" from play");
|
||||||
} else if (zoneName == GRAVE_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::GRAVE) {
|
||||||
fromStr = tr(" from their graveyard");
|
fromStr = tr(" from their graveyard");
|
||||||
} else if (zoneName == EXILE_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::EXILE) {
|
||||||
fromStr = tr(" from exile");
|
fromStr = tr(" from exile");
|
||||||
} else if (zoneName == HAND_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::HAND) {
|
||||||
fromStr = tr(" from their hand");
|
fromStr = tr(" from their hand");
|
||||||
} else if (zoneName == DECK_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::DECK) {
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
if (cardName.isEmpty()) {
|
if (cardName.isEmpty()) {
|
||||||
if (ownerChange) {
|
if (ownerChange) {
|
||||||
|
|
@ -83,9 +76,9 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position
|
||||||
fromStr = tr(" from their library");
|
fromStr = tr(" from their library");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (zoneName == SIDEBOARD_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::SIDEBOARD) {
|
||||||
fromStr = tr(" from sideboard");
|
fromStr = tr(" from sideboard");
|
||||||
} else if (zoneName == STACK_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::STACK) {
|
||||||
fromStr = tr(" from the stack");
|
fromStr = tr(" from the stack");
|
||||||
} else {
|
} else {
|
||||||
fromStr = tr(" from custom zone '%1'").arg(zoneName);
|
fromStr = tr(" from custom zone '%1'").arg(zoneName);
|
||||||
|
|
@ -275,9 +268,9 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
|
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
|
||||||
|
|
||||||
// do not log if moved within the same zone
|
// do not log if moved within the same zone
|
||||||
if ((startZoneName == TABLE_ZONE_NAME && targetZoneName == TABLE_ZONE_NAME && !ownerChanged) ||
|
if ((startZoneName == ZoneNames::TABLE && targetZoneName == ZoneNames::TABLE && !ownerChanged) ||
|
||||||
(startZoneName == HAND_ZONE_NAME && targetZoneName == HAND_ZONE_NAME) ||
|
(startZoneName == ZoneNames::HAND && targetZoneName == ZoneNames::HAND) ||
|
||||||
(startZoneName == EXILE_ZONE_NAME && targetZoneName == EXILE_ZONE_NAME)) {
|
(startZoneName == ZoneNames::EXILE && targetZoneName == ZoneNames::EXILE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,20 +299,28 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
|
|
||||||
QString finalStr;
|
QString finalStr;
|
||||||
std::optional<QString> fourthArg;
|
std::optional<QString> fourthArg;
|
||||||
if (targetZoneName == TABLE_ZONE_NAME) {
|
if (targetZoneName == ZoneNames::TABLE) {
|
||||||
soundEngine->playSound("play_card");
|
soundEngine->playSound("play_card");
|
||||||
if (card->getFaceDown()) {
|
if (card->getFaceDown()) {
|
||||||
finalStr = tr("%1 puts %2 into play%3 face down.");
|
finalStr = tr("%1 puts %2 into play%3 face down.");
|
||||||
} else {
|
} else {
|
||||||
finalStr = tr("%1 puts %2 into play%3.");
|
finalStr = tr("%1 puts %2 into play%3.");
|
||||||
}
|
}
|
||||||
} else if (targetZoneName == GRAVE_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::GRAVE) {
|
||||||
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 puts %2%3 into their graveyard face down.");
|
||||||
|
} else {
|
||||||
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
||||||
} else if (targetZoneName == EXILE_ZONE_NAME) {
|
}
|
||||||
|
} else if (targetZoneName == ZoneNames::EXILE) {
|
||||||
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 exiles %2%3 face down.");
|
||||||
|
} else {
|
||||||
finalStr = tr("%1 exiles %2%3.");
|
finalStr = tr("%1 exiles %2%3.");
|
||||||
} else if (targetZoneName == HAND_ZONE_NAME) {
|
}
|
||||||
|
} else if (targetZoneName == ZoneNames::HAND) {
|
||||||
finalStr = tr("%1 moves %2%3 to their hand.");
|
finalStr = tr("%1 moves %2%3 to their hand.");
|
||||||
} else if (targetZoneName == DECK_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::DECK) {
|
||||||
if (newX == -1) {
|
if (newX == -1) {
|
||||||
finalStr = tr("%1 puts %2%3 into their library.");
|
finalStr = tr("%1 puts %2%3 into their library.");
|
||||||
} else if (newX >= targetZone->getCards().size()) {
|
} else if (newX >= targetZone->getCards().size()) {
|
||||||
|
|
@ -331,15 +332,23 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
fourthArg = QString::number(newX);
|
fourthArg = QString::number(newX);
|
||||||
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
|
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
|
||||||
}
|
}
|
||||||
} else if (targetZoneName == SIDEBOARD_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::SIDEBOARD) {
|
||||||
finalStr = tr("%1 moves %2%3 to sideboard.");
|
finalStr = tr("%1 moves %2%3 to sideboard.");
|
||||||
} else if (targetZoneName == STACK_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::STACK) {
|
||||||
soundEngine->playSound("play_card");
|
soundEngine->playSound("play_card");
|
||||||
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 plays %2%3 face down.");
|
||||||
|
} else {
|
||||||
finalStr = tr("%1 plays %2%3.");
|
finalStr = tr("%1 plays %2%3.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fourthArg = targetZoneName;
|
fourthArg = targetZoneName;
|
||||||
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 moves %2%3 to custom zone '%4' face down.");
|
||||||
|
} else {
|
||||||
finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
|
finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second);
|
QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
|
PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
|
||||||
: QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
|
: QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
|
||||||
|
|
@ -259,7 +260,7 @@ void PhasesToolbar::actNextTurn()
|
||||||
void PhasesToolbar::actUntapAll()
|
void PhasesToolbar::actUntapAll()
|
||||||
{
|
{
|
||||||
Command_SetCardAttr cmd;
|
Command_SetCardAttr cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_attribute(AttrTapped);
|
cmd.set_attribute(AttrTapped);
|
||||||
cmd.set_attr_value("0");
|
cmd.set_attr_value("0");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/card/relation/card_relation.h>
|
#include <libcockatrice/card/relation/card_relation.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive)
|
CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive)
|
||||||
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
|
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
|
||||||
|
|
@ -112,31 +113,20 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
|
||||||
addAction(aSelectAll);
|
addAction(aSelectAll);
|
||||||
addAction(aSelectColumn);
|
addAction(aSelectColumn);
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
} else if (writeableCard) {
|
} else {
|
||||||
|
|
||||||
if (card->getZone()) {
|
if (card->getZone()) {
|
||||||
if (card->getZone()->getName() == "table") {
|
if (card->getZone()->getName() == ZoneNames::TABLE) {
|
||||||
createTableMenu();
|
createTableMenu(writeableCard);
|
||||||
} else if (card->getZone()->getName() == "stack") {
|
} else if (card->getZone()->getName() == ZoneNames::STACK) {
|
||||||
createStackMenu();
|
createStackMenu(writeableCard);
|
||||||
} else if (card->getZone()->getName() == "rfg" || card->getZone()->getName() == "grave") {
|
} else if (card->getZone()->getName() == ZoneNames::EXILE ||
|
||||||
createGraveyardOrExileMenu();
|
card->getZone()->getName() == ZoneNames::GRAVE) {
|
||||||
|
createGraveyardOrExileMenu(writeableCard);
|
||||||
} else {
|
} else {
|
||||||
createHandOrCustomZoneMenu();
|
createHandOrCustomZoneMenu(writeableCard);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addMenu(new MoveMenu(player));
|
createZonelessMenu(writeableCard);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (card->getZone() && card->getZone()->getName() != "hand") {
|
|
||||||
addAction(aDrawArrow);
|
|
||||||
addSeparator();
|
|
||||||
addRelatedCardView();
|
|
||||||
addRelatedCardActions();
|
|
||||||
addSeparator();
|
|
||||||
addAction(aClone);
|
|
||||||
addSeparator();
|
|
||||||
addAction(aSelectAll);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -152,11 +142,9 @@ void CardMenu::removePlayer(Player *playerToRemove)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createTableMenu()
|
void CardMenu::createTableMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
// Card is on the battlefield
|
// Card is on the battlefield
|
||||||
bool canModifyCard = player->getPlayerInfo()->judge || card->getOwner() == player;
|
|
||||||
|
|
||||||
if (!canModifyCard) {
|
if (!canModifyCard) {
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
|
|
@ -211,10 +199,8 @@ void CardMenu::createTableMenu()
|
||||||
addMenu(mCardCounters);
|
addMenu(mCardCounters);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createStackMenu()
|
void CardMenu::createStackMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
bool canModifyCard = player->getPlayerInfo()->judge || card->getOwner() == player;
|
|
||||||
|
|
||||||
// Card is on the stack
|
// Card is on the stack
|
||||||
if (canModifyCard) {
|
if (canModifyCard) {
|
||||||
addAction(aAttach);
|
addAction(aAttach);
|
||||||
|
|
@ -236,10 +222,8 @@ void CardMenu::createStackMenu()
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createGraveyardOrExileMenu()
|
void CardMenu::createGraveyardOrExileMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
bool canModifyCard = player->getPlayerInfo()->judge || card->getOwner() == player;
|
|
||||||
|
|
||||||
// Card is in the graveyard or exile
|
// Card is in the graveyard or exile
|
||||||
if (canModifyCard) {
|
if (canModifyCard) {
|
||||||
addAction(aPlay);
|
addAction(aPlay);
|
||||||
|
|
@ -268,8 +252,20 @@ void CardMenu::createGraveyardOrExileMenu()
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createHandOrCustomZoneMenu()
|
void CardMenu::createHandOrCustomZoneMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
|
if (!canModifyCard) {
|
||||||
|
addAction(aDrawArrow);
|
||||||
|
addSeparator();
|
||||||
|
addRelatedCardView();
|
||||||
|
addRelatedCardActions();
|
||||||
|
addSeparator();
|
||||||
|
addAction(aClone);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aSelectAll);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Card is in hand or a custom zone specified by server
|
// Card is in hand or a custom zone specified by server
|
||||||
addAction(aPlay);
|
addAction(aPlay);
|
||||||
addAction(aPlayFacedown);
|
addAction(aPlayFacedown);
|
||||||
|
|
@ -285,7 +281,7 @@ void CardMenu::createHandOrCustomZoneMenu()
|
||||||
addMenu(new MoveMenu(player));
|
addMenu(new MoveMenu(player));
|
||||||
|
|
||||||
// actions that are really wonky when done from deck or sideboard
|
// actions that are really wonky when done from deck or sideboard
|
||||||
if (card->getZone()->getName() == "hand") {
|
if (card->getZone()->getName() == ZoneNames::HAND) {
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aAttach);
|
addAction(aAttach);
|
||||||
addAction(aDrawArrow);
|
addAction(aDrawArrow);
|
||||||
|
|
@ -298,11 +294,18 @@ void CardMenu::createHandOrCustomZoneMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
if (card->getZone()->getName() == "hand") {
|
if (card->getZone()->getName() == ZoneNames::HAND) {
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardMenu::createZonelessMenu(bool canModifyCard)
|
||||||
|
{
|
||||||
|
if (canModifyCard) {
|
||||||
|
addMenu(new MoveMenu(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Populates the menu with an action for each active player.
|
* @brief Populates the menu with an action for each active player.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,11 @@ class CardMenu : public QMenu
|
||||||
public:
|
public:
|
||||||
explicit CardMenu(Player *player, const CardItem *card, bool shortcutsActive);
|
explicit CardMenu(Player *player, const CardItem *card, bool shortcutsActive);
|
||||||
void removePlayer(Player *playerToRemove);
|
void removePlayer(Player *playerToRemove);
|
||||||
void createTableMenu();
|
void createTableMenu(bool canModifyCard);
|
||||||
void createStackMenu();
|
void createStackMenu(bool canModifyCard);
|
||||||
void createGraveyardOrExileMenu();
|
void createGraveyardOrExileMenu(bool canModifyCard);
|
||||||
void createHandOrCustomZoneMenu();
|
void createHandOrCustomZoneMenu(bool canModifyCard);
|
||||||
|
void createZonelessMenu(bool canModifyCard);
|
||||||
|
|
||||||
QMenu *mCardCounters;
|
QMenu *mCardCounters;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||||
{
|
{
|
||||||
|
|
@ -39,16 +40,16 @@ void GraveyardMenu::createMoveActions()
|
||||||
|
|
||||||
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
||||||
aMoveGraveToTopLibrary = new QAction(this);
|
aMoveGraveToTopLibrary = new QAction(this);
|
||||||
aMoveGraveToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveGraveToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||||
|
|
||||||
aMoveGraveToBottomLibrary = new QAction(this);
|
aMoveGraveToBottomLibrary = new QAction(this);
|
||||||
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||||
|
|
||||||
aMoveGraveToHand = new QAction(this);
|
aMoveGraveToHand = new QAction(this);
|
||||||
aMoveGraveToHand->setData(QList<QVariant>() << "hand" << 0);
|
aMoveGraveToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
|
||||||
|
|
||||||
aMoveGraveToRfg = new QAction(this);
|
aMoveGraveToRfg = new QAction(this);
|
||||||
aMoveGraveToRfg->setData(QList<QVariant>() << "rfg" << 0);
|
aMoveGraveToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
|
||||||
|
|
||||||
connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||||
connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
|
HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||||
{
|
{
|
||||||
|
|
@ -76,13 +77,13 @@ HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : T
|
||||||
|
|
||||||
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
||||||
aMoveHandToTopLibrary = new QAction(this);
|
aMoveHandToTopLibrary = new QAction(this);
|
||||||
aMoveHandToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveHandToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||||
aMoveHandToBottomLibrary = new QAction(this);
|
aMoveHandToBottomLibrary = new QAction(this);
|
||||||
aMoveHandToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
aMoveHandToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||||
aMoveHandToGrave = new QAction(this);
|
aMoveHandToGrave = new QAction(this);
|
||||||
aMoveHandToGrave->setData(QList<QVariant>() << "grave" << 0);
|
aMoveHandToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
|
||||||
aMoveHandToRfg = new QAction(this);
|
aMoveHandToRfg = new QAction(this);
|
||||||
aMoveHandToRfg->setData(QList<QVariant>() << "rfg" << 0);
|
aMoveHandToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
|
||||||
|
|
||||||
auto hand = player->getHandZone();
|
auto hand = player->getHandZone();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,10 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent)
|
||||||
topLibraryMenu->addSeparator();
|
topLibraryMenu->addSeparator();
|
||||||
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
|
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
|
||||||
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
|
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardsToGraveyardFaceDown);
|
||||||
topLibraryMenu->addAction(aMoveTopCardToExile);
|
topLibraryMenu->addAction(aMoveTopCardToExile);
|
||||||
topLibraryMenu->addAction(aMoveTopCardsToExile);
|
topLibraryMenu->addAction(aMoveTopCardsToExile);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardsToExileFaceDown);
|
||||||
topLibraryMenu->addAction(aMoveTopCardsUntil);
|
topLibraryMenu->addAction(aMoveTopCardsUntil);
|
||||||
topLibraryMenu->addSeparator();
|
topLibraryMenu->addSeparator();
|
||||||
topLibraryMenu->addAction(aShuffleTopCards);
|
topLibraryMenu->addAction(aShuffleTopCards);
|
||||||
|
|
@ -66,8 +68,10 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent)
|
||||||
bottomLibraryMenu->addSeparator();
|
bottomLibraryMenu->addSeparator();
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
|
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
|
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyardFaceDown);
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
|
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
|
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardsToExileFaceDown);
|
||||||
bottomLibraryMenu->addSeparator();
|
bottomLibraryMenu->addSeparator();
|
||||||
bottomLibraryMenu->addAction(aShuffleBottomCards);
|
bottomLibraryMenu->addAction(aShuffleBottomCards);
|
||||||
|
|
||||||
|
|
@ -136,8 +140,14 @@ void LibraryMenu::createMoveActions()
|
||||||
connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile);
|
connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile);
|
||||||
aMoveTopCardsToGraveyard = new QAction(this);
|
aMoveTopCardsToGraveyard = new QAction(this);
|
||||||
connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave);
|
connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave);
|
||||||
|
aMoveTopCardsToGraveyardFaceDown = new QAction(this);
|
||||||
|
connect(aMoveTopCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveTopCardsToGraveFaceDown);
|
||||||
aMoveTopCardsToExile = new QAction(this);
|
aMoveTopCardsToExile = new QAction(this);
|
||||||
connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile);
|
connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile);
|
||||||
|
aMoveTopCardsToExileFaceDown = new QAction(this);
|
||||||
|
connect(aMoveTopCardsToExileFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveTopCardsToExileFaceDown);
|
||||||
aMoveTopCardsUntil = new QAction(this);
|
aMoveTopCardsUntil = new QAction(this);
|
||||||
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsUntil);
|
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsUntil);
|
||||||
aMoveTopCardToBottom = new QAction(this);
|
aMoveTopCardToBottom = new QAction(this);
|
||||||
|
|
@ -156,8 +166,14 @@ void LibraryMenu::createMoveActions()
|
||||||
aMoveBottomCardsToGraveyard = new QAction(this);
|
aMoveBottomCardsToGraveyard = new QAction(this);
|
||||||
connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions,
|
connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions,
|
||||||
&PlayerActions::actMoveBottomCardsToGrave);
|
&PlayerActions::actMoveBottomCardsToGrave);
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown = new QAction(this);
|
||||||
|
connect(aMoveBottomCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveBottomCardsToGraveFaceDown);
|
||||||
aMoveBottomCardsToExile = new QAction(this);
|
aMoveBottomCardsToExile = new QAction(this);
|
||||||
connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile);
|
connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile);
|
||||||
|
aMoveBottomCardsToExileFaceDown = new QAction(this);
|
||||||
|
connect(aMoveBottomCardsToExileFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveBottomCardsToExileFaceDown);
|
||||||
aMoveBottomCardToTop = new QAction(this);
|
aMoveBottomCardToTop = new QAction(this);
|
||||||
connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop);
|
connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop);
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +232,9 @@ void LibraryMenu::retranslateUi()
|
||||||
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
||||||
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
||||||
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
||||||
|
aMoveTopCardsToGraveyardFaceDown->setText(tr("Move top cards to graveyard face down..."));
|
||||||
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
||||||
|
aMoveTopCardsToExileFaceDown->setText(tr("Move top cards to exile face down..."));
|
||||||
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
|
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
|
||||||
aShuffleTopCards->setText(tr("Shuffle top cards..."));
|
aShuffleTopCards->setText(tr("Shuffle top cards..."));
|
||||||
|
|
||||||
|
|
@ -227,7 +245,9 @@ void LibraryMenu::retranslateUi()
|
||||||
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
|
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
|
||||||
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
|
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
|
||||||
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
|
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown->setText(tr("Move bottom cards to graveyard face down..."));
|
||||||
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
|
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
|
||||||
|
aMoveBottomCardsToExileFaceDown->setText(tr("Move bottom cards to exile face down..."));
|
||||||
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
|
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
|
||||||
aShuffleBottomCards->setText(tr("Shuffle bottom cards..."));
|
aShuffleBottomCards->setText(tr("Shuffle bottom cards..."));
|
||||||
}
|
}
|
||||||
|
|
@ -335,8 +355,10 @@ void LibraryMenu::setShortcutsActive()
|
||||||
aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown"));
|
aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown"));
|
||||||
aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard"));
|
aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard"));
|
||||||
aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard"));
|
aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard"));
|
||||||
|
aMoveTopCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyardFaceDown"));
|
||||||
aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
|
aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
|
||||||
aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
|
aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
|
||||||
|
aMoveTopCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExileFaceDown"));
|
||||||
aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil"));
|
aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil"));
|
||||||
aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom"));
|
aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom"));
|
||||||
aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard"));
|
aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard"));
|
||||||
|
|
@ -345,8 +367,10 @@ void LibraryMenu::setShortcutsActive()
|
||||||
aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown"));
|
aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown"));
|
||||||
aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave"));
|
aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave"));
|
||||||
aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave"));
|
aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave"));
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGraveFaceDown"));
|
||||||
aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
|
aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
|
||||||
aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
|
aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
|
||||||
|
aMoveBottomCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExileFaceDown"));
|
||||||
aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
|
aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,8 +391,10 @@ void LibraryMenu::setShortcutsInactive()
|
||||||
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
||||||
|
aMoveTopCardsToGraveyardFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardToExile->setShortcut(QKeySequence());
|
aMoveTopCardToExile->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
||||||
|
aMoveTopCardsToExileFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsUntil->setShortcut(QKeySequence());
|
aMoveTopCardsUntil->setShortcut(QKeySequence());
|
||||||
aDrawBottomCard->setShortcut(QKeySequence());
|
aDrawBottomCard->setShortcut(QKeySequence());
|
||||||
aDrawBottomCards->setShortcut(QKeySequence());
|
aDrawBottomCards->setShortcut(QKeySequence());
|
||||||
|
|
@ -376,6 +402,8 @@ void LibraryMenu::setShortcutsInactive()
|
||||||
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
|
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
|
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
|
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardToExile->setShortcut(QKeySequence());
|
aMoveBottomCardToExile->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardsToExile->setShortcut(QKeySequence());
|
aMoveBottomCardsToExile->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardsToExileFaceDown->setShortcut(QKeySequence());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,9 @@ public:
|
||||||
QAction *aMoveTopCardToGraveyard = nullptr;
|
QAction *aMoveTopCardToGraveyard = nullptr;
|
||||||
QAction *aMoveTopCardToExile = nullptr;
|
QAction *aMoveTopCardToExile = nullptr;
|
||||||
QAction *aMoveTopCardsToGraveyard = nullptr;
|
QAction *aMoveTopCardsToGraveyard = nullptr;
|
||||||
|
QAction *aMoveTopCardsToGraveyardFaceDown = nullptr;
|
||||||
QAction *aMoveTopCardsToExile = nullptr;
|
QAction *aMoveTopCardsToExile = nullptr;
|
||||||
|
QAction *aMoveTopCardsToExileFaceDown = nullptr;
|
||||||
QAction *aMoveTopCardsUntil = nullptr;
|
QAction *aMoveTopCardsUntil = nullptr;
|
||||||
QAction *aShuffleTopCards = nullptr;
|
QAction *aShuffleTopCards = nullptr;
|
||||||
|
|
||||||
|
|
@ -100,7 +102,9 @@ public:
|
||||||
QAction *aMoveBottomCardToGraveyard = nullptr;
|
QAction *aMoveBottomCardToGraveyard = nullptr;
|
||||||
QAction *aMoveBottomCardToExile = nullptr;
|
QAction *aMoveBottomCardToExile = nullptr;
|
||||||
QAction *aMoveBottomCardsToGraveyard = nullptr;
|
QAction *aMoveBottomCardsToGraveyard = nullptr;
|
||||||
|
QAction *aMoveBottomCardsToGraveyardFaceDown = nullptr;
|
||||||
QAction *aMoveBottomCardsToExile = nullptr;
|
QAction *aMoveBottomCardsToExile = nullptr;
|
||||||
|
QAction *aMoveBottomCardsToExileFaceDown = nullptr;
|
||||||
QAction *aShuffleBottomCards = nullptr;
|
QAction *aShuffleBottomCards = nullptr;
|
||||||
|
|
||||||
int defaultNumberTopCards = 1;
|
int defaultNumberTopCards = 1;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#include "../player.h"
|
#include "../player.h"
|
||||||
#include "../player_actions.h"
|
#include "../player_actions.h"
|
||||||
|
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
RfgMenu::RfgMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
RfgMenu::RfgMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||||
{
|
{
|
||||||
createMoveActions();
|
createMoveActions();
|
||||||
|
|
@ -30,13 +32,13 @@ void RfgMenu::createMoveActions()
|
||||||
auto rfg = player->getRfgZone();
|
auto rfg = player->getRfgZone();
|
||||||
|
|
||||||
aMoveRfgToTopLibrary = new QAction(this);
|
aMoveRfgToTopLibrary = new QAction(this);
|
||||||
aMoveRfgToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveRfgToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||||
aMoveRfgToBottomLibrary = new QAction(this);
|
aMoveRfgToBottomLibrary = new QAction(this);
|
||||||
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||||
aMoveRfgToHand = new QAction(this);
|
aMoveRfgToHand = new QAction(this);
|
||||||
aMoveRfgToHand->setData(QList<QVariant>() << "hand" << 0);
|
aMoveRfgToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
|
||||||
aMoveRfgToGrave = new QAction(this);
|
aMoveRfgToGrave = new QAction(this);
|
||||||
aMoveRfgToGrave->setData(QList<QVariant>() << "grave" << 0);
|
aMoveRfgToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
|
||||||
|
|
||||||
connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||||
connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||||
|
|
|
||||||
|
|
@ -61,15 +61,15 @@ void Player::forwardActionSignalsToEventHandler()
|
||||||
|
|
||||||
void Player::initializeZones()
|
void Player::initializeZones()
|
||||||
{
|
{
|
||||||
addZone(new PileZoneLogic(this, "deck", false, true, false, this));
|
addZone(new PileZoneLogic(this, ZoneNames::DECK, false, true, false, this));
|
||||||
addZone(new PileZoneLogic(this, "grave", false, false, true, this));
|
addZone(new PileZoneLogic(this, ZoneNames::GRAVE, false, false, true, this));
|
||||||
addZone(new PileZoneLogic(this, "rfg", false, false, true, this));
|
addZone(new PileZoneLogic(this, ZoneNames::EXILE, false, false, true, this));
|
||||||
addZone(new PileZoneLogic(this, "sb", false, false, false, this));
|
addZone(new PileZoneLogic(this, ZoneNames::SIDEBOARD, false, false, false, this));
|
||||||
addZone(new TableZoneLogic(this, "table", true, false, true, this));
|
addZone(new TableZoneLogic(this, ZoneNames::TABLE, true, false, true, this));
|
||||||
addZone(new StackZoneLogic(this, "stack", true, false, true, this));
|
addZone(new StackZoneLogic(this, ZoneNames::STACK, true, false, true, this));
|
||||||
bool visibleHand = playerInfo->getLocalOrJudge() ||
|
bool visibleHand = playerInfo->getLocalOrJudge() ||
|
||||||
(game->getPlayerManager()->isSpectator() && game->getGameMetaInfo()->spectatorsOmniscient());
|
(game->getPlayerManager()->isSpectator() && game->getGameMetaInfo()->spectatorsOmniscient());
|
||||||
addZone(new HandZoneLogic(this, "hand", false, false, visibleHand, this));
|
addZone(new HandZoneLogic(this, ZoneNames::HAND, false, false, visibleHand, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player()
|
Player::~Player()
|
||||||
|
|
@ -119,13 +119,13 @@ void Player::setZoneId(int _zoneId)
|
||||||
void Player::processPlayerInfo(const ServerInfo_Player &info)
|
void Player::processPlayerInfo(const ServerInfo_Player &info)
|
||||||
{
|
{
|
||||||
static QSet<QString> builtinZones{/* PileZones */
|
static QSet<QString> builtinZones{/* PileZones */
|
||||||
"deck", "grave", "rfg", "sb",
|
ZoneNames::DECK, ZoneNames::GRAVE, ZoneNames::EXILE, ZoneNames::SIDEBOARD,
|
||||||
/* TableZone */
|
/* TableZone */
|
||||||
"table",
|
ZoneNames::TABLE,
|
||||||
/* StackZone */
|
/* StackZone */
|
||||||
"stack",
|
ZoneNames::STACK,
|
||||||
/* HandZone */
|
/* HandZone */
|
||||||
"hand"};
|
ZoneNames::HAND};
|
||||||
clearCounters();
|
clearCounters();
|
||||||
clearArrows();
|
clearArrows();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <libcockatrice/filters/filter_string.h>
|
#include <libcockatrice/filters/filter_string.h>
|
||||||
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
|
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/game_event.pb.h>
|
#include <libcockatrice/protocol/pb/game_event.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
|
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
|
||||||
|
|
||||||
|
|
@ -155,37 +156,37 @@ public:
|
||||||
|
|
||||||
PileZoneLogic *getDeckZone()
|
PileZoneLogic *getDeckZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("deck"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::DECK));
|
||||||
}
|
}
|
||||||
|
|
||||||
PileZoneLogic *getGraveZone()
|
PileZoneLogic *getGraveZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("grave"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::GRAVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
PileZoneLogic *getRfgZone()
|
PileZoneLogic *getRfgZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("rfg"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::EXILE));
|
||||||
}
|
}
|
||||||
|
|
||||||
PileZoneLogic *getSideboardZone()
|
PileZoneLogic *getSideboardZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("sb"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::SIDEBOARD));
|
||||||
}
|
}
|
||||||
|
|
||||||
TableZoneLogic *getTableZone()
|
TableZoneLogic *getTableZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<TableZoneLogic *>(zones.value("table"));
|
return qobject_cast<TableZoneLogic *>(zones.value(ZoneNames::TABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
StackZoneLogic *getStackZone()
|
StackZoneLogic *getStackZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<StackZoneLogic *>(zones.value("stack"));
|
return qobject_cast<StackZoneLogic *>(zones.value(ZoneNames::STACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
HandZoneLogic *getHandZone()
|
HandZoneLogic *getHandZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<HandZoneLogic *>(zones.value("hand"));
|
return qobject_cast<HandZoneLogic *>(zones.value(ZoneNames::HAND));
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractCounter *addCounter(const ServerInfo_Counter &counter);
|
AbstractCounter *addCounter(const ServerInfo_Counter &counter);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||||
#include <libcockatrice/utility/trice_limits.h>
|
#include <libcockatrice/utility/trice_limits.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
// milliseconds in between triggers of the move top cards until action
|
// milliseconds in between triggers of the move top cards until action
|
||||||
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
|
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
|
||||||
|
|
@ -63,13 +64,13 @@ void PlayerActions::playCard(CardItem *card, bool faceDown)
|
||||||
int tableRow = info.getUiAttributes().tableRow;
|
int tableRow = info.getUiAttributes().tableRow;
|
||||||
bool playToStack = SettingsCache::instance().getPlayToStack();
|
bool playToStack = SettingsCache::instance().getPlayToStack();
|
||||||
QString currentZone = card->getZone()->getName();
|
QString currentZone = card->getZone()->getName();
|
||||||
if (currentZone == "stack" && tableRow == 3) {
|
if (currentZone == ZoneNames::STACK && tableRow == 3) {
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
} else if (!faceDown &&
|
} else if (!faceDown && ((!playToStack && tableRow == 3) ||
|
||||||
((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) {
|
((playToStack && tableRow != 0) && currentZone != ZoneNames::STACK))) {
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone(ZoneNames::STACK);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -81,7 +82,7 @@ void PlayerActions::playCard(CardItem *card, bool faceDown)
|
||||||
}
|
}
|
||||||
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
||||||
if (tableRow != 3)
|
if (tableRow != 3)
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(gridPoint.x());
|
cmd.set_x(gridPoint.x());
|
||||||
cmd.set_y(gridPoint.y());
|
cmd.set_y(gridPoint.y());
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +125,7 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
||||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||||
}
|
}
|
||||||
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(gridPoint.x());
|
cmd.set_x(gridPoint.x());
|
||||||
cmd.set_y(gridPoint.y());
|
cmd.set_y(gridPoint.y());
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -132,12 +133,12 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
||||||
|
|
||||||
void PlayerActions::actViewLibrary()
|
void PlayerActions::actViewLibrary()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "deck", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewHand()
|
void PlayerActions::actViewHand()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "hand", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::HAND, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -181,7 +182,7 @@ void PlayerActions::actViewTopCards()
|
||||||
deckSize, 1, &ok);
|
deckSize, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
player->getGameScene()->toggleZoneView(player, "deck", number);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,14 +195,14 @@ void PlayerActions::actViewBottomCards()
|
||||||
deckSize, 1, &ok);
|
deckSize, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
player->getGameScene()->toggleZoneView(player, "deck", number, true);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, number, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actAlwaysRevealTopCard()
|
void PlayerActions::actAlwaysRevealTopCard()
|
||||||
{
|
{
|
||||||
Command_ChangeZoneProperties cmd;
|
Command_ChangeZoneProperties cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_always_reveal_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysRevealTopCardChecked());
|
cmd.set_always_reveal_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysRevealTopCardChecked());
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -210,7 +211,7 @@ void PlayerActions::actAlwaysRevealTopCard()
|
||||||
void PlayerActions::actAlwaysLookAtTopCard()
|
void PlayerActions::actAlwaysLookAtTopCard()
|
||||||
{
|
{
|
||||||
Command_ChangeZoneProperties cmd;
|
Command_ChangeZoneProperties cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_always_look_at_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysLookAtTopCardChecked());
|
cmd.set_always_look_at_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysLookAtTopCardChecked());
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -223,17 +224,17 @@ void PlayerActions::actOpenDeckInDeckEditor()
|
||||||
|
|
||||||
void PlayerActions::actViewGraveyard()
|
void PlayerActions::actViewGraveyard()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "grave", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::GRAVE, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewRfg()
|
void PlayerActions::actViewRfg()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "rfg", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::EXILE, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewSideboard()
|
void PlayerActions::actViewSideboard()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "sb", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::SIDEBOARD, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actShuffle()
|
void PlayerActions::actShuffle()
|
||||||
|
|
@ -263,7 +264,7 @@ void PlayerActions::actShuffleTop()
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
|
|
||||||
Command_Shuffle cmd;
|
Command_Shuffle cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_start(0);
|
cmd.set_start(0);
|
||||||
cmd.set_end(number - 1); // inclusive, the indexed card at end will be shuffled
|
cmd.set_end(number - 1); // inclusive, the indexed card at end will be shuffled
|
||||||
|
|
||||||
|
|
@ -292,7 +293,7 @@ void PlayerActions::actShuffleBottom()
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_Shuffle cmd;
|
Command_Shuffle cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_start(-number);
|
cmd.set_start(-number);
|
||||||
cmd.set_end(-1);
|
cmd.set_end(-1);
|
||||||
|
|
||||||
|
|
@ -376,7 +377,7 @@ void PlayerActions::actUndoDraw()
|
||||||
|
|
||||||
void PlayerActions::cmdSetTopCard(Command_MoveCard &cmd)
|
void PlayerActions::cmdSetTopCard(Command_MoveCard &cmd)
|
||||||
{
|
{
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(0);
|
cardToMove->set_card_id(0);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
|
|
@ -386,7 +387,7 @@ void PlayerActions::cmdSetBottomCard(Command_MoveCard &cmd)
|
||||||
{
|
{
|
||||||
CardZoneLogic *zone = player->getDeckZone();
|
CardZoneLogic *zone = player->getDeckZone();
|
||||||
int lastCard = zone->getCards().size() - 1;
|
int lastCard = zone->getCards().size() - 1;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(lastCard);
|
cardToMove->set_card_id(lastCard);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
|
|
@ -400,7 +401,7 @@ void PlayerActions::actMoveTopCardToGrave()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -415,7 +416,7 @@ void PlayerActions::actMoveTopCardToExile()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(ZoneNames::EXILE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -424,37 +425,25 @@ void PlayerActions::actMoveTopCardToExile()
|
||||||
|
|
||||||
void PlayerActions::actMoveTopCardsToGrave()
|
void PlayerActions::actMoveTopCardsToGrave()
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
moveTopCardsTo(ZoneNames::GRAVE, tr("grave"), false);
|
||||||
if (maxCards == 0) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok;
|
void PlayerActions::actMoveTopCardsToGraveFaceDown()
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to grave"),
|
{
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
moveTopCardsTo(ZoneNames::GRAVE, tr("grave"), true);
|
||||||
maxCards, 1, &ok);
|
|
||||||
if (!ok) {
|
|
||||||
return;
|
|
||||||
} else if (number > maxCards) {
|
|
||||||
number = maxCards;
|
|
||||||
}
|
|
||||||
defaultNumberTopCards = number;
|
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
|
||||||
cmd.set_start_zone("deck");
|
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
|
||||||
cmd.set_target_zone("grave");
|
|
||||||
cmd.set_x(0);
|
|
||||||
cmd.set_y(0);
|
|
||||||
|
|
||||||
for (int i = number - 1; i >= 0; --i) {
|
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actMoveTopCardsToExile()
|
void PlayerActions::actMoveTopCardsToExile()
|
||||||
|
{
|
||||||
|
moveTopCardsTo(ZoneNames::EXILE, tr("exile"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::actMoveTopCardsToExileFaceDown()
|
||||||
|
{
|
||||||
|
moveTopCardsTo(ZoneNames::EXILE, tr("exile"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown)
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
const int maxCards = player->getDeckZone()->getCards().size();
|
||||||
if (maxCards == 0) {
|
if (maxCards == 0) {
|
||||||
|
|
@ -462,25 +451,31 @@ void PlayerActions::actMoveTopCardsToExile()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to exile"),
|
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to %1").arg(zoneDisplayName),
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
||||||
maxCards, 1, &ok);
|
maxCards, 1, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
} else if (number > maxCards) {
|
}
|
||||||
|
|
||||||
|
if (number > maxCards) {
|
||||||
number = maxCards;
|
number = maxCards;
|
||||||
}
|
}
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(targetZone.toStdString());
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
for (int i = number - 1; i >= 0; --i) {
|
for (int i = number - 1; i >= 0; --i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
auto card = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
card->set_card_id(i);
|
||||||
|
if (faceDown) {
|
||||||
|
card->set_face_down(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -555,7 +550,7 @@ void PlayerActions::actMoveTopCardToBottom()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("deck");
|
cmd.set_target_zone(ZoneNames::DECK);
|
||||||
cmd.set_x(-1); // bottom of deck
|
cmd.set_x(-1); // bottom of deck
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -570,7 +565,7 @@ void PlayerActions::actMoveTopCardToPlay()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone(ZoneNames::STACK);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -584,12 +579,12 @@ void PlayerActions::actMoveTopCardToPlayFaceDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(0);
|
cardToMove->set_card_id(0);
|
||||||
cardToMove->set_face_down(true);
|
cardToMove->set_face_down(true);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -604,7 +599,7 @@ void PlayerActions::actMoveBottomCardToGrave()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -619,7 +614,7 @@ void PlayerActions::actMoveBottomCardToExile()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(ZoneNames::EXILE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -628,37 +623,25 @@ void PlayerActions::actMoveBottomCardToExile()
|
||||||
|
|
||||||
void PlayerActions::actMoveBottomCardsToGrave()
|
void PlayerActions::actMoveBottomCardsToGrave()
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
moveBottomCardsTo(ZoneNames::GRAVE, tr("grave"), false);
|
||||||
if (maxCards == 0) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok;
|
void PlayerActions::actMoveBottomCardsToGraveFaceDown()
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to grave"),
|
{
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
moveBottomCardsTo(ZoneNames::GRAVE, tr("grave"), true);
|
||||||
maxCards, 1, &ok);
|
|
||||||
if (!ok) {
|
|
||||||
return;
|
|
||||||
} else if (number > maxCards) {
|
|
||||||
number = maxCards;
|
|
||||||
}
|
|
||||||
defaultNumberBottomCards = number;
|
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
|
||||||
cmd.set_start_zone("deck");
|
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
|
||||||
cmd.set_target_zone("grave");
|
|
||||||
cmd.set_x(0);
|
|
||||||
cmd.set_y(0);
|
|
||||||
|
|
||||||
for (int i = maxCards - number; i < maxCards; ++i) {
|
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actMoveBottomCardsToExile()
|
void PlayerActions::actMoveBottomCardsToExile()
|
||||||
|
{
|
||||||
|
moveBottomCardsTo(ZoneNames::EXILE, tr("exile"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::actMoveBottomCardsToExileFaceDown()
|
||||||
|
{
|
||||||
|
moveBottomCardsTo(ZoneNames::EXILE, tr("exile"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown)
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
const int maxCards = player->getDeckZone()->getCards().size();
|
||||||
if (maxCards == 0) {
|
if (maxCards == 0) {
|
||||||
|
|
@ -666,25 +649,31 @@ void PlayerActions::actMoveBottomCardsToExile()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to exile"),
|
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to %1").arg(zoneDisplayName),
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
||||||
maxCards, 1, &ok);
|
maxCards, 1, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
} else if (number > maxCards) {
|
}
|
||||||
|
|
||||||
|
if (number > maxCards) {
|
||||||
number = maxCards;
|
number = maxCards;
|
||||||
}
|
}
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(targetZone.toStdString());
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
for (int i = maxCards - number; i < maxCards; ++i) {
|
for (int i = maxCards - number; i < maxCards; ++i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
auto card = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
card->set_card_id(i);
|
||||||
|
if (faceDown) {
|
||||||
|
card->set_face_down(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -698,7 +687,7 @@ void PlayerActions::actMoveBottomCardToTop()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("deck");
|
cmd.set_target_zone(ZoneNames::DECK);
|
||||||
cmd.set_x(0); // top of deck
|
cmd.set_x(0); // top of deck
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -768,7 +757,7 @@ void PlayerActions::actDrawBottomCard()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("hand");
|
cmd.set_target_zone(ZoneNames::HAND);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -794,9 +783,9 @@ void PlayerActions::actDrawBottomCards()
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("hand");
|
cmd.set_target_zone(ZoneNames::HAND);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -815,7 +804,7 @@ void PlayerActions::actMoveBottomCardToPlay()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone(ZoneNames::STACK);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -832,13 +821,13 @@ void PlayerActions::actMoveBottomCardToPlayFaceDown()
|
||||||
int lastCard = zone->getCards().size() - 1;
|
int lastCard = zone->getCards().size() - 1;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(lastCard);
|
cardToMove->set_card_id(lastCard);
|
||||||
cardToMove->set_face_down(true);
|
cardToMove->set_face_down(true);
|
||||||
|
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -848,7 +837,7 @@ void PlayerActions::actMoveBottomCardToPlayFaceDown()
|
||||||
void PlayerActions::actUntapAll()
|
void PlayerActions::actUntapAll()
|
||||||
{
|
{
|
||||||
Command_SetCardAttr cmd;
|
Command_SetCardAttr cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_attribute(AttrTapped);
|
cmd.set_attribute(AttrTapped);
|
||||||
cmd.set_attr_value("0");
|
cmd.set_attr_value("0");
|
||||||
|
|
||||||
|
|
@ -898,7 +887,7 @@ void PlayerActions::actCreateAnotherToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_CreateToken cmd;
|
Command_CreateToken cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_name(lastTokenInfo.name.toStdString());
|
cmd.set_card_name(lastTokenInfo.name.toStdString());
|
||||||
cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString());
|
cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString());
|
||||||
cmd.set_color(lastTokenInfo.color.toStdString());
|
cmd.set_color(lastTokenInfo.color.toStdString());
|
||||||
|
|
@ -1079,7 +1068,7 @@ bool PlayerActions::createRelatedFromRelation(const CardItem *sourceCard, const
|
||||||
|
|
||||||
// move card onto table first if attaching from some other zone
|
// move card onto table first if attaching from some other zone
|
||||||
// we only do this for AttachTo because cross-zone TransformInto is already handled server-side
|
// we only do this for AttachTo because cross-zone TransformInto is already handled server-side
|
||||||
if (attachType == CardRelationType::AttachTo && sourceCard->getZone()->getName() != "table") {
|
if (attachType == CardRelationType::AttachTo && sourceCard->getZone()->getName() != ZoneNames::TABLE) {
|
||||||
playCardToTable(sourceCard, false);
|
playCardToTable(sourceCard, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1105,7 +1094,7 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
||||||
|
|
||||||
// create the token for the related card
|
// create the token for the related card
|
||||||
Command_CreateToken cmd;
|
Command_CreateToken cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_name(cardInfo->getName().toStdString());
|
cmd.set_card_name(cardInfo->getName().toStdString());
|
||||||
switch (cardInfo->getColors().size()) {
|
switch (cardInfo->getColors().size()) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -1134,12 +1123,12 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
||||||
|
|
||||||
switch (attachType) {
|
switch (attachType) {
|
||||||
case CardRelationType::DoesNotAttach:
|
case CardRelationType::DoesNotAttach:
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CardRelationType::AttachTo:
|
case CardRelationType::AttachTo:
|
||||||
cmd.set_target_zone("table"); // We currently only support creating tokens on the table
|
cmd.set_target_zone(ZoneNames::TABLE); // We currently only support creating tokens on the table
|
||||||
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
||||||
cmd.set_target_card_id(sourceCard->getId());
|
cmd.set_target_card_id(sourceCard->getId());
|
||||||
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
||||||
|
|
@ -1147,7 +1136,7 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
||||||
|
|
||||||
case CardRelationType::TransformInto:
|
case CardRelationType::TransformInto:
|
||||||
// allow cards to directly transform on stack
|
// allow cards to directly transform on stack
|
||||||
cmd.set_zone(sourceCard->getZone()->getName() == "stack" ? "stack" : "table");
|
cmd.set_zone(sourceCard->getZone()->getName() == ZoneNames::STACK ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||||
// Transform card zone changes are handled server-side
|
// Transform card zone changes are handled server-side
|
||||||
cmd.set_target_zone(sourceCard->getZone()->getName().toStdString());
|
cmd.set_target_zone(sourceCard->getZone()->getName().toStdString());
|
||||||
cmd.set_target_card_id(sourceCard->getId());
|
cmd.set_target_card_id(sourceCard->getId());
|
||||||
|
|
@ -1262,7 +1251,7 @@ void PlayerActions::actMoveCardXCardsFromTop()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("deck");
|
cmd->set_target_zone(ZoneNames::DECK);
|
||||||
cmd->set_x(number);
|
cmd->set_x(number);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
@ -1651,7 +1640,7 @@ void PlayerActions::playSelectedCards(const bool faceDown)
|
||||||
[](const auto &card1, const auto &card2) { return card1->getId() > card2->getId(); });
|
[](const auto &card1, const auto &card2) { return card1->getId() > card2->getId(); });
|
||||||
|
|
||||||
for (auto &card : selectedCards) {
|
for (auto &card : selectedCards) {
|
||||||
if (card && !isUnwritableRevealZone(card->getZone()) && card->getZone()->getName() != "table") {
|
if (card && !isUnwritableRevealZone(card->getZone()) && card->getZone()->getName() != ZoneNames::TABLE) {
|
||||||
playCard(card, faceDown);
|
playCard(card, faceDown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1704,7 +1693,7 @@ void PlayerActions::actRevealHand(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("hand");
|
cmd.set_zone_name(ZoneNames::HAND);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -1715,7 +1704,7 @@ void PlayerActions::actRevealRandomHandCard(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("hand");
|
cmd.set_zone_name(ZoneNames::HAND);
|
||||||
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1727,7 +1716,7 @@ void PlayerActions::actRevealLibrary(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -1738,7 +1727,7 @@ void PlayerActions::actLendLibrary(int lendToPlayerId)
|
||||||
if (lendToPlayerId != -1) {
|
if (lendToPlayerId != -1) {
|
||||||
cmd.set_player_id(lendToPlayerId);
|
cmd.set_player_id(lendToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_grant_write_access(true);
|
cmd.set_grant_write_access(true);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1751,7 +1740,7 @@ void PlayerActions::actRevealTopCards(int revealToPlayerId, int amount)
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_top_cards(amount);
|
cmd.set_top_cards(amount);
|
||||||
// backward compatibility: servers before #1051 only permits to reveal the first card
|
// backward compatibility: servers before #1051 only permits to reveal the first card
|
||||||
cmd.add_card_id(0);
|
cmd.add_card_id(0);
|
||||||
|
|
@ -1765,7 +1754,7 @@ void PlayerActions::actRevealRandomGraveyardCard(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("grave");
|
cmd.set_zone_name(ZoneNames::GRAVE);
|
||||||
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -1828,7 +1817,7 @@ void PlayerActions::cardMenuAction()
|
||||||
}
|
}
|
||||||
case cmClone: {
|
case cmClone: {
|
||||||
auto *cmd = new Command_CreateToken;
|
auto *cmd = new Command_CreateToken;
|
||||||
cmd->set_zone("table");
|
cmd->set_zone(ZoneNames::TABLE);
|
||||||
cmd->set_card_name(card->getName().toStdString());
|
cmd->set_card_name(card->getName().toStdString());
|
||||||
cmd->set_card_provider_id(card->getProviderId().toStdString());
|
cmd->set_card_provider_id(card->getProviderId().toStdString());
|
||||||
cmd->set_color(card->getColor().toStdString());
|
cmd->set_color(card->getColor().toStdString());
|
||||||
|
|
@ -1870,13 +1859,13 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("deck");
|
cmd->set_target_zone(ZoneNames::DECK);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
|
|
||||||
if (idList.card_size() > 1) {
|
if (idList.card_size() > 1) {
|
||||||
auto *scmd = new Command_Shuffle;
|
auto *scmd = new Command_Shuffle;
|
||||||
scmd->set_zone_name("deck");
|
scmd->set_zone_name(ZoneNames::DECK);
|
||||||
scmd->set_start(0);
|
scmd->set_start(0);
|
||||||
scmd->set_end(idList.card_size() - 1); // inclusive, the indexed card at end will be shuffled
|
scmd->set_end(idList.card_size() - 1); // inclusive, the indexed card at end will be shuffled
|
||||||
// Server process events backwards, so...
|
// Server process events backwards, so...
|
||||||
|
|
@ -1892,13 +1881,13 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("deck");
|
cmd->set_target_zone(ZoneNames::DECK);
|
||||||
cmd->set_x(-1);
|
cmd->set_x(-1);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
|
|
||||||
if (idList.card_size() > 1) {
|
if (idList.card_size() > 1) {
|
||||||
auto *scmd = new Command_Shuffle;
|
auto *scmd = new Command_Shuffle;
|
||||||
scmd->set_zone_name("deck");
|
scmd->set_zone_name(ZoneNames::DECK);
|
||||||
scmd->set_start(-idList.card_size());
|
scmd->set_start(-idList.card_size());
|
||||||
scmd->set_end(-1);
|
scmd->set_end(-1);
|
||||||
// Server process events backwards, so...
|
// Server process events backwards, so...
|
||||||
|
|
@ -1914,7 +1903,7 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("hand");
|
cmd->set_target_zone(ZoneNames::HAND);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
@ -1926,7 +1915,7 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("grave");
|
cmd->set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
@ -1938,7 +1927,7 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("rfg");
|
cmd->set_target_zone(ZoneNames::EXILE);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,9 @@ public slots:
|
||||||
void actMoveTopCardToGrave();
|
void actMoveTopCardToGrave();
|
||||||
void actMoveTopCardToExile();
|
void actMoveTopCardToExile();
|
||||||
void actMoveTopCardsToGrave();
|
void actMoveTopCardsToGrave();
|
||||||
|
void actMoveTopCardsToGraveFaceDown();
|
||||||
void actMoveTopCardsToExile();
|
void actMoveTopCardsToExile();
|
||||||
|
void actMoveTopCardsToExileFaceDown();
|
||||||
void actMoveTopCardsUntil();
|
void actMoveTopCardsUntil();
|
||||||
void actMoveTopCardToBottom();
|
void actMoveTopCardToBottom();
|
||||||
void actDrawBottomCard();
|
void actDrawBottomCard();
|
||||||
|
|
@ -108,7 +110,9 @@ public slots:
|
||||||
void actMoveBottomCardToGrave();
|
void actMoveBottomCardToGrave();
|
||||||
void actMoveBottomCardToExile();
|
void actMoveBottomCardToExile();
|
||||||
void actMoveBottomCardsToGrave();
|
void actMoveBottomCardsToGrave();
|
||||||
|
void actMoveBottomCardsToGraveFaceDown();
|
||||||
void actMoveBottomCardsToExile();
|
void actMoveBottomCardsToExile();
|
||||||
|
void actMoveBottomCardsToExileFaceDown();
|
||||||
void actMoveBottomCardToTop();
|
void actMoveBottomCardToTop();
|
||||||
|
|
||||||
void actSelectAll();
|
void actSelectAll();
|
||||||
|
|
@ -180,6 +184,9 @@ private:
|
||||||
FilterString movingCardsUntilFilter;
|
FilterString movingCardsUntilFilter;
|
||||||
int movingCardsUntilCounter = 0;
|
int movingCardsUntilCounter = 0;
|
||||||
|
|
||||||
|
void moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
|
||||||
|
void moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
|
||||||
|
|
||||||
void createCard(const CardItem *sourceCard,
|
void createCard(const CardItem *sourceCard,
|
||||||
const QString &dbCardName,
|
const QString &dbCardName,
|
||||||
CardRelationType attach = CardRelationType::DoesNotAttach,
|
CardRelationType attach = CardRelationType::DoesNotAttach,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
PlayerEventHandler::PlayerEventHandler(Player *_player) : player(_player)
|
PlayerEventHandler::PlayerEventHandler(Player *_player) : player(_player)
|
||||||
{
|
{
|
||||||
|
|
@ -321,8 +322,8 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
|
||||||
}
|
}
|
||||||
player->getPlayerMenu()->updateCardMenu(card);
|
player->getPlayerMenu()->updateCardMenu(card);
|
||||||
|
|
||||||
if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == "deck" &&
|
if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK &&
|
||||||
targetZone->getName() == "stack") {
|
targetZone->getName() == ZoneNames::STACK) {
|
||||||
player->getPlayerActions()->moveOneCardUntil(card);
|
player->getPlayerActions()->moveOneCardUntil(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ PlayerGraphicsItem::PlayerGraphicsItem(Player *_player) : player(_player)
|
||||||
playerArea = new PlayerArea(this);
|
playerArea = new PlayerArea(this);
|
||||||
|
|
||||||
playerTarget = new PlayerTarget(player, playerArea);
|
playerTarget = new PlayerTarget(player, playerArea);
|
||||||
qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0;
|
qreal avatarMargin =
|
||||||
|
(counterAreaWidth + CardDimensions::HEIGHT_F + 15 - playerTarget->boundingRect().width()) / 2.0;
|
||||||
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
|
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
|
||||||
|
|
||||||
initializeZones();
|
initializeZones();
|
||||||
|
|
@ -55,8 +56,9 @@ void PlayerGraphicsItem::onPlayerActiveChanged(bool _active)
|
||||||
void PlayerGraphicsItem::initializeZones()
|
void PlayerGraphicsItem::initializeZones()
|
||||||
{
|
{
|
||||||
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
||||||
auto base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
|
auto base = QPointF(counterAreaWidth + (CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F + 15) / 2.0,
|
||||||
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
|
10 + playerTarget->boundingRect().height() + 5 -
|
||||||
|
(CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F) / 2.0);
|
||||||
deckZoneGraphicsItem->setPos(base);
|
deckZoneGraphicsItem->setPos(base);
|
||||||
|
|
||||||
qreal h = deckZoneGraphicsItem->boundingRect().width() + 5;
|
qreal h = deckZoneGraphicsItem->boundingRect().width() + 5;
|
||||||
|
|
@ -95,7 +97,7 @@ QRectF PlayerGraphicsItem::boundingRect() const
|
||||||
|
|
||||||
qreal PlayerGraphicsItem::getMinimumWidth() const
|
qreal PlayerGraphicsItem::getMinimumWidth() const
|
||||||
{
|
{
|
||||||
qreal result = tableZoneGraphicsItem->getMinimumWidth() + CARD_HEIGHT + 15 + counterAreaWidth +
|
qreal result = tableZoneGraphicsItem->getMinimumWidth() + CardDimensions::HEIGHT_F + 15 + counterAreaWidth +
|
||||||
stackZoneGraphicsItem->boundingRect().width();
|
stackZoneGraphicsItem->boundingRect().width();
|
||||||
if (!SettingsCache::instance().getHorizontalHand()) {
|
if (!SettingsCache::instance().getHorizontalHand()) {
|
||||||
result += handZoneGraphicsItem->boundingRect().width();
|
result += handZoneGraphicsItem->boundingRect().width();
|
||||||
|
|
@ -112,8 +114,8 @@ void PlayerGraphicsItem::paint(QPainter * /*painter*/,
|
||||||
void PlayerGraphicsItem::processSceneSizeChange(int newPlayerWidth)
|
void PlayerGraphicsItem::processSceneSizeChange(int newPlayerWidth)
|
||||||
{
|
{
|
||||||
// Extend table (and hand, if horizontal) to accommodate the new player width.
|
// Extend table (and hand, if horizontal) to accommodate the new player width.
|
||||||
qreal tableWidth =
|
qreal tableWidth = newPlayerWidth - CardDimensions::HEIGHT_F - 15 - counterAreaWidth -
|
||||||
newPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stackZoneGraphicsItem->boundingRect().width();
|
stackZoneGraphicsItem->boundingRect().width();
|
||||||
if (!SettingsCache::instance().getHorizontalHand()) {
|
if (!SettingsCache::instance().getHorizontalHand()) {
|
||||||
tableWidth -= handZoneGraphicsItem->boundingRect().width();
|
tableWidth -= handZoneGraphicsItem->boundingRect().width();
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +154,7 @@ void PlayerGraphicsItem::rearrangeCounters()
|
||||||
|
|
||||||
void PlayerGraphicsItem::rearrangeZones()
|
void PlayerGraphicsItem::rearrangeZones()
|
||||||
{
|
{
|
||||||
auto base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0);
|
auto base = QPointF(CardDimensions::HEIGHT_F + counterAreaWidth + 15, 0);
|
||||||
if (SettingsCache::instance().getHorizontalHand()) {
|
if (SettingsCache::instance().getHorizontalHand()) {
|
||||||
if (mirrored) {
|
if (mirrored) {
|
||||||
if (player->getHandZone()->contentsKnown()) {
|
if (player->getHandZone()->contentsKnown()) {
|
||||||
|
|
@ -203,7 +205,7 @@ void PlayerGraphicsItem::rearrangeZones()
|
||||||
void PlayerGraphicsItem::updateBoundingRect()
|
void PlayerGraphicsItem::updateBoundingRect()
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
qreal width = CARD_HEIGHT + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width();
|
qreal width = CardDimensions::HEIGHT_F + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width();
|
||||||
if (SettingsCache::instance().getHorizontalHand()) {
|
if (SettingsCache::instance().getHorizontalHand()) {
|
||||||
qreal handHeight =
|
qreal handHeight =
|
||||||
player->getPlayerInfo()->getHandVisible() ? handZoneGraphicsItem->boundingRect().height() : 0;
|
player->getPlayerInfo()->getHandVisible() ? handZoneGraphicsItem->boundingRect().height() : 0;
|
||||||
|
|
@ -214,7 +216,7 @@ void PlayerGraphicsItem::updateBoundingRect()
|
||||||
0, 0, width + handZoneGraphicsItem->boundingRect().width() + tableZoneGraphicsItem->boundingRect().width(),
|
0, 0, width + handZoneGraphicsItem->boundingRect().width() + tableZoneGraphicsItem->boundingRect().width(),
|
||||||
tableZoneGraphicsItem->boundingRect().height());
|
tableZoneGraphicsItem->boundingRect().height());
|
||||||
}
|
}
|
||||||
playerArea->setSize(CARD_HEIGHT + counterAreaWidth + 15, bRect.height());
|
playerArea->setSize(CardDimensions::HEIGHT_F + counterAreaWidth + 15, bRect.height());
|
||||||
|
|
||||||
emit sizeChanged();
|
emit sizeChanged();
|
||||||
}
|
}
|
||||||
136
cockatrice/src/game/z_value_layer_manager.h
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
/**
|
||||||
|
* @file z_value_layer_manager.h
|
||||||
|
* @ingroup GameGraphics
|
||||||
|
* @brief Semantic Z-value layer management for game scene rendering.
|
||||||
|
*
|
||||||
|
* This file provides a structured approach to Z-value allocation in the game scene.
|
||||||
|
* Z-values in Qt determine stacking order - higher values render on top of lower values.
|
||||||
|
*
|
||||||
|
* ## Layer Architecture
|
||||||
|
*
|
||||||
|
* The game scene is organized into three conceptual layers:
|
||||||
|
*
|
||||||
|
* 1. **Zone Layer (0-999)**: Zone backgrounds, containers, and static elements
|
||||||
|
* - Zone backgrounds (0.5-1.0)
|
||||||
|
* - Cards within zones (1.0 base + index)
|
||||||
|
*
|
||||||
|
* 2. **Card Layer (1-40,000,000)**: Dynamic card rendering on the table zone
|
||||||
|
* - Cards use formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100
|
||||||
|
* - Maximum card Z-value: ~40,000,000 (with 3 rows, actualY <= ~289)
|
||||||
|
*
|
||||||
|
* 3. **Overlay Layer (2,000,000,000+)**: UI elements that must appear above all cards
|
||||||
|
* - Hovered cards (+1)
|
||||||
|
* - Arrows (+3)
|
||||||
|
* - Zone views (+4)
|
||||||
|
* - Drag items (+5, +6)
|
||||||
|
* - Top UI elements (+7)
|
||||||
|
*
|
||||||
|
* ## Design Rationale
|
||||||
|
*
|
||||||
|
* The large gap between card Z-values (max ~40M) and overlay base (2B) provides
|
||||||
|
* safety margin for future table zone expansions while ensuring overlays always
|
||||||
|
* render above cards regardless of table position.
|
||||||
|
*
|
||||||
|
* ## Usage
|
||||||
|
*
|
||||||
|
* Prefer using the semantic constants from ZValues namespace:
|
||||||
|
* @code
|
||||||
|
* card->setZValue(ZValues::HOVERED_CARD);
|
||||||
|
* arrow->setZValue(ZValues::ARROWS);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* Use validation functions to verify card Z-values during development:
|
||||||
|
* @code
|
||||||
|
* Q_ASSERT(ZValueLayerManager::isValidCardZValue(cardZ));
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Z_VALUE_LAYER_MANAGER_H
|
||||||
|
#define Z_VALUE_LAYER_MANAGER_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @namespace ZValueLayerManager
|
||||||
|
* @brief Utilities for Z-value validation and layer management.
|
||||||
|
*/
|
||||||
|
namespace ZValueLayerManager
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum Layer
|
||||||
|
* @brief Semantic layer identifiers for Z-value allocation.
|
||||||
|
*
|
||||||
|
* These represent conceptual rendering layers, not actual Z-values.
|
||||||
|
* Use the corresponding ZValues constants for actual rendering.
|
||||||
|
*/
|
||||||
|
enum class Layer
|
||||||
|
{
|
||||||
|
/// Zone-level elements like backgrounds and containers
|
||||||
|
Zone,
|
||||||
|
/// Cards rendered in zones (uses sequential Z-values)
|
||||||
|
Card,
|
||||||
|
/// Temporary UI elements like hovered cards and drag items
|
||||||
|
Overlay
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum Z-value a card can have on the table zone.
|
||||||
|
*
|
||||||
|
* Based on table zone formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100
|
||||||
|
* With maximum 3 rows and CardDimensions::HEIGHT = 102, actualY <= ~289.
|
||||||
|
* Maximum: (289 + 102) * 100000 + 100 * 100 = 39,110,000
|
||||||
|
*
|
||||||
|
* We use 40,000,000 as a safe upper bound with margin.
|
||||||
|
*/
|
||||||
|
constexpr qreal CARD_Z_VALUE_MAX = 40000000.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base Z-value for overlay elements.
|
||||||
|
*
|
||||||
|
* Must exceed CARD_Z_VALUE_MAX to ensure overlays render above all cards.
|
||||||
|
* The 50x margin (2B vs 40M) provides safety for future expansion.
|
||||||
|
*/
|
||||||
|
constexpr qreal OVERLAY_BASE = 2000000000.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates that a Z-value is within the valid card range.
|
||||||
|
*
|
||||||
|
* Cards should have Z-values between CARD_BASE (1.0) and CARD_Z_VALUE_MAX.
|
||||||
|
* Values outside this range may interfere with overlay rendering.
|
||||||
|
*
|
||||||
|
* @param zValue The Z-value to validate
|
||||||
|
* @return true if the Z-value is valid for a card
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr bool isValidCardZValue(qreal zValue)
|
||||||
|
{
|
||||||
|
return zValue >= 1.0 && zValue <= CARD_Z_VALUE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates that a Z-value is in the overlay layer.
|
||||||
|
*
|
||||||
|
* Overlay elements should have Z-values at or above OVERLAY_BASE.
|
||||||
|
*
|
||||||
|
* @param zValue The Z-value to validate
|
||||||
|
* @return true if the Z-value is valid for an overlay element
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr bool isOverlayZValue(qreal zValue)
|
||||||
|
{
|
||||||
|
return zValue >= OVERLAY_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the Z-value for a specific overlay element.
|
||||||
|
*
|
||||||
|
* @param offset Offset from OVERLAY_BASE (0-7 for current elements)
|
||||||
|
* @return The absolute Z-value for the overlay element
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr qreal overlayZValue(qreal offset)
|
||||||
|
{
|
||||||
|
return OVERLAY_BASE + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZValueLayerManager
|
||||||
|
|
||||||
|
#endif // Z_VALUE_LAYER_MANAGER_H
|
||||||
83
cockatrice/src/game/z_values.h
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#ifndef Z_VALUES_H
|
||||||
|
#define Z_VALUES_H
|
||||||
|
|
||||||
|
#include "card_dimensions.h"
|
||||||
|
#include "z_value_layer_manager.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file z_values.h
|
||||||
|
* @ingroup GameGraphics
|
||||||
|
* @brief Centralized Z-value constants for rendering layer order.
|
||||||
|
*
|
||||||
|
* Z-values in Qt determine stacking order. Higher values render on top.
|
||||||
|
* These constants define the visual layering hierarchy for the game scene.
|
||||||
|
*
|
||||||
|
* ## Layer Architecture
|
||||||
|
*
|
||||||
|
* See z_value_layer_manager.h for detailed documentation on the three-layer
|
||||||
|
* architecture (Zone, Card, Overlay) and the rationale for Z-value choices.
|
||||||
|
*
|
||||||
|
* ## Quick Reference
|
||||||
|
*
|
||||||
|
* | Layer | Z-Value Range | Purpose |
|
||||||
|
* |----------|------------------|-----------------------------------|
|
||||||
|
* | Zone | 0.5 - 1.0 | Zone backgrounds, containers |
|
||||||
|
* | Card | 1.0 - 40,000,000 | Cards on table (position-based) |
|
||||||
|
* | Overlay | 2,000,000,000+ | UI elements above all cards |
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ZValues
|
||||||
|
{
|
||||||
|
|
||||||
|
// Expose base for callers that need it
|
||||||
|
constexpr qreal OVERLAY_BASE = ZValueLayerManager::OVERLAY_BASE;
|
||||||
|
|
||||||
|
// Overlay layer Z-values for items that should appear above normal cards
|
||||||
|
constexpr qreal HOVERED_CARD = ZValueLayerManager::overlayZValue(1.0);
|
||||||
|
constexpr qreal ARROWS = ZValueLayerManager::overlayZValue(3.0);
|
||||||
|
constexpr qreal ZONE_VIEW_WIDGET = ZValueLayerManager::overlayZValue(4.0);
|
||||||
|
constexpr qreal DRAG_ITEM = ZValueLayerManager::overlayZValue(5.0);
|
||||||
|
constexpr qreal DRAG_ITEM_CHILD = ZValueLayerManager::overlayZValue(6.0);
|
||||||
|
constexpr qreal TOP_UI = ZValueLayerManager::overlayZValue(7.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute Z-value for child drag items based on hotspot position.
|
||||||
|
*
|
||||||
|
* When dragging multiple cards together, each child card needs a unique Z-value
|
||||||
|
* to prevent Z-fighting (flickering/flashing). The Z-values are derived from
|
||||||
|
* their position when grabbed to conserve original stacking. The formula encodes
|
||||||
|
* 2D coordinates into a single value where X has higher weight, ensuring
|
||||||
|
* deterministic visual stacking.
|
||||||
|
*
|
||||||
|
* @param hotSpotX The X coordinate of the grab position
|
||||||
|
* @param hotSpotY The Y coordinate of the grab position
|
||||||
|
* @return Unique Z-value for the child drag item
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr qreal childDragZValue(qreal hotSpotX, qreal hotSpotY)
|
||||||
|
{
|
||||||
|
return DRAG_ITEM_CHILD + hotSpotX * 1000000 + hotSpotY * 1000 + 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute Z-value for cards on the table zone based on position.
|
||||||
|
*
|
||||||
|
* Cards lower on the table (higher Y) render above cards higher up,
|
||||||
|
* and cards to the right (higher X) render above cards to the left.
|
||||||
|
* This creates natural visual stacking for overlapping cards.
|
||||||
|
*
|
||||||
|
* @param x The X coordinate of the card position
|
||||||
|
* @param y The Y coordinate of the card position
|
||||||
|
* @return Z-value for the card's table position
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr qreal tableCardZValue(qreal x, qreal y)
|
||||||
|
{
|
||||||
|
return (y + CardDimensions::HEIGHT_F) * 100000.0 + (x + 1) * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card layering (general architecture, not command-zone specific)
|
||||||
|
constexpr qreal CARD_BASE = 1.0;
|
||||||
|
constexpr qreal CARD_MAX = ZValueLayerManager::CARD_Z_VALUE_MAX;
|
||||||
|
|
||||||
|
} // namespace ZValues
|
||||||
|
|
||||||
|
#endif // Z_VALUES_H
|
||||||
|
|
@ -56,7 +56,7 @@ void HandZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
QRectF HandZone::boundingRect() const
|
QRectF HandZone::boundingRect() const
|
||||||
{
|
{
|
||||||
if (SettingsCache::instance().getHorizontalHand())
|
if (SettingsCache::instance().getHorizontalHand())
|
||||||
return QRectF(0, 0, width, CARD_HEIGHT + 10);
|
return QRectF(0, 0, width, CardDimensions::HEIGHT_F + 10);
|
||||||
else
|
else
|
||||||
return QRectF(0, 0, 100, zoneHeight);
|
return QRectF(0, 0, 100, zoneHeight);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param _player the player that the zone belongs to
|
* @param _player the player that the zone belongs to
|
||||||
|
|
@ -43,8 +44,10 @@ void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x,
|
||||||
|
|
||||||
for (auto *view : views) {
|
for (auto *view : views) {
|
||||||
if (qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->prepareAddCard(x)) {
|
if (qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->prepareAddCard(x)) {
|
||||||
view->getLogic()->addCard(new CardItem(player, nullptr, card->getCardRef(), card->getId()), reorganize, x,
|
auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId());
|
||||||
y);
|
copy->setFaceDown(card->getFaceDown());
|
||||||
|
|
||||||
|
view->getLogic()->addCard(copy, reorganize, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,9 +175,9 @@ void CardZoneLogic::clearContents()
|
||||||
QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
|
QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
|
||||||
{
|
{
|
||||||
QString ownerName = player->getPlayerInfo()->getName();
|
QString ownerName = player->getPlayerInfo()->getName();
|
||||||
if (name == "hand")
|
if (name == ZoneNames::HAND)
|
||||||
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
|
||||||
else if (name == "deck")
|
else if (name == ZoneNames::DECK)
|
||||||
switch (gc) {
|
switch (gc) {
|
||||||
case CaseLookAtZone:
|
case CaseLookAtZone:
|
||||||
return (theirOwn ? tr("their library", "look at zone")
|
return (theirOwn ? tr("their library", "look at zone")
|
||||||
|
|
@ -190,11 +193,11 @@ QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) cons
|
||||||
default:
|
default:
|
||||||
return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName));
|
||||||
}
|
}
|
||||||
else if (name == "grave")
|
else if (name == ZoneNames::GRAVE)
|
||||||
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
|
||||||
else if (name == "rfg")
|
else if (name == ZoneNames::EXILE)
|
||||||
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
|
||||||
else if (name == "sb")
|
else if (name == ZoneNames::SIDEBOARD)
|
||||||
switch (gc) {
|
switch (gc) {
|
||||||
case CaseLookAtZone:
|
case CaseLookAtZone:
|
||||||
return (theirOwn ? tr("their sideboard", "look at zone")
|
return (theirOwn ? tr("their sideboard", "look at zone")
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_log
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
|
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(90)
|
.rotate(90)
|
||||||
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
Q_UNUSED(_roundCardCorners);
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
@ -33,13 +33,13 @@ PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_log
|
||||||
|
|
||||||
QRectF PileZone::boundingRect() const
|
QRectF PileZone::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
|
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainterPath PileZone::shape() const
|
QPainterPath PileZone::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +52,9 @@ void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*optio
|
||||||
getLogic()->getCards().at(0)->paintPicture(painter, getLogic()->getCards().at(0)->getTranslatedSize(painter),
|
getLogic()->getCards().at(0)->paintPicture(painter, getLogic()->getCards().at(0)->getTranslatedSize(painter),
|
||||||
90);
|
90);
|
||||||
|
|
||||||
painter->translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2);
|
painter->translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F);
|
||||||
painter->rotate(-90);
|
painter->rotate(-90);
|
||||||
painter->translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2);
|
painter->translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F);
|
||||||
paintNumberEllipse(getLogic()->getCards().size(), 28, Qt::white, -1, -1, painter);
|
paintNumberEllipse(getLogic()->getCards().size(), 28, Qt::white, -1, -1, painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,8 +68,13 @@ void PileZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneL
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
for (int i = 0; i < dragItems.size(); ++i)
|
for (int i = 0; i < dragItems.size(); ++i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
|
auto cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(dragItems[i]->getId());
|
||||||
|
if (dragItems[i]->isForceFaceDown()) {
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -101,12 +106,12 @@ void PileZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (getLogic()->getCards().isEmpty())
|
if (getLogic()->getCards().isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool faceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||||
bool bottomCard = event->modifiers().testFlag(Qt::ControlModifier);
|
bool bottomCard = event->modifiers().testFlag(Qt::ControlModifier);
|
||||||
CardItem *card = bottomCard ? getLogic()->getCards().last() : getLogic()->getCards().first();
|
CardItem *card = bottomCard ? getLogic()->getCards().last() : getLogic()->getCards().first();
|
||||||
const int cardid =
|
const int cardid =
|
||||||
getLogic()->contentsKnown() ? card->getId() : (bottomCard ? getLogic()->getCards().size() - 1 : 0);
|
getLogic()->contentsKnown() ? card->getId() : (bottomCard ? getLogic()->getCards().size() - 1 : 0);
|
||||||
CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), faceDown);
|
CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), forceFaceDown);
|
||||||
drag->grabMouse();
|
drag->grabMouse();
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,11 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
|
|
||||||
for (CardDragItem *item : dragItems) {
|
for (CardDragItem *item : dragItems) {
|
||||||
if (item) {
|
if (item) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(item->getId());
|
auto cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(item->getId());
|
||||||
|
if (item->isForceFaceDown()) {
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../board/card_item.h"
|
#include "../board/card_item.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../player/player_actions.h"
|
#include "../player/player_actions.h"
|
||||||
|
#include "../z_values.h"
|
||||||
#include "logic/table_zone_logic.h"
|
#include "logic/table_zone_logic.h"
|
||||||
|
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
#include <libcockatrice/card/card_info.h>
|
#include <libcockatrice/card/card_info.h>
|
||||||
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
const QColor TableZone::BACKGROUND_COLOR = QColor(100, 100, 100);
|
const QColor TableZone::BACKGROUND_COLOR = QColor(100, 100, 100);
|
||||||
const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
|
const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
|
||||||
|
|
@ -30,7 +32,7 @@ TableZone::TableZone(TableZoneLogic *_logic, QGraphicsItem *parent) : SelectZone
|
||||||
|
|
||||||
updateBg();
|
updateBg();
|
||||||
|
|
||||||
height = MARGIN_TOP + MARGIN_BOTTOM + TABLEROWS * CARD_HEIGHT + (TABLEROWS - 1) * PADDING_Y;
|
height = MARGIN_TOP + MARGIN_BOTTOM + TABLEROWS * CardDimensions::HEIGHT + (TABLEROWS - 1) * PADDING_Y;
|
||||||
width = MIN_WIDTH;
|
width = MIN_WIDTH;
|
||||||
currentMinimumWidth = width;
|
currentMinimumWidth = width;
|
||||||
|
|
||||||
|
|
@ -105,7 +107,7 @@ void TableZone::paintLandDivider(QPainter *painter)
|
||||||
{
|
{
|
||||||
// Place the line 2 grid heights down then back it off just enough to allow
|
// Place the line 2 grid heights down then back it off just enough to allow
|
||||||
// some space between a 3-card stack and the land area.
|
// some space between a 3-card stack and the land area.
|
||||||
qreal separatorY = MARGIN_TOP + 2 * (CARD_HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2;
|
qreal separatorY = MARGIN_TOP + 2 * (CardDimensions::HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2;
|
||||||
if (isInverted())
|
if (isInverted())
|
||||||
separatorY = height - separatorY;
|
separatorY = height - separatorY;
|
||||||
painter->setPen(QColor(255, 255, 255, 40));
|
painter->setPen(QColor(255, 255, 255, 40));
|
||||||
|
|
@ -134,8 +136,10 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
|
||||||
for (const auto &item : dragItems) {
|
for (const auto &item : dragItems) {
|
||||||
CardToMove *ctm = cmd.mutable_cards_to_move()->add_card();
|
CardToMove *ctm = cmd.mutable_cards_to_move()->add_card();
|
||||||
ctm->set_card_id(item->getId());
|
ctm->set_card_id(item->getId());
|
||||||
ctm->set_face_down(item->getFaceDown());
|
if (item->isForceFaceDown()) {
|
||||||
if (startZone->getName() != getLogic()->getName() && !item->getFaceDown()) {
|
ctm->set_face_down(true);
|
||||||
|
}
|
||||||
|
if (startZone->getName() != getLogic()->getName() && !item->isForceFaceDown()) {
|
||||||
const auto &card = item->getItem()->getCard();
|
const auto &card = item->getItem()->getCard();
|
||||||
if (card) {
|
if (card) {
|
||||||
ctm->set_pt(card.getInfo().getPowTough().toStdString());
|
ctm->set_pt(card.getInfo().getPowTough().toStdString());
|
||||||
|
|
@ -167,7 +171,7 @@ void TableZone::reorganizeCards()
|
||||||
actualY += 15;
|
actualY += 15;
|
||||||
|
|
||||||
getLogic()->getCards()[i]->setPos(actualX, actualY);
|
getLogic()->getCards()[i]->setPos(actualX, actualY);
|
||||||
getLogic()->getCards()[i]->setRealZValue((actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100);
|
getLogic()->getCards()[i]->setRealZValue(ZValues::tableCardZValue(actualX, actualY));
|
||||||
|
|
||||||
QListIterator<CardItem *> attachedCardIterator(getLogic()->getCards()[i]->getAttachedCards());
|
QListIterator<CardItem *> attachedCardIterator(getLogic()->getCards()[i]->getAttachedCards());
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
@ -177,7 +181,7 @@ void TableZone::reorganizeCards()
|
||||||
qreal childX = actualX - j * STACKED_CARD_OFFSET_X;
|
qreal childX = actualX - j * STACKED_CARD_OFFSET_X;
|
||||||
qreal childY = y + 5;
|
qreal childY = y + 5;
|
||||||
attachedCard->setPos(childX, childY);
|
attachedCard->setPos(childX, childY);
|
||||||
attachedCard->setRealZValue((childY + CARD_HEIGHT) * 100000 + (childX + 1) * 100);
|
attachedCard->setRealZValue(ZValues::tableCardZValue(childX, childY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +196,7 @@ void TableZone::toggleTapped()
|
||||||
|
|
||||||
auto isCardOnTable = [](const QGraphicsItem *item) {
|
auto isCardOnTable = [](const QGraphicsItem *item) {
|
||||||
if (auto card = qgraphicsitem_cast<const CardItem *>(item)) {
|
if (auto card = qgraphicsitem_cast<const CardItem *>(item)) {
|
||||||
return card->getZone()->getName() == "table";
|
return card->getZone()->getName() == ZoneNames::TABLE;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -229,7 +233,7 @@ void TableZone::resizeToContents()
|
||||||
|
|
||||||
// Minimum width is the rightmost card position plus enough room for
|
// Minimum width is the rightmost card position plus enough room for
|
||||||
// another card with padding, then margin.
|
// another card with padding, then margin.
|
||||||
currentMinimumWidth = xMax + (2 * CARD_WIDTH) + PADDING_X + MARGIN_RIGHT;
|
currentMinimumWidth = xMax + (2 * CardDimensions::WIDTH) + PADDING_X + MARGIN_RIGHT;
|
||||||
|
|
||||||
if (currentMinimumWidth < MIN_WIDTH)
|
if (currentMinimumWidth < MIN_WIDTH)
|
||||||
currentMinimumWidth = MIN_WIDTH;
|
currentMinimumWidth = MIN_WIDTH;
|
||||||
|
|
@ -279,10 +283,10 @@ void TableZone::computeCardStackWidths()
|
||||||
const int key = getCardStackMapKey(gridPoint.x() / 3, gridPoint.y());
|
const int key = getCardStackMapKey(gridPoint.x() / 3, gridPoint.y());
|
||||||
const int stackCount = cardStackCount.value(key, 0);
|
const int stackCount = cardStackCount.value(key, 0);
|
||||||
if (stackCount == 1)
|
if (stackCount == 1)
|
||||||
cardStackWidth.insert(key, CARD_WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() *
|
cardStackWidth.insert(key, CardDimensions::WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() *
|
||||||
STACKED_CARD_OFFSET_X);
|
STACKED_CARD_OFFSET_X);
|
||||||
else
|
else
|
||||||
cardStackWidth.insert(key, CARD_WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X);
|
cardStackWidth.insert(key, CardDimensions::WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,7 +300,7 @@ QPointF TableZone::mapFromGrid(QPoint gridPoint) const
|
||||||
// Add in width of card stack plus padding for each column
|
// Add in width of card stack plus padding for each column
|
||||||
for (int i = 0; i < gridPoint.x() / 3; ++i) {
|
for (int i = 0; i < gridPoint.x() / 3; ++i) {
|
||||||
const int key = getCardStackMapKey(i, gridPoint.y());
|
const int key = getCardStackMapKey(i, gridPoint.y());
|
||||||
x += cardStackWidth.value(key, CARD_WIDTH) + PADDING_X;
|
x += cardStackWidth.value(key, CardDimensions::WIDTH) + PADDING_X;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInverted())
|
if (isInverted())
|
||||||
|
|
@ -307,7 +311,7 @@ QPointF TableZone::mapFromGrid(QPoint gridPoint) const
|
||||||
|
|
||||||
// Add in card size and padding for each row
|
// Add in card size and padding for each row
|
||||||
for (int i = 0; i < gridPoint.y(); ++i)
|
for (int i = 0; i < gridPoint.y(); ++i)
|
||||||
y += CARD_HEIGHT + PADDING_Y;
|
y += CardDimensions::HEIGHT + PADDING_Y;
|
||||||
|
|
||||||
return QPointF(x, y);
|
return QPointF(x, y);
|
||||||
}
|
}
|
||||||
|
|
@ -321,7 +325,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const
|
||||||
int y = mapPoint.y() - MARGIN_TOP;
|
int y = mapPoint.y() - MARGIN_TOP;
|
||||||
|
|
||||||
// Below calculation effectively rounds to the nearest grid point.
|
// Below calculation effectively rounds to the nearest grid point.
|
||||||
const int gridPointHeight = CARD_HEIGHT + PADDING_Y;
|
const int gridPointHeight = CardDimensions::HEIGHT + PADDING_Y;
|
||||||
int gridPointY = (y + PADDING_Y / 2) / gridPointHeight;
|
int gridPointY = (y + PADDING_Y / 2) / gridPointHeight;
|
||||||
|
|
||||||
gridPointY = clampValidTableRow(gridPointY);
|
gridPointY = clampValidTableRow(gridPointY);
|
||||||
|
|
@ -337,7 +341,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const
|
||||||
|
|
||||||
// Maximum value is a card width from the right margin, referenced to the
|
// Maximum value is a card width from the right margin, referenced to the
|
||||||
// grid area.
|
// grid area.
|
||||||
const int xMax = width - MARGIN_LEFT - MARGIN_RIGHT - CARD_WIDTH;
|
const int xMax = width - MARGIN_LEFT - MARGIN_RIGHT - CardDimensions::WIDTH;
|
||||||
|
|
||||||
int xStack = 0;
|
int xStack = 0;
|
||||||
int xNextStack = 0;
|
int xNextStack = 0;
|
||||||
|
|
@ -345,7 +349,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const
|
||||||
while ((xNextStack <= x) && (xNextStack <= xMax)) {
|
while ((xNextStack <= x) && (xNextStack <= xMax)) {
|
||||||
xStack = xNextStack;
|
xStack = xNextStack;
|
||||||
const int key = getCardStackMapKey(nextStackCol, gridPointY);
|
const int key = getCardStackMapKey(nextStackCol, gridPointY);
|
||||||
xNextStack += cardStackWidth.value(key, CARD_WIDTH) + PADDING_X;
|
xNextStack += cardStackWidth.value(key, CardDimensions::WIDTH) + PADDING_X;
|
||||||
nextStackCol++;
|
nextStackCol++;
|
||||||
}
|
}
|
||||||
int stackCol = qMax(nextStackCol - 1, 0);
|
int stackCol = qMax(nextStackCol - 1, 0);
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,12 @@ private:
|
||||||
/*
|
/*
|
||||||
Minimum width of the table zone including margins.
|
Minimum width of the table zone including margins.
|
||||||
*/
|
*/
|
||||||
static const int MIN_WIDTH = MARGIN_LEFT + (5 * CARD_WIDTH) + MARGIN_RIGHT;
|
static const int MIN_WIDTH = MARGIN_LEFT + (5 * CardDimensions::WIDTH) + MARGIN_RIGHT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Offset sizes when cards are stacked on each other in the grid
|
Offset sizes when cards are stacked on each other in the grid
|
||||||
*/
|
*/
|
||||||
static const int STACKED_CARD_OFFSET_X = CARD_WIDTH / 3;
|
static const int STACKED_CARD_OFFSET_X = CardDimensions::WIDTH / 3;
|
||||||
static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3;
|
static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,10 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
||||||
for (int i = 0; i < cardList.size(); ++i) {
|
for (int i = 0; i < cardList.size(); ++i) {
|
||||||
auto card = cardList[i];
|
auto card = cardList[i];
|
||||||
CardRef cardRef = {QString::fromStdString(card->name()), QString::fromStdString(card->provider_id())};
|
CardRef cardRef = {QString::fromStdString(card->name()), QString::fromStdString(card->provider_id())};
|
||||||
getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, cardRef, card->id()), false, i);
|
auto copy = new CardItem(getLogic()->getPlayer(), this, cardRef, card->id());
|
||||||
|
copy->setFaceDown(card->face_down());
|
||||||
|
|
||||||
|
getLogic()->addCard(copy, false, i);
|
||||||
}
|
}
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
} else if (!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->contentsKnown()) {
|
} else if (!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->contentsKnown()) {
|
||||||
|
|
@ -91,8 +94,10 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
||||||
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
|
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
|
||||||
for (int i = 0; i < number; i++) {
|
for (int i = 0; i < number; i++) {
|
||||||
CardItem *card = c.at(i);
|
CardItem *card = c.at(i);
|
||||||
getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId()), false,
|
auto copy = new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId());
|
||||||
i);
|
copy->setFaceDown(card->getFaceDown());
|
||||||
|
|
||||||
|
getLogic()->addCard(copy, false, i);
|
||||||
}
|
}
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
}
|
}
|
||||||
|
|
@ -107,12 +112,15 @@ void ZoneViewZone::zoneDumpReceived(const Response &r)
|
||||||
auto cardName = QString::fromStdString(cardInfo.name());
|
auto cardName = QString::fromStdString(cardInfo.name());
|
||||||
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
|
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
|
||||||
auto card = new CardItem(getLogic()->getPlayer(), this, {cardName, cardProviderId}, cardInfo.id(), getLogic());
|
auto card = new CardItem(getLogic()->getPlayer(), this, {cardName, cardProviderId}, cardInfo.id(), getLogic());
|
||||||
|
card->setFaceDown(cardInfo.face_down());
|
||||||
getLogic()->rawInsertCard(card, i);
|
getLogic()->rawInsertCard(card, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
qobject_cast<ZoneViewZoneLogic *>(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE);
|
qobject_cast<ZoneViewZoneLogic *>(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE);
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
emit getLogic()->cardCountChanged();
|
// clang-format off
|
||||||
|
emit getLogic()->cardCountChanged(); // emit keyword causes spurious spacing around ->
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
|
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
|
||||||
|
|
@ -160,8 +168,8 @@ void ZoneViewZone::reorganizeCards()
|
||||||
// determine bounding rect
|
// determine bounding rect
|
||||||
qreal aleft = 0;
|
qreal aleft = 0;
|
||||||
qreal atop = 0;
|
qreal atop = 0;
|
||||||
qreal awidth = gridSize.cols * CARD_WIDTH + (CARD_WIDTH / 2) + HORIZONTAL_PADDING;
|
qreal awidth = gridSize.cols * CardDimensions::WIDTH_F + CardDimensions::WIDTH_HALF_F + HORIZONTAL_PADDING;
|
||||||
qreal aheight = (gridSize.rows * CARD_HEIGHT) / 3 + CARD_HEIGHT * 1.3;
|
qreal aheight = (gridSize.rows * CardDimensions::HEIGHT_F) / 3 + CardDimensions::HEIGHT_F * 1.3;
|
||||||
optimumRect = QRectF(aleft, atop, awidth, aheight);
|
optimumRect = QRectF(aleft, atop, awidth, aheight);
|
||||||
|
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
|
|
@ -204,8 +212,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca
|
||||||
}
|
}
|
||||||
|
|
||||||
lastColumnProp = columnProp;
|
lastColumnProp = columnProp;
|
||||||
qreal x = col * CARD_WIDTH;
|
qreal x = col * CardDimensions::WIDTH_F;
|
||||||
qreal y = row * CARD_HEIGHT / 3;
|
qreal y = row * CardDimensions::HEIGHT_F / 3;
|
||||||
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
||||||
c->setRealZValue(i);
|
c->setRealZValue(i);
|
||||||
longestRow = qMax(row, longestRow);
|
longestRow = qMax(row, longestRow);
|
||||||
|
|
@ -232,8 +240,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca
|
||||||
|
|
||||||
for (int i = 0; i < cardCount; i++) {
|
for (int i = 0; i < cardCount; i++) {
|
||||||
CardItem *c = cards.at(i);
|
CardItem *c = cards.at(i);
|
||||||
qreal x = (i / rows) * CARD_WIDTH;
|
qreal x = (i / rows) * CardDimensions::WIDTH_F;
|
||||||
qreal y = (i % rows) * CARD_HEIGHT / 3;
|
qreal y = (i % rows) * CardDimensions::HEIGHT_F / 3;
|
||||||
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
||||||
c->setRealZValue(i);
|
c->setRealZValue(i);
|
||||||
}
|
}
|
||||||
|
|
@ -279,8 +287,13 @@ void ZoneViewZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
cmd.set_is_reversed(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getIsReversed());
|
cmd.set_is_reversed(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getIsReversed());
|
||||||
|
|
||||||
for (int i = 0; i < dragItems.size(); ++i)
|
for (int i = 0; i < dragItems.size(); ++i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
|
auto cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(dragItems[i]->getId());
|
||||||
|
if (dragItems[i]->isForceFaceDown()) {
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../game_scene.h"
|
#include "../game_scene.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../player/player_actions.h"
|
#include "../player/player_actions.h"
|
||||||
|
#include "../z_values.h"
|
||||||
#include "view_zone.h"
|
#include "view_zone.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
|
@ -47,7 +48,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
|
||||||
{
|
{
|
||||||
setAcceptHoverEvents(true);
|
setAcceptHoverEvents(true);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setZValue(2000000006);
|
setZValue(ZValues::ZONE_VIEW_WIDGET);
|
||||||
setFlag(ItemIgnoresTransformations);
|
setFlag(ItemIgnoresTransformations);
|
||||||
|
|
||||||
QGraphicsLinearLayout *vbox = new QGraphicsLinearLayout(Qt::Vertical);
|
QGraphicsLinearLayout *vbox = new QGraphicsLinearLayout(Qt::Vertical);
|
||||||
|
|
@ -71,7 +72,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
|
||||||
|
|
||||||
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
|
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
|
||||||
searchEditProxy->setWidget(&searchEdit);
|
searchEditProxy->setWidget(&searchEdit);
|
||||||
searchEditProxy->setZValue(2000000007);
|
searchEditProxy->setZValue(ZValues::DRAG_ITEM);
|
||||||
vbox->addItem(searchEditProxy);
|
vbox->addItem(searchEditProxy);
|
||||||
|
|
||||||
// top row
|
// top row
|
||||||
|
|
@ -80,13 +81,13 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
|
||||||
// groupBy options
|
// groupBy options
|
||||||
QGraphicsProxyWidget *groupBySelectorProxy = new QGraphicsProxyWidget;
|
QGraphicsProxyWidget *groupBySelectorProxy = new QGraphicsProxyWidget;
|
||||||
groupBySelectorProxy->setWidget(&groupBySelector);
|
groupBySelectorProxy->setWidget(&groupBySelector);
|
||||||
groupBySelectorProxy->setZValue(2000000008);
|
groupBySelectorProxy->setZValue(ZValues::TOP_UI);
|
||||||
hTopRow->addItem(groupBySelectorProxy);
|
hTopRow->addItem(groupBySelectorProxy);
|
||||||
|
|
||||||
// sortBy options
|
// sortBy options
|
||||||
QGraphicsProxyWidget *sortBySelectorProxy = new QGraphicsProxyWidget;
|
QGraphicsProxyWidget *sortBySelectorProxy = new QGraphicsProxyWidget;
|
||||||
sortBySelectorProxy->setWidget(&sortBySelector);
|
sortBySelectorProxy->setWidget(&sortBySelector);
|
||||||
sortBySelectorProxy->setZValue(2000000007);
|
sortBySelectorProxy->setZValue(ZValues::DRAG_ITEM);
|
||||||
hTopRow->addItem(sortBySelectorProxy);
|
hTopRow->addItem(sortBySelectorProxy);
|
||||||
|
|
||||||
vbox->addItem(hTopRow);
|
vbox->addItem(hTopRow);
|
||||||
|
|
@ -457,7 +458,7 @@ void ZoneViewWidget::resizeScrollbar(const qreal newZoneHeight)
|
||||||
*/
|
*/
|
||||||
static qreal rowsToHeight(int rows)
|
static qreal rowsToHeight(int rows)
|
||||||
{
|
{
|
||||||
const qreal cardsHeight = (rows + 1) * (CARD_HEIGHT / 3);
|
const qreal cardsHeight = (rows + 1) * (CardDimensions::HEIGHT_F / 3);
|
||||||
return cardsHeight + 5; // +5 padding to make the cutoff look nicer
|
return cardsHeight + 5; // +5 padding to make the cutoff look nicer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ QNetworkReply *CardPictureLoaderWorker::makeRequest(const QUrl &url, CardPicture
|
||||||
|
|
||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
||||||
|
req.setRawHeader("Accept", "image/avif,image/webp,image/apng,image/,/*;q=0.8");
|
||||||
if (!picDownload) {
|
if (!picDownload) {
|
||||||
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
|
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
|
|
||||||
// Card back returned by gatherer when card is not found
|
// Card back returned by gatherer when card is not found
|
||||||
static const QStringList MD5_BLACKLIST = {"db0c48db407a907c16ade38de048a441"};
|
static const QStringList MD5_BLACKLIST = {
|
||||||
|
"db0c48db407a907c16ade38de048a441", // Old card back hash. Keep around just in case
|
||||||
|
"fbc7d763c08771c260b39e2115414eeb" // Current card back hash
|
||||||
|
};
|
||||||
|
|
||||||
CardPictureLoaderWorkerWork::CardPictureLoaderWorkerWork(const CardPictureLoaderWorker *worker, const ExactCard &toLoad)
|
CardPictureLoaderWorkerWork::CardPictureLoaderWorkerWork(const CardPictureLoaderWorker *worker, const ExactCard &toLoad)
|
||||||
: QObject(nullptr), cardToDownload(CardPictureToLoad(toLoad)),
|
: QObject(nullptr), cardToDownload(CardPictureToLoad(toLoad)),
|
||||||
|
|
@ -70,16 +73,22 @@ void CardPictureLoaderWorkerWork::picDownloadFailed()
|
||||||
void CardPictureLoaderWorkerWork::handleNetworkReply(QNetworkReply *reply)
|
void CardPictureLoaderWorkerWork::handleNetworkReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
QVariant redirectTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
QVariant redirectTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||||
|
bool redirectFailure = false;
|
||||||
if (redirectTarget.isValid()) {
|
if (redirectTarget.isValid()) {
|
||||||
QUrl url = reply->request().url();
|
QUrl url = reply->request().url();
|
||||||
QUrl redirectUrl = redirectTarget.toUrl();
|
QUrl redirectUrl = redirectTarget.toUrl();
|
||||||
if (redirectUrl.isRelative()) {
|
if (redirectUrl.isRelative()) {
|
||||||
redirectUrl = url.resolved(redirectUrl);
|
redirectUrl = url.resolved(redirectUrl);
|
||||||
}
|
}
|
||||||
|
if (url == redirectUrl) {
|
||||||
|
qCWarning(CardPictureLoaderWorkerWorkLog) << "recursive redirect detected!";
|
||||||
|
redirectFailure = true;
|
||||||
|
} else {
|
||||||
emit urlRedirected(url, redirectUrl);
|
emit urlRedirected(url, redirectUrl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (reply->error()) {
|
if (redirectFailure || reply->error()) {
|
||||||
handleFailedReply(reply);
|
handleFailedReply(reply);
|
||||||
} else {
|
} else {
|
||||||
handleSuccessfulReply(reply);
|
handleSuccessfulReply(reply);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <libcockatrice/card/database/card_database.h>
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
#include <libcockatrice/card/import/card_name_normalizer.h>
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||||
|
|
||||||
|
|
@ -29,26 +30,28 @@ DeckLoader::DeckLoader(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
std::optional<LoadedDeck>
|
||||||
|
DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
return false;
|
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
DeckList deckList = DeckList();
|
DeckList deckList;
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = deckList.loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file, CardNameNormalizer());
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice: {
|
case DeckFileFormat::Cockatrice: {
|
||||||
result = deckList.loadFromFile_Native(&file);
|
result = deckList.loadFromFile_Native(&file);
|
||||||
qCInfo(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
qCInfo(DeckLoaderLog) << "Retrying as plain format";
|
qCInfo(DeckLoaderLog) << "Failed to load " << fileName
|
||||||
|
<< "as cockatrice format; retrying as plain format";
|
||||||
file.seek(0);
|
file.seek(0);
|
||||||
result = deckList.loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file, CardNameNormalizer());
|
||||||
fmt = DeckFileFormat::PlainText;
|
fmt = DeckFileFormat::PlainText;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -58,120 +61,128 @@ bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fm
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
|
||||||
loadedDeck.deckList = deckList;
|
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
if (userRequest) {
|
|
||||||
updateLastLoadedTimestamp(fileName, fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit deckLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
qCInfo(DeckLoaderLog) << "Deck was loaded -" << result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
|
||||||
{
|
|
||||||
auto *watcher = new QFutureWatcher<bool>(this);
|
|
||||||
|
|
||||||
connect(watcher, &QFutureWatcher<bool>::finished, this, [this, watcher, fileName, fmt, userRequest]() {
|
|
||||||
const bool result = watcher->result();
|
|
||||||
watcher->deleteLater();
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
if (userRequest) {
|
|
||||||
updateLastLoadedTimestamp(fileName, fmt);
|
|
||||||
}
|
|
||||||
emit deckLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit loadFinished(result);
|
|
||||||
});
|
|
||||||
|
|
||||||
QFuture<bool> future = QtConcurrent::run([=, this]() {
|
|
||||||
QFile file(fileName);
|
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fmt) {
|
|
||||||
case DeckFileFormat::PlainText:
|
|
||||||
return loadedDeck.deckList.loadFromFile_Plain(&file);
|
|
||||||
case DeckFileFormat::Cockatrice: {
|
|
||||||
bool result = false;
|
|
||||||
result = loadedDeck.deckList.loadFromFile_Native(&file);
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
file.seek(0);
|
qCWarning(DeckLoaderLog) << "Failed to load " << fileName << "as" << fmt;
|
||||||
return loadedDeck.deckList.loadFromFile_Plain(&file);
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
watcher->setFuture(future);
|
LoadedDeck::LoadInfo lastLoadInfo = {
|
||||||
return true; // Return immediately to indicate the async task was started
|
.fileName = fileName,
|
||||||
}
|
.fileFormat = fmt,
|
||||||
|
|
||||||
bool DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId)
|
|
||||||
{
|
|
||||||
bool result = loadedDeck.deckList.loadFromString_Native(nativeString);
|
|
||||||
if (result) {
|
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.remoteDeckId = remoteDeckId,
|
|
||||||
};
|
};
|
||||||
|
LoadedDeck loadedDeck = {deckList, lastLoadInfo};
|
||||||
|
|
||||||
emit deckLoaded();
|
if (userRequest) {
|
||||||
|
updateLastLoadedTimestamp(loadedDeck);
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
qCDebug(DeckLoaderLog) << "Loaded deck" << fileName << "with userRequest:" << userRequest;
|
||||||
|
|
||||||
|
return loadedDeck;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::saveToFile(const QString &fileName, DeckFileFormat::Format fmt)
|
void DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
||||||
|
{
|
||||||
|
QFuture<void> future = QtConcurrent::run([=, this] {
|
||||||
|
std::optional<LoadedDeck> deckOpt = loadFromFile(fileName, fmt, userRequest);
|
||||||
|
if (deckOpt) {
|
||||||
|
loadedDeck = deckOpt.value();
|
||||||
|
}
|
||||||
|
emit loadFinished(deckOpt.has_value());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckLoader::reload()
|
||||||
|
{
|
||||||
|
QString lastFileName = loadedDeck.lastLoadInfo.fileName;
|
||||||
|
if (lastFileName.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::optional<LoadedDeck> deck = loadFromFile(lastFileName, loadedDeck.lastLoadInfo.fileFormat, false);
|
||||||
|
|
||||||
|
if (!deck) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedDeck = *deck;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<LoadedDeck> DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId)
|
||||||
|
{
|
||||||
|
DeckList deckList;
|
||||||
|
bool success = deckList.loadFromString_Native(nativeString);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
qCWarning(DeckLoaderLog) << "Failed to load remote deck with id" << remoteDeckId << ":" << nativeString;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadedDeck::LoadInfo lastLoadInfo = {.remoteDeckId = remoteDeckId};
|
||||||
|
LoadedDeck loadedDeck = {deckList, lastLoadInfo};
|
||||||
|
|
||||||
|
qCDebug(DeckLoaderLog) << "Loaded remote deck with id" << remoteDeckId;
|
||||||
|
|
||||||
|
return loadedDeck;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<LoadedDeck::LoadInfo>
|
||||||
|
DeckLoader::saveToFile(const DeckList &deck, const QString &fileName, DeckFileFormat::Format fmt)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
return false;
|
qCWarning(DeckLoaderLog) << "Could not create or open file:" << fileName;
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = false;
|
bool success = false;
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = loadedDeck.deckList.saveToFile_Plain(&file);
|
success = deck.saveToFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
result = loadedDeck.deckList.saveToFile_Native(&file);
|
success = deck.saveToFile_Native(&file);
|
||||||
qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
qCInfo(DeckLoaderLog) << "Deck was saved -" << result;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.flush();
|
file.flush();
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
return result;
|
qCInfo(DeckLoaderLog) << "Saved deck to " << fileName << "with format" << fmt << "-" << success;
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadedDeck::LoadInfo lastLoadInfo = {fileName, fmt};
|
||||||
|
return lastLoadInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt)
|
bool DeckLoader::saveToFile(const LoadedDeck &deck)
|
||||||
{
|
{
|
||||||
|
auto opt = saveToFile(deck.deckList, deck.lastLoadInfo.fileName, deck.lastLoadInfo.fileFormat);
|
||||||
|
return opt.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckLoader::saveToNewFile(LoadedDeck &deck, const QString &fileName, DeckFileFormat::Format fmt)
|
||||||
|
{
|
||||||
|
std::optional<LoadedDeck::LoadInfo> infoOpt = saveToFile(deck.deckList, fileName, fmt);
|
||||||
|
|
||||||
|
if (infoOpt) {
|
||||||
|
deck.lastLoadInfo = infoOpt.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return infoOpt.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the lastLoadedTimestamp field in the file corresponding to the deck, without changing the
|
||||||
|
* FileModificationTime of the file.
|
||||||
|
*/
|
||||||
|
bool DeckLoader::updateLastLoadedTimestamp(LoadedDeck &deck)
|
||||||
|
{
|
||||||
|
QString fileName = deck.lastLoadInfo.fileName;
|
||||||
|
|
||||||
QFileInfo fileInfo(fileName);
|
QFileInfo fileInfo(fileName);
|
||||||
if (!fileInfo.exists()) {
|
if (!fileInfo.exists()) {
|
||||||
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
||||||
|
|
@ -190,24 +201,19 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileForm
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
// Perform file modifications
|
// Perform file modifications
|
||||||
switch (fmt) {
|
switch (deck.lastLoadInfo.fileFormat) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = loadedDeck.deckList.saveToFile_Plain(&file);
|
result = deck.deckList.saveToFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
loadedDeck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
deck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
||||||
result = loadedDeck.deckList.saveToFile_Native(&file);
|
result = deck.deckList.saveToFile_Native(&file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close(); // Close the file to ensure changes are flushed
|
file.close(); // Close the file to ensure changes are flushed
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Re-open the file and set the original timestamp
|
// Re-open the file and set the original timestamp
|
||||||
if (!file.open(QIODevice::ReadWrite)) {
|
if (!file.open(QIODevice::ReadWrite)) {
|
||||||
qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName;
|
qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName;
|
||||||
|
|
@ -434,8 +440,13 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
|
bool DeckLoader::convertToCockatriceFormat(LoadedDeck &deck)
|
||||||
{
|
{
|
||||||
|
QString fileName = deck.lastLoadInfo.fileName;
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Change the file extension to .cod
|
// Change the file extension to .cod
|
||||||
QFileInfo fileInfo(fileName);
|
QFileInfo fileInfo(fileName);
|
||||||
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
|
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
|
||||||
|
|
@ -453,7 +464,7 @@ bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
|
||||||
switch (DeckFileFormat::getFormatFromName(fileName)) {
|
switch (DeckFileFormat::getFormatFromName(fileName)) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
// Save in Cockatrice's native format
|
// Save in Cockatrice's native format
|
||||||
result = loadedDeck.deckList.saveToFile_Native(&file);
|
result = deck.deckList.saveToFile_Native(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
|
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
|
||||||
|
|
@ -474,7 +485,7 @@ bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
|
||||||
} else {
|
} else {
|
||||||
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
|
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
|
||||||
}
|
}
|
||||||
loadedDeck.lastLoadInfo = {
|
deck.lastLoadInfo = {
|
||||||
.fileName = newFileName,
|
.fileName = newFileName,
|
||||||
.fileFormat = DeckFileFormat::Cockatrice,
|
.fileFormat = DeckFileFormat::Cockatrice,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ class DeckLoader : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
signals:
|
signals:
|
||||||
void deckLoaded();
|
|
||||||
void loadFinished(bool success);
|
void loadFinished(bool success);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -53,11 +52,67 @@ public:
|
||||||
return loadedDeck.lastLoadInfo.isEmpty();
|
return loadedDeck.lastLoadInfo.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest = false);
|
/**
|
||||||
bool loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest);
|
* @brief Asynchronously loads a deck from a local file into this DeckLoader.
|
||||||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
* The `loadFinished` signal will be emitted when the load finishes.
|
||||||
bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt);
|
* Once the loading finishes, the deck can be accessed with `getDeck`
|
||||||
bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt);
|
* @param fileName The file to load
|
||||||
|
* @param fmt The format of the file to load
|
||||||
|
* @param userRequest Whether the load was manually requested by the user, instead of being done in the background.
|
||||||
|
*/
|
||||||
|
void loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads the file that the lastLoadInfo currently points to into this instance.
|
||||||
|
* No-ops if the lastLoadInfo is missing the required info or the load fails.
|
||||||
|
* @return Whether the loaded succeeded.
|
||||||
|
*/
|
||||||
|
bool reload();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads a deck from a local file.
|
||||||
|
* @param fileName The file to load
|
||||||
|
* @param fmt The format of the file to load
|
||||||
|
* @param userRequest Whether the load was manually requested by the user, instead of being done in the background.
|
||||||
|
* @return An optional containing the LoadedDeck, or empty if the load failed.
|
||||||
|
*/
|
||||||
|
static std::optional<LoadedDeck>
|
||||||
|
loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads a deck from the response of a remote deck request
|
||||||
|
* @param nativeString The deck string, in cod format
|
||||||
|
* @param remoteDeckId The remote deck id
|
||||||
|
* @return An optional containing the LoadedDeck, or empty if the load failed.
|
||||||
|
*/
|
||||||
|
static std::optional<LoadedDeck> loadFromRemote(const QString &nativeString, int remoteDeckId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Saves a DeckList to a local file.
|
||||||
|
* @param deck The DeckList
|
||||||
|
* @param fileName The file to write to
|
||||||
|
* @param fmt The deck file format to use
|
||||||
|
* @return An optional containing the LoadInfo for the new file, or empty if the save failed.
|
||||||
|
*/
|
||||||
|
static std::optional<LoadedDeck::LoadInfo>
|
||||||
|
saveToFile(const DeckList &deck, const QString &fileName, DeckFileFormat::Format fmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Saves a LoadedDeck to a local file.
|
||||||
|
* Uses the lastLoadInfo in the LoadedDeck to determine where to save to.
|
||||||
|
* @param deck The LoadedDeck to save. Should have valid lastLoadInfo.
|
||||||
|
* @return Whether the save succeeded.
|
||||||
|
*/
|
||||||
|
static bool saveToFile(const LoadedDeck &deck);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Saves a LoadedDeck to a new local file.
|
||||||
|
* @param deck The LoadedDeck to save. Will update the lastLoadInfo.
|
||||||
|
* @param fileName The file to write to
|
||||||
|
* @param fmt The deck file format to use
|
||||||
|
* @return Whether the save succeeded.
|
||||||
|
*/
|
||||||
|
static bool saveToNewFile(LoadedDeck &deck, const QString &fileName, DeckFileFormat::Format fmt);
|
||||||
|
|
||||||
static QString exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website);
|
static QString exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website);
|
||||||
|
|
||||||
|
|
@ -74,7 +129,13 @@ public:
|
||||||
*/
|
*/
|
||||||
static void printDeckList(QPrinter *printer, const DeckList &deckList);
|
static void printDeckList(QPrinter *printer, const DeckList &deckList);
|
||||||
|
|
||||||
bool convertToCockatriceFormat(const QString &fileName);
|
/**
|
||||||
|
* Converts the given deck's file to the cockatrice file format.
|
||||||
|
* Uses the lastLoadInfo in the LoadedDeck to determine the current name of the file and where to save to.
|
||||||
|
* @param deck The deck to convert. Should have valid lastLoadInfo. Will update the lastLoadInfo.
|
||||||
|
* @return Whether the conversion succeeded.
|
||||||
|
*/
|
||||||
|
static bool convertToCockatriceFormat(LoadedDeck &deck);
|
||||||
|
|
||||||
LoadedDeck &getDeck()
|
LoadedDeck &getDeck()
|
||||||
{
|
{
|
||||||
|
|
@ -90,6 +151,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool updateLastLoadedTimestamp(LoadedDeck &deck);
|
||||||
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
|
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
|
||||||
static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList);
|
static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,21 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
#include <QPalette>
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QStyleHints>
|
||||||
|
#include <Qt>
|
||||||
|
|
||||||
#define NONE_THEME_NAME "Default"
|
#define NONE_THEME_NAME "Default"
|
||||||
|
#define FUSION_THEME_NAME "Fusion (System Default)"
|
||||||
|
#define FUSION_THEME_NAME_LIGHT "Fusion (Light)"
|
||||||
|
#define FUSION_THEME_NAME_DARK "Fusion (Dark)"
|
||||||
#define STYLE_CSS_NAME "style.css"
|
#define STYLE_CSS_NAME "style.css"
|
||||||
#define HANDZONE_BG_NAME "handzone"
|
#define HANDZONE_BG_NAME "handzone"
|
||||||
#define PLAYERZONE_BG_NAME "playerzone"
|
#define PLAYERZONE_BG_NAME "playerzone"
|
||||||
|
|
@ -21,9 +32,69 @@ static const QColor PLAYERZONE_BG_DEFAULT = QColor(200, 200, 200);
|
||||||
static const QColor STACKZONE_BG_DEFAULT = QColor(113, 43, 43);
|
static const QColor STACKZONE_BG_DEFAULT = QColor(113, 43, 43);
|
||||||
static const QStringList DEFAULT_RESOURCE_PATHS = {":/resources"};
|
static const QStringList DEFAULT_RESOURCE_PATHS = {":/resources"};
|
||||||
|
|
||||||
|
struct PaletteColorInfo
|
||||||
|
{
|
||||||
|
QPalette::ColorGroup group;
|
||||||
|
QPalette::ColorRole role;
|
||||||
|
QColor color;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[maybe_unused]] static inline QList<PaletteColorInfo> queryAllPaletteColors(const QPalette &palette = qApp->palette())
|
||||||
|
{
|
||||||
|
QList<PaletteColorInfo> colors;
|
||||||
|
|
||||||
|
// Iterate through relevant color groups (Active, Disabled, Inactive)
|
||||||
|
const QList<QPalette::ColorGroup> groups = {QPalette::Active, QPalette::Disabled, QPalette::Inactive};
|
||||||
|
|
||||||
|
for (auto group : groups) {
|
||||||
|
// Iterate through all color roles (excluding NoRole and NColorRoles)
|
||||||
|
for (int r = 0; r < QPalette::NColorRoles; ++r) {
|
||||||
|
auto role = static_cast<QPalette::ColorRole>(r);
|
||||||
|
if (role == QPalette::NoRole)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PaletteColorInfo info;
|
||||||
|
info.group = group;
|
||||||
|
info.role = role;
|
||||||
|
info.color = palette.color(group, role);
|
||||||
|
colors.append(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pretty print version
|
||||||
|
[[maybe_unused]] static inline void printPaletteColors(const QPalette &palette = qApp->palette())
|
||||||
|
{
|
||||||
|
QMetaEnum groupEnum = QMetaEnum::fromType<QPalette::ColorGroup>();
|
||||||
|
QMetaEnum roleEnum = QMetaEnum::fromType<QPalette::ColorRole>();
|
||||||
|
|
||||||
|
const QList<QPalette::ColorGroup> groups = {QPalette::Active, QPalette::Disabled, QPalette::Inactive};
|
||||||
|
|
||||||
|
for (auto group : groups) {
|
||||||
|
qInfo() << "\n===========" << groupEnum.valueToKey(group) << "===========";
|
||||||
|
|
||||||
|
for (int r = 0; r < QPalette::NColorRoles; ++r) {
|
||||||
|
auto role = static_cast<QPalette::ColorRole>(r);
|
||||||
|
if (role == QPalette::NoRole)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QColor color = palette.color(group, role);
|
||||||
|
qInfo().nospace() << qPrintable(QString("%1").arg(roleEnum.valueToKey(role), -20)) << " : "
|
||||||
|
<< qPrintable(color.name(QColor::HexArgb)) << " (RGBA: " << color.red() << ", "
|
||||||
|
<< color.green() << ", " << color.blue() << ", " << color.alpha() << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
defaultStyleName = qApp->style()->objectName();
|
||||||
ensureThemeDirectoryExists();
|
ensureThemeDirectoryExists();
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||||
|
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot);
|
||||||
|
#endif
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, &ThemeManager::themeChangedSlot);
|
connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, &ThemeManager::themeChangedSlot);
|
||||||
themeChangedSlot();
|
themeChangedSlot();
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +119,10 @@ QStringMap &ThemeManager::getAvailableThemes()
|
||||||
// load themes from user profile dir
|
// load themes from user profile dir
|
||||||
dir.setPath(SettingsCache::instance().getThemesPath());
|
dir.setPath(SettingsCache::instance().getThemesPath());
|
||||||
|
|
||||||
|
availableThemes.insert(FUSION_THEME_NAME, dir.filePath("Fusion (System Default)"));
|
||||||
|
availableThemes.insert(FUSION_THEME_NAME_LIGHT, dir.filePath("Fusion (Light)"));
|
||||||
|
availableThemes.insert(FUSION_THEME_NAME_DARK, dir.filePath("Fusion (Dark)"));
|
||||||
|
|
||||||
for (QString themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
for (QString themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
||||||
if (!availableThemes.contains(themeName)) {
|
if (!availableThemes.contains(themeName)) {
|
||||||
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
||||||
|
|
@ -102,6 +177,145 @@ QBrush ThemeManager::loadExtraBrush(QString fileName, QBrush &fallbackBrush)
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline QPalette createDarkGreenFusionPalette()
|
||||||
|
{
|
||||||
|
QPalette p;
|
||||||
|
|
||||||
|
// ---------- Core backgrounds ----------
|
||||||
|
p.setColor(QPalette::Window, QColor(30, 30, 30)); // #ff1e1e1e
|
||||||
|
p.setColor(QPalette::Base, QColor(45, 45, 45)); // #ff2d2d2d
|
||||||
|
p.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); // #ff353535
|
||||||
|
p.setColor(QPalette::Button, QColor(60, 60, 60)); // #ff3c3c3c
|
||||||
|
p.setColor(QPalette::ToolTipBase, QColor(60, 60, 60)); // #ff3c3c3c
|
||||||
|
|
||||||
|
// ---------- Core text ----------
|
||||||
|
p.setColor(QPalette::WindowText, Qt::white); // #ffffffff
|
||||||
|
p.setColor(QPalette::Text, Qt::white); // #ffffffff
|
||||||
|
p.setColor(QPalette::ButtonText, Qt::white); // #ffffffff
|
||||||
|
p.setColor(QPalette::ToolTipText, QColor(212, 212, 212)); // #ffd4d4d4
|
||||||
|
p.setColor(QPalette::PlaceholderText, QColor(255, 255, 255, 128)); // #80ffffff
|
||||||
|
|
||||||
|
// ---------- Selection / focus ----------
|
||||||
|
const QColor highlight(20, 140, 60); // #ff148c3c
|
||||||
|
p.setColor(QPalette::Highlight, highlight);
|
||||||
|
p.setColor(QPalette::HighlightedText, Qt::white); // #ffffffff
|
||||||
|
|
||||||
|
// ---------- Links ----------
|
||||||
|
p.setColor(QPalette::Link, QColor(0, 246, 82)); // #ff00f652
|
||||||
|
p.setColor(QPalette::LinkVisited, QColor(0, 211, 70)); // #ff00d346
|
||||||
|
|
||||||
|
// ---------- Accent (Qt 6) ----------
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||||
|
p.setColor(QPalette::Accent, QColor(0, 211, 70)); // #ff00d346
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------- Bright text ----------
|
||||||
|
p.setColor(QPalette::BrightText, QColor(0, 246, 82)); // #ff00f652
|
||||||
|
|
||||||
|
// ---------- 3D / frame shading ----------
|
||||||
|
p.setColor(QPalette::Light, QColor(120, 120, 120)); // #ff787878
|
||||||
|
p.setColor(QPalette::Midlight, QColor(90, 90, 90)); // #ff5a5a5a
|
||||||
|
p.setColor(QPalette::Mid, QColor(40, 40, 40)); // #ff282828
|
||||||
|
p.setColor(QPalette::Dark, QColor(30, 30, 30)); // #ff1e1e1e
|
||||||
|
p.setColor(QPalette::Shadow, Qt::black); // #ff000000
|
||||||
|
|
||||||
|
// ---------- Disabled state ----------
|
||||||
|
const QColor disabledText(157, 157, 157); // #ff9d9d9d
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::WindowText, disabledText);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Text, disabledText);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::ButtonText, disabledText);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Base, QColor(30, 30, 30));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Window, QColor(30, 30, 30));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Link, QColor(48, 140, 198)); // #ff308cc6
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::LinkVisited, QColor(255, 0, 255)); // #ffff00ff
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::ToolTipBase, QColor(255, 255, 220));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::ToolTipText, Qt::black);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Accent, disabledText);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------- Inactive state ----------
|
||||||
|
p.setColor(QPalette::Inactive, QPalette::Highlight, QColor(30, 30, 30));
|
||||||
|
p.setColor(QPalette::Inactive, QPalette::HighlightedText, Qt::white);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||||
|
p.setColor(QPalette::Inactive, QPalette::Accent, QColor(30, 30, 30));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QPalette createLightGreenFusionPalette()
|
||||||
|
{
|
||||||
|
QPalette p;
|
||||||
|
|
||||||
|
// ---------- Core backgrounds ----------
|
||||||
|
p.setColor(QPalette::Window, QColor(240, 240, 240)); // #fff0f0f0
|
||||||
|
p.setColor(QPalette::Base, Qt::white); // #ffffffff
|
||||||
|
p.setColor(QPalette::AlternateBase, QColor(233, 231, 227)); // #ffe9e7e3
|
||||||
|
p.setColor(QPalette::Button, QColor(240, 240, 240)); // #fff0f0f0
|
||||||
|
p.setColor(QPalette::ToolTipBase, QColor(255, 255, 220)); // #ffffffdc
|
||||||
|
|
||||||
|
// ---------- Core text ----------
|
||||||
|
p.setColor(QPalette::WindowText, Qt::black); // #ff000000
|
||||||
|
p.setColor(QPalette::Text, Qt::black); // #ff000000
|
||||||
|
p.setColor(QPalette::ButtonText, Qt::black); // #ff000000
|
||||||
|
p.setColor(QPalette::ToolTipText, Qt::black); // #ff000000
|
||||||
|
p.setColor(QPalette::PlaceholderText, QColor(0, 0, 0, 128)); // #80000000
|
||||||
|
|
||||||
|
// ---------- Selection / focus ----------
|
||||||
|
const QColor highlight(20, 140, 60); // #ff148c3c
|
||||||
|
p.setColor(QPalette::Highlight, highlight);
|
||||||
|
p.setColor(QPalette::HighlightedText, Qt::white); // #ffffffff
|
||||||
|
|
||||||
|
// ---------- Links ----------
|
||||||
|
p.setColor(QPalette::Link, QColor(13, 95, 40)); // #ff0d5f28
|
||||||
|
p.setColor(QPalette::LinkVisited, QColor(8, 64, 27)); // #ff08401b
|
||||||
|
|
||||||
|
// ---------- Accent (Qt 6) ----------
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||||
|
p.setColor(QPalette::Accent, QColor(16, 117, 50)); // #ff107532
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------- Bright text ----------
|
||||||
|
p.setColor(QPalette::BrightText, Qt::white); // #ffffffff
|
||||||
|
|
||||||
|
// ---------- 3D / frame shading ----------
|
||||||
|
p.setColor(QPalette::Light, Qt::white); // #ffffffff
|
||||||
|
p.setColor(QPalette::Midlight, QColor(227, 227, 227)); // #ffe3e3e3
|
||||||
|
p.setColor(QPalette::Mid, QColor(160, 160, 160)); // #ffa0a0a0
|
||||||
|
p.setColor(QPalette::Dark, QColor(160, 160, 160)); // #ffa0a0a0
|
||||||
|
p.setColor(QPalette::Shadow, QColor(105, 105, 105)); // #ff696969
|
||||||
|
|
||||||
|
// ---------- Disabled state ----------
|
||||||
|
const QColor disabledText(120, 120, 120); // #ff787878
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::WindowText, disabledText);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Text, disabledText);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::ButtonText, disabledText);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Base, QColor(240, 240, 240));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Window, QColor(240, 240, 240));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Midlight, QColor(247, 247, 247));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::AlternateBase, QColor(247, 247, 247));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Shadow, Qt::black);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Link, QColor(0, 0, 255));
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::LinkVisited, QColor(255, 0, 255));
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Accent, disabledText);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------- Inactive state ----------
|
||||||
|
p.setColor(QPalette::Inactive, QPalette::Highlight, QColor(240, 240, 240));
|
||||||
|
p.setColor(QPalette::Inactive, QPalette::HighlightedText, Qt::black);
|
||||||
|
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||||
|
p.setColor(QPalette::Inactive, QPalette::Accent, QColor(240, 240, 240));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
void ThemeManager::themeChangedSlot()
|
void ThemeManager::themeChangedSlot()
|
||||||
{
|
{
|
||||||
QString themeName = SettingsCache::instance().getThemeName();
|
QString themeName = SettingsCache::instance().getThemeName();
|
||||||
|
|
@ -117,6 +331,26 @@ void ThemeManager::themeChangedSlot()
|
||||||
qApp->setStyleSheet("");
|
qApp->setStyleSheet("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (themeName == FUSION_THEME_NAME) {
|
||||||
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||||
|
QPalette palette;
|
||||||
|
if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
|
||||||
|
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
||||||
|
}
|
||||||
|
|
||||||
|
qApp->setPalette(palette);
|
||||||
|
#endif
|
||||||
|
} else if (themeName == FUSION_THEME_NAME_LIGHT) {
|
||||||
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
qApp->setPalette(createLightGreenFusionPalette());
|
||||||
|
} else if (themeName == FUSION_THEME_NAME_DARK) {
|
||||||
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
qApp->setPalette(createDarkGreenFusionPalette());
|
||||||
|
} else {
|
||||||
|
qApp->setStyle(defaultStyleName); // setting the style also sets the palette
|
||||||
|
}
|
||||||
|
|
||||||
if (dirPath.isEmpty()) {
|
if (dirPath.isEmpty()) {
|
||||||
// set default values
|
// set default values
|
||||||
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
|
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString defaultStyleName;
|
||||||
std::array<QBrush, Role::MaxRole + 1> brushes;
|
std::array<QBrush, Role::MaxRole + 1> brushes;
|
||||||
QStringMap availableThemes;
|
QStringMap availableThemes;
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
#include <libcockatrice/utility/qt_utils.h>
|
||||||
|
|
||||||
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, CardInfoPtr _card) : QWidget(parent), card(_card)
|
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, const QString &_colorIdentity)
|
||||||
|
: QWidget(parent), colorIdentity(_colorIdentity)
|
||||||
{
|
{
|
||||||
layout = new QHBoxLayout(this);
|
layout = new QHBoxLayout(this);
|
||||||
layout->setSpacing(5); // Small spacing between icons
|
layout->setSpacing(5); // Small spacing between icons
|
||||||
|
|
@ -17,40 +19,27 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, CardInfoPtr _card) : Q
|
||||||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
|
||||||
QString fullColorIdentity = "WUBRG";
|
|
||||||
|
|
||||||
if (card) {
|
|
||||||
manaCost = card->getColors(); // Get mana cost string
|
|
||||||
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
|
||||||
|
|
||||||
populateManaSymbolWidgets();
|
populateManaSymbolWidgets();
|
||||||
}
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
||||||
&ColorIdentityWidget::toggleUnusedVisibility);
|
&ColorIdentityWidget::toggleUnusedVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString _manaCost)
|
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, const CardInfoPtr &card)
|
||||||
: QWidget(parent), card(nullptr), manaCost(_manaCost)
|
: ColorIdentityWidget(parent, card->getColors())
|
||||||
{
|
{
|
||||||
layout = new QHBoxLayout(this);
|
|
||||||
layout->setSpacing(5); // Small spacing between icons
|
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
populateManaSymbolWidgets();
|
|
||||||
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
|
||||||
&ColorIdentityWidget::toggleUnusedVisibility);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorIdentityWidget::populateManaSymbolWidgets()
|
void ColorIdentityWidget::populateManaSymbolWidgets()
|
||||||
{
|
{
|
||||||
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||||
QString fullColorIdentity = "WUBRG";
|
QString fullColorIdentity = "WUBRG";
|
||||||
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
QStringList symbols = parseColorIdentity(colorIdentity); // Parse mana cost string
|
||||||
|
|
||||||
|
// clear old layout
|
||||||
|
QtUtils::clearLayoutRec(layout);
|
||||||
|
|
||||||
|
// populate mana symbols
|
||||||
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()) {
|
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()) {
|
||||||
for (const QString symbol : fullColorIdentity) {
|
for (const QString symbol : fullColorIdentity) {
|
||||||
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||||
|
|
@ -64,15 +53,18 @@ void ColorIdentityWidget::populateManaSymbolWidgets()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ColorIdentityWidget::setColorIdentity(const QString &_colorIdentity)
|
||||||
|
{
|
||||||
|
if (colorIdentity == _colorIdentity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorIdentity = _colorIdentity;
|
||||||
|
populateManaSymbolWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
void ColorIdentityWidget::toggleUnusedVisibility()
|
void ColorIdentityWidget::toggleUnusedVisibility()
|
||||||
{
|
{
|
||||||
if (layout != nullptr) {
|
|
||||||
QLayoutItem *item;
|
|
||||||
while ((item = layout->takeAt(0)) != nullptr) {
|
|
||||||
item->widget()->deleteLater(); // Delete the widget
|
|
||||||
delete item; // Delete the layout item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
populateManaSymbolWidgets();
|
populateManaSymbolWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,12 +89,12 @@ void ColorIdentityWidget::resizeEvent(QResizeEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ColorIdentityWidget::parseColorIdentity(const QString &cmc)
|
QStringList ColorIdentityWidget::parseColorIdentity(const QString &manaString)
|
||||||
{
|
{
|
||||||
QStringList symbols;
|
QStringList symbols;
|
||||||
|
|
||||||
// Handle split costs (e.g., "3U // 4UU")
|
// Handle split costs (e.g., "3U // 4UU")
|
||||||
QStringList splitCosts = cmc.split(" // ");
|
QStringList splitCosts = manaString.split(" // ");
|
||||||
for (const QString &part : splitCosts) {
|
for (const QString &part : splitCosts) {
|
||||||
QRegularExpression regex(R"(\{([^}]+)\}|(\d+)|([WUBRGCSPX]))");
|
QRegularExpression regex(R"(\{([^}]+)\}|(\d+)|([WUBRGCSPX]))");
|
||||||
QRegularExpressionMatchIterator matches = regex.globalMatch(part);
|
QRegularExpressionMatchIterator matches = regex.globalMatch(part);
|
||||||
|
|
|
||||||
|
|
@ -15,19 +15,20 @@ class ColorIdentityWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ColorIdentityWidget(QWidget *parent, CardInfoPtr card);
|
explicit ColorIdentityWidget(QWidget *parent, const QString &_colorIdentity = "");
|
||||||
explicit ColorIdentityWidget(QWidget *parent, QString manaCost);
|
explicit ColorIdentityWidget(QWidget *parent, const CardInfoPtr &card);
|
||||||
|
|
||||||
void populateManaSymbolWidgets();
|
void populateManaSymbolWidgets();
|
||||||
|
|
||||||
QStringList parseColorIdentity(const QString &manaString);
|
static QStringList parseColorIdentity(const QString &manaString);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void setColorIdentity(const QString &_colorIdentity);
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
void toggleUnusedVisibility();
|
void toggleUnusedVisibility();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CardInfoPtr card;
|
QString colorIdentity;
|
||||||
QString manaCost;
|
|
||||||
QHBoxLayout *layout;
|
QHBoxLayout *layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,35 @@ CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
|
||||||
&CardGroupDisplayWidget::onSelectionChanged);
|
&CardGroupDisplayWidget::onSelectionChanged);
|
||||||
}
|
}
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
||||||
|
connect(deckListModel, &QAbstractItemModel::dataChanged, this, &CardGroupDisplayWidget::onDataChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just here so it can get overwritten in subclasses.
|
||||||
|
void CardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// User Interaction
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::mousePressEvent(event);
|
||||||
|
if (selectionModel) {
|
||||||
|
selectionModel->clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::onHover(const ExactCard &card)
|
||||||
|
{
|
||||||
|
emit cardHovered(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
void CardGroupDisplayWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
||||||
|
|
@ -53,12 +82,15 @@ void CardGroupDisplayWidget::onSelectionChanged(const QItemSelection &selected,
|
||||||
|
|
||||||
auto it = indexToWidgetMap.find(QPersistentModelIndex(idx));
|
auto it = indexToWidgetMap.find(QPersistentModelIndex(idx));
|
||||||
if (it != indexToWidgetMap.end()) {
|
if (it != indexToWidgetMap.end()) {
|
||||||
if (auto displayWidget = qobject_cast<CardInfoPictureWithTextOverlayWidget *>(it.value())) {
|
// Highlight all copies of this card
|
||||||
|
for (auto widget : it.value()) {
|
||||||
|
if (auto displayWidget = qobject_cast<CardInfoPictureWithTextOverlayWidget *>(widget)) {
|
||||||
displayWidget->setHighlighted(true);
|
displayWidget->setHighlighted(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &range : deselected) {
|
for (auto &range : deselected) {
|
||||||
for (int row = range.top(); row <= range.bottom(); ++row) {
|
for (int row = range.top(); row <= range.bottom(); ++row) {
|
||||||
|
|
@ -68,29 +100,51 @@ void CardGroupDisplayWidget::onSelectionChanged(const QItemSelection &selected,
|
||||||
|
|
||||||
auto it = indexToWidgetMap.find(QPersistentModelIndex(idx));
|
auto it = indexToWidgetMap.find(QPersistentModelIndex(idx));
|
||||||
if (it != indexToWidgetMap.end()) {
|
if (it != indexToWidgetMap.end()) {
|
||||||
if (auto displayWidget = qobject_cast<CardInfoPictureWithTextOverlayWidget *>(it.value())) {
|
// Un-highlight all copies of this card
|
||||||
|
for (auto widget : it.value()) {
|
||||||
|
if (auto displayWidget = qobject_cast<CardInfoPictureWithTextOverlayWidget *>(widget)) {
|
||||||
displayWidget->setHighlighted(false);
|
displayWidget->setHighlighted(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::clearAllDisplayWidgets()
|
|
||||||
{
|
|
||||||
for (auto idx : indexToWidgetMap.keys()) {
|
|
||||||
auto displayWidget = indexToWidgetMap.value(idx);
|
|
||||||
removeFromLayout(displayWidget);
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
delete displayWidget;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::refreshSelectionForIndex(const QPersistentModelIndex &persistent)
|
||||||
|
{
|
||||||
|
if (!selectionModel || !indexToWidgetMap.contains(persistent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert persistent index to regular index for selection check
|
||||||
|
QModelIndex idx = QModelIndex(persistent);
|
||||||
|
|
||||||
|
// Check if this index is selected
|
||||||
|
// We need to check against the selection model's model (which might be a proxy)
|
||||||
|
bool isSelected = false;
|
||||||
|
if (auto proxyModel = qobject_cast<QAbstractProxyModel *>(selectionModel->model())) {
|
||||||
|
// Map source index to proxy
|
||||||
|
QModelIndex proxyIdx = proxyModel->mapFromSource(idx);
|
||||||
|
isSelected = selectionModel->isSelected(proxyIdx);
|
||||||
|
} else {
|
||||||
|
isSelected = selectionModel->isSelected(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply selection state to all widgets for this index
|
||||||
|
for (auto widget : indexToWidgetMap[persistent]) {
|
||||||
|
if (auto displayWidget = qobject_cast<CardInfoPictureWithTextOverlayWidget *>(widget)) {
|
||||||
|
displayWidget->setHighlighted(isSelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// Display Widget Management
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
QWidget *CardGroupDisplayWidget::constructWidgetForIndex(QPersistentModelIndex index)
|
QWidget *CardGroupDisplayWidget::constructWidgetForIndex(QPersistentModelIndex index)
|
||||||
{
|
{
|
||||||
if (indexToWidgetMap.contains(index)) {
|
|
||||||
return indexToWidgetMap[index];
|
|
||||||
}
|
|
||||||
auto cardName = index.sibling(index.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
auto cardName = index.sibling(index.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
auto cardProviderId =
|
auto cardProviderId =
|
||||||
index.sibling(index.row(), DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::EditRole).toString();
|
index.sibling(index.row(), DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::EditRole).toString();
|
||||||
|
|
@ -103,7 +157,8 @@ QWidget *CardGroupDisplayWidget::constructWidgetForIndex(QPersistentModelIndex i
|
||||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &CardGroupDisplayWidget::onHover);
|
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &CardGroupDisplayWidget::onHover);
|
||||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget, &CardInfoPictureWidget::setScaleFactor);
|
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget, &CardInfoPictureWidget::setScaleFactor);
|
||||||
|
|
||||||
indexToWidgetMap.insert(index, widget);
|
indexToWidgetMap[index].append(widget);
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,10 +185,33 @@ void CardGroupDisplayWidget::updateCardDisplays()
|
||||||
// 4. persist the source index
|
// 4. persist the source index
|
||||||
QPersistentModelIndex persistent(sourceIndex);
|
QPersistentModelIndex persistent(sourceIndex);
|
||||||
|
|
||||||
|
// Get the card amount
|
||||||
|
int cardAmount =
|
||||||
|
sourceIndex.sibling(sourceIndex.row(), DeckListModelColumns::CARD_AMOUNT).data(Qt::EditRole).toInt();
|
||||||
|
|
||||||
|
// Create multiple widgets for the card count
|
||||||
|
for (int copy = 0; copy < cardAmount; ++copy) {
|
||||||
addToLayout(constructWidgetForIndex(persistent));
|
addToLayout(constructWidgetForIndex(persistent));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::clearAllDisplayWidgets()
|
||||||
|
{
|
||||||
|
auto it = indexToWidgetMap.begin();
|
||||||
|
while (it != indexToWidgetMap.end()) {
|
||||||
|
for (auto displayWidget : it.value()) {
|
||||||
|
removeFromLayout(displayWidget);
|
||||||
|
delete displayWidget;
|
||||||
|
}
|
||||||
|
it = indexToWidgetMap.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// DeckListModel Signal Responses
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onCardAddition(const QModelIndex &parent, int first, int last)
|
void CardGroupDisplayWidget::onCardAddition(const QModelIndex &parent, int first, int last)
|
||||||
{
|
{
|
||||||
if (!trackedIndex.isValid()) {
|
if (!trackedIndex.isValid()) {
|
||||||
|
|
@ -148,27 +226,126 @@ void CardGroupDisplayWidget::onCardAddition(const QModelIndex &parent, int first
|
||||||
// Persist the index
|
// Persist the index
|
||||||
QPersistentModelIndex persistent(child);
|
QPersistentModelIndex persistent(child);
|
||||||
|
|
||||||
|
// Get the card amount for the newly added card
|
||||||
|
int cardAmount = child.sibling(child.row(), DeckListModelColumns::CARD_AMOUNT).data(Qt::EditRole).toInt();
|
||||||
|
|
||||||
|
// Insert multiple copies
|
||||||
|
for (int copy = 0; copy < cardAmount; ++copy) {
|
||||||
insertIntoLayout(constructWidgetForIndex(persistent), row);
|
insertIntoLayout(constructWidgetForIndex(persistent), row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onCardRemoval(const QModelIndex &parent, int first, int last)
|
void CardGroupDisplayWidget::onCardRemoval(const QModelIndex &parent, int first, int last)
|
||||||
{
|
{
|
||||||
Q_UNUSED(first);
|
Q_UNUSED(first);
|
||||||
Q_UNUSED(last);
|
Q_UNUSED(last);
|
||||||
if (parent == trackedIndex) {
|
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
if (parent != trackedIndex) {
|
||||||
if (!idx.isValid()) {
|
return;
|
||||||
removeFromLayout(indexToWidgetMap.value(idx));
|
}
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
|
||||||
indexToWidgetMap.remove(idx);
|
// Use iterator so we can remove while iterating
|
||||||
|
auto it = indexToWidgetMap.begin();
|
||||||
|
while (it != indexToWidgetMap.end()) {
|
||||||
|
const QPersistentModelIndex &idx = it.key();
|
||||||
|
bool shouldRemove = !idx.isValid() || it.value().isEmpty();
|
||||||
|
|
||||||
|
if (shouldRemove) {
|
||||||
|
// Clean up widgets
|
||||||
|
for (auto widget : it.value()) {
|
||||||
|
removeFromLayout(widget);
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase and advance iterator
|
||||||
|
it = indexToWidgetMap.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!trackedIndex.isValid()) {
|
if (!trackedIndex.isValid()) {
|
||||||
emit cleanupRequested(this);
|
emit cleanupRequested(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::onDataChanged(const QModelIndex &topLeft,
|
||||||
|
const QModelIndex &bottomRight,
|
||||||
|
const QVector<int> &roles)
|
||||||
|
{
|
||||||
|
if (topLeft.parent() != trackedIndex && bottomRight.parent() != trackedIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if CARD_AMOUNT column changed
|
||||||
|
bool amountChanged = (topLeft.column() <= DeckListModelColumns::CARD_AMOUNT &&
|
||||||
|
bottomRight.column() >= DeckListModelColumns::CARD_AMOUNT) ||
|
||||||
|
roles.isEmpty() || roles.contains(Qt::EditRole);
|
||||||
|
|
||||||
|
if (!amountChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each affected row, adjust widget count
|
||||||
|
for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
|
||||||
|
QModelIndex idx = deckListModel->index(row, 0, trackedIndex);
|
||||||
|
|
||||||
|
if (!idx.isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPersistentModelIndex persistent(idx);
|
||||||
|
int newAmount = idx.sibling(idx.row(), DeckListModelColumns::CARD_AMOUNT).data(Qt::EditRole).toInt();
|
||||||
|
|
||||||
|
// Get current widget count
|
||||||
|
int currentWidgetCount = indexToWidgetMap.contains(persistent) ? indexToWidgetMap.value(persistent).count() : 0;
|
||||||
|
|
||||||
|
if (newAmount == currentWidgetCount) {
|
||||||
|
// Still refresh selection even if count didn't change
|
||||||
|
refreshSelectionForIndex(persistent);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newAmount < currentWidgetCount) {
|
||||||
|
// Remove excess widgets
|
||||||
|
int toRemove = currentWidgetCount - newAmount;
|
||||||
|
|
||||||
|
for (int i = 0; i < toRemove; ++i) {
|
||||||
|
if (!indexToWidgetMap[persistent].isEmpty()) {
|
||||||
|
QWidget *widget = indexToWidgetMap[persistent].takeLast();
|
||||||
|
removeFromLayout(widget);
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all widgets removed, clean up the map entry
|
||||||
|
if (indexToWidgetMap[persistent].isEmpty()) {
|
||||||
|
indexToWidgetMap.remove(persistent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int toAdd = newAmount - currentWidgetCount;
|
||||||
|
int insertBase = 0;
|
||||||
|
|
||||||
|
// Count widgets belonging to rows before this one
|
||||||
|
for (int r = 0; r < row; ++r) {
|
||||||
|
QModelIndex prevIdx = deckListModel->index(r, 0, trackedIndex);
|
||||||
|
QPersistentModelIndex prevPersistent(prevIdx);
|
||||||
|
|
||||||
|
if (indexToWidgetMap.contains(prevPersistent)) {
|
||||||
|
insertBase += indexToWidgetMap.value(prevPersistent).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert after existing copies of this card
|
||||||
|
for (int i = 0; i < toAdd; ++i) {
|
||||||
|
insertIntoLayout(constructWidgetForIndex(persistent), insertBase + currentWidgetCount + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always refresh selection state after modifying widgets
|
||||||
|
refreshSelectionForIndex(persistent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,26 +356,3 @@ void CardGroupDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSort
|
||||||
clearAllDisplayWidgets();
|
clearAllDisplayWidgets();
|
||||||
updateCardDisplays();
|
updateCardDisplays();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardGroupDisplayWidget::mousePressEvent(QMouseEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::mousePressEvent(event);
|
|
||||||
if (selectionModel) {
|
|
||||||
selectionModel->clearSelection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
|
||||||
{
|
|
||||||
emit cardClicked(event, card);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onHover(const ExactCard &card)
|
|
||||||
{
|
|
||||||
emit cardHovered(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
}
|
|
||||||
|
|
@ -33,12 +33,13 @@ public:
|
||||||
int bannerOpacity,
|
int bannerOpacity,
|
||||||
CardSizeWidget *cardSizeWidget);
|
CardSizeWidget *cardSizeWidget);
|
||||||
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||||
|
void refreshSelectionForIndex(const QPersistentModelIndex &persistent);
|
||||||
void clearAllDisplayWidgets();
|
void clearAllDisplayWidgets();
|
||||||
|
|
||||||
DeckListModel *deckListModel;
|
DeckListModel *deckListModel;
|
||||||
QItemSelectionModel *selectionModel;
|
QItemSelectionModel *selectionModel;
|
||||||
QPersistentModelIndex trackedIndex;
|
QPersistentModelIndex trackedIndex;
|
||||||
QHash<QPersistentModelIndex, QWidget *> indexToWidgetMap;
|
QMap<QPersistentModelIndex, QList<QWidget *>> indexToWidgetMap;
|
||||||
QString zoneName;
|
QString zoneName;
|
||||||
QString cardGroupCategory;
|
QString cardGroupCategory;
|
||||||
QString activeGroupCriteria;
|
QString activeGroupCriteria;
|
||||||
|
|
@ -53,6 +54,7 @@ public slots:
|
||||||
virtual void updateCardDisplays();
|
virtual void updateCardDisplays();
|
||||||
virtual void onCardAddition(const QModelIndex &parent, int first, int last);
|
virtual void onCardAddition(const QModelIndex &parent, int first, int last);
|
||||||
virtual void onCardRemoval(const QModelIndex &parent, int first, int last);
|
virtual void onCardRemoval(const QModelIndex &parent, int first, int last);
|
||||||
|
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
|
||||||
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
|
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,17 @@ FlatCardGroupDisplayWidget::FlatCardGroupDisplayWidget(QWidget *parent,
|
||||||
|
|
||||||
layout->addWidget(flowWidget);
|
layout->addWidget(flowWidget);
|
||||||
|
|
||||||
|
// Clear all existing widgets
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
||||||
FlatCardGroupDisplayWidget::removeFromLayout(indexToWidgetMap.value(idx));
|
for (auto widget : indexToWidgetMap.value(idx)) {
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
FlatCardGroupDisplayWidget::removeFromLayout(widget);
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
indexToWidgetMap.remove(idx);
|
indexToWidgetMap.remove(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatCardGroupDisplayWidget::updateCardDisplays();
|
FlatCardGroupDisplayWidget::updateCardDisplays();
|
||||||
|
|
||||||
disconnect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
disconnect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
||||||
disconnect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
disconnect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,12 @@ OverlappedCardGroupDisplayWidget::OverlappedCardGroupDisplayWidget(QWidget *pare
|
||||||
|
|
||||||
layout->addWidget(overlapWidget);
|
layout->addWidget(overlapWidget);
|
||||||
|
|
||||||
|
// Clear all existing widgets
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
||||||
OverlappedCardGroupDisplayWidget::removeFromLayout(indexToWidgetMap.value(idx));
|
for (auto widget : indexToWidgetMap.value(idx)) {
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
OverlappedCardGroupDisplayWidget::removeFromLayout(widget);
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
indexToWidgetMap.remove(idx);
|
indexToWidgetMap.remove(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
|
||||||
CardInfoDisplayWidget::CardInfoDisplayWidget(const CardRef &cardRef, QWidget *parent, Qt::WindowFlags flags)
|
CardInfoDisplayWidget::CardInfoDisplayWidget(const CardRef &cardRef, QWidget *parent, Qt::WindowFlags flags)
|
||||||
: QFrame(parent, flags), aspectRatio((qreal)CARD_HEIGHT / (qreal)CARD_WIDTH)
|
: QFrame(parent, flags), aspectRatio(CardDimensions::HEIGHT_F / CardDimensions::WIDTH_F)
|
||||||
{
|
{
|
||||||
setContentsMargins(3, 3, 3, 3);
|
setContentsMargins(3, 3, 3, 3);
|
||||||
pic = new CardInfoPictureWidget();
|
pic = new CardInfoPictureWidget();
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ CardInfoPictureArtCropWidget::CardInfoPictureArtCropWidget(QWidget *parent)
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &targetSize)
|
QPixmap CardInfoPictureArtCropWidget::getBackground()
|
||||||
{
|
{
|
||||||
// Load the full-resolution card image, not a pre-scaled one
|
// Load the full-resolution card image, not a pre-scaled one
|
||||||
QPixmap fullResPixmap;
|
QPixmap fullResPixmap;
|
||||||
|
|
@ -17,10 +17,8 @@ QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &target
|
||||||
} else {
|
} else {
|
||||||
CardPictureLoader::getCardBackPixmap(fullResPixmap, QSize(745, 1040));
|
CardPictureLoader::getCardBackPixmap(fullResPixmap, QSize(745, 1040));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail-safe if loading failed
|
|
||||||
if (fullResPixmap.isNull()) {
|
if (fullResPixmap.isNull()) {
|
||||||
return QPixmap(targetSize);
|
return QPixmap(); // return null qpixmap
|
||||||
}
|
}
|
||||||
|
|
||||||
const QSize sz = fullResPixmap.size();
|
const QSize sz = fullResPixmap.size();
|
||||||
|
|
@ -33,9 +31,7 @@ QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &target
|
||||||
|
|
||||||
foilRect = foilRect.intersected(fullResPixmap.rect()); // always clamp to source bounds
|
foilRect = foilRect.intersected(fullResPixmap.rect()); // always clamp to source bounds
|
||||||
|
|
||||||
// Crop first, then scale for best quality
|
// return full resolution image crop
|
||||||
QPixmap cropped = fullResPixmap.copy(foilRect);
|
QPixmap cropped = fullResPixmap.copy(foilRect);
|
||||||
QPixmap scaled = cropped.scaled(targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
return cropped;
|
||||||
|
|
||||||
return scaled;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ class CardInfoPictureArtCropWidget : public CardInfoPictureWidget
|
||||||
public:
|
public:
|
||||||
explicit CardInfoPictureArtCropWidget(QWidget *parent = nullptr);
|
explicit CardInfoPictureArtCropWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
// Returns a processed (cropped & scaled) version of the pixmap
|
// Returns a cropped version of the pixmap
|
||||||
QPixmap getProcessedBackground(const QSize &targetSize);
|
QPixmap getBackground();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CARD_INFO_PICTURE_ART_CROP_WIDGET_H
|
#endif // CARD_INFO_PICTURE_ART_CROP_WIDGET_H
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,18 @@
|
||||||
#include <libcockatrice/card/relation/card_relation.h>
|
#include <libcockatrice/card/relation/card_relation.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
static constexpr qreal MTG_CARD_ASPECT_RATIO = 1.396;
|
||||||
|
// static constexpr qreal YUGIOH_CARD_ASPECT_RATIO = 1.457;
|
||||||
|
static constexpr qreal ASPECT_RATIO = MTG_CARD_ASPECT_RATIO;
|
||||||
|
|
||||||
|
static constexpr int BASE_WIDTH = 200;
|
||||||
|
static constexpr int BASE_HEIGHT = 200;
|
||||||
|
|
||||||
|
static constexpr int ENLARGED_PIXMAP_OFFSET = 10;
|
||||||
|
|
||||||
|
static constexpr int HOVER_ACTIVATE_THRESHOLD_MS = 500;
|
||||||
|
static constexpr int ANIMATION_OFFSET = 10; // Adjust this for how much the widget moves up
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class CardInfoPictureWidget
|
* @class CardInfoPictureWidget
|
||||||
* @brief Widget that displays an enlarged image of a card, loading the image based on the card's info or showing a
|
* @brief Widget that displays an enlarged image of a card, loading the image based on the card's info or showing a
|
||||||
|
|
@ -34,7 +46,7 @@
|
||||||
CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverToZoomEnabled, const bool _raiseOnEnter)
|
CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverToZoomEnabled, const bool _raiseOnEnter)
|
||||||
: QWidget(parent), pixmapDirty(true), hoverToZoomEnabled(_hoverToZoomEnabled), raiseOnEnter(_raiseOnEnter)
|
: QWidget(parent), pixmapDirty(true), hoverToZoomEnabled(_hoverToZoomEnabled), raiseOnEnter(_raiseOnEnter)
|
||||||
{
|
{
|
||||||
setMinimumHeight(baseHeight);
|
setMinimumHeight(BASE_HEIGHT);
|
||||||
if (hoverToZoomEnabled) {
|
if (hoverToZoomEnabled) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
@ -47,12 +59,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverT
|
||||||
originalPos = this->pos();
|
originalPos = this->pos();
|
||||||
|
|
||||||
// Create the animation
|
// Create the animation
|
||||||
animation = new QPropertyAnimation(this, "pos");
|
animation = new QPropertyAnimation(this, "pos", this);
|
||||||
animation->setDuration(200); // 200ms animation duration
|
animation->setDuration(200); // 200ms animation duration
|
||||||
animation->setEasingCurve(QEasingCurve::OutQuad);
|
animation->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
|
||||||
animation->setStartValue(originalPos);
|
animation->setStartValue(originalPos);
|
||||||
animation->setEndValue(originalPos - QPoint(0, animationOffset));
|
animation->setEndValue(originalPos - QPoint(0, ANIMATION_OFFSET));
|
||||||
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
Q_UNUSED(_roundCardCorners);
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
@ -119,8 +131,8 @@ void CardInfoPictureWidget::resizeEvent(QResizeEvent *event)
|
||||||
*/
|
*/
|
||||||
void CardInfoPictureWidget::setScaleFactor(const int scale)
|
void CardInfoPictureWidget::setScaleFactor(const int scale)
|
||||||
{
|
{
|
||||||
const int newWidth = baseWidth * scale / 100;
|
const int newWidth = BASE_WIDTH * scale / 100;
|
||||||
const int newHeight = static_cast<int>(newWidth * aspectRatio);
|
const int newHeight = static_cast<int>(newWidth * ASPECT_RATIO);
|
||||||
|
|
||||||
scaleFactor = scale;
|
scaleFactor = scale;
|
||||||
|
|
||||||
|
|
@ -226,8 +238,8 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
|
||||||
*/
|
*/
|
||||||
QSize CardInfoPictureWidget::sizeHint() const
|
QSize CardInfoPictureWidget::sizeHint() const
|
||||||
{
|
{
|
||||||
return {static_cast<int>(baseWidth * scaleFactor / 100.0),
|
return {static_cast<int>(BASE_WIDTH * scaleFactor / 100.0),
|
||||||
static_cast<int>(baseWidth * scaleFactor / 100.0 * aspectRatio)};
|
static_cast<int>(BASE_WIDTH * scaleFactor / 100.0 * ASPECT_RATIO)};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -244,7 +256,7 @@ void CardInfoPictureWidget::enterEvent(QEvent *event)
|
||||||
|
|
||||||
// If hover-to-zoom is enabled, start the hover timer
|
// If hover-to-zoom is enabled, start the hover timer
|
||||||
if (hoverToZoomEnabled) {
|
if (hoverToZoomEnabled) {
|
||||||
hoverTimer->start(hoverActivateThresholdInMs);
|
hoverTimer->start(HOVER_ACTIVATE_THRESHOLD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit signal indicating a card is being hovered on
|
// Emit signal indicating a card is being hovered on
|
||||||
|
|
@ -256,7 +268,7 @@ void CardInfoPictureWidget::enterEvent(QEvent *event)
|
||||||
} else {
|
} else {
|
||||||
originalPos = this->pos(); // Update the baseline position
|
originalPos = this->pos(); // Update the baseline position
|
||||||
animation->setStartValue(originalPos);
|
animation->setStartValue(originalPos);
|
||||||
animation->setEndValue(originalPos - QPoint(0, animationOffset));
|
animation->setEndValue(originalPos - QPoint(0, ANIMATION_OFFSET));
|
||||||
}
|
}
|
||||||
animation->setDirection(QAbstractAnimation::Forward);
|
animation->setDirection(QAbstractAnimation::Forward);
|
||||||
animation->start();
|
animation->start();
|
||||||
|
|
@ -311,15 +323,15 @@ void CardInfoPictureWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
||||||
const QSize widgetSize = enlargedPixmapWidget->size();
|
const QSize widgetSize = enlargedPixmapWidget->size();
|
||||||
|
|
||||||
int newX = cursorPos.x() + enlargedPixmapOffset;
|
int newX = cursorPos.x() + ENLARGED_PIXMAP_OFFSET;
|
||||||
int newY = cursorPos.y() + enlargedPixmapOffset;
|
int newY = cursorPos.y() + ENLARGED_PIXMAP_OFFSET;
|
||||||
|
|
||||||
// Adjust if out of bounds
|
// Adjust if out of bounds
|
||||||
if (newX + widgetSize.width() > screenGeometry.right()) {
|
if (newX + widgetSize.width() > screenGeometry.right()) {
|
||||||
newX = cursorPos.x() - widgetSize.width() - enlargedPixmapOffset;
|
newX = cursorPos.x() - widgetSize.width() - ENLARGED_PIXMAP_OFFSET;
|
||||||
}
|
}
|
||||||
if (newY + widgetSize.height() > screenGeometry.bottom()) {
|
if (newY + widgetSize.height() > screenGeometry.bottom()) {
|
||||||
newY = cursorPos.y() - widgetSize.height() - enlargedPixmapOffset;
|
newY = cursorPos.y() - widgetSize.height() - ENLARGED_PIXMAP_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
enlargedPixmapWidget->move(newX, newY);
|
enlargedPixmapWidget->move(newX, newY);
|
||||||
|
|
@ -453,21 +465,21 @@ void CardInfoPictureWidget::showEnlargedPixmap()
|
||||||
connect(this, &QObject::destroyed, enlargedPixmapWidget, &CardInfoPictureEnlargedWidget::deleteLater);
|
connect(this, &QObject::destroyed, enlargedPixmapWidget, &CardInfoPictureEnlargedWidget::deleteLater);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QSize enlargedSize(static_cast<int>(size().width() * 2), static_cast<int>(size().width() * aspectRatio * 2));
|
const QSize enlargedSize(static_cast<int>(size().width() * 2), static_cast<int>(size().width() * ASPECT_RATIO * 2));
|
||||||
enlargedPixmapWidget->setCardPixmap(exactCard, enlargedSize);
|
enlargedPixmapWidget->setCardPixmap(exactCard, enlargedSize);
|
||||||
|
|
||||||
const QPoint cursorPos = QCursor::pos();
|
const QPoint cursorPos = QCursor::pos();
|
||||||
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
||||||
const QSize widgetSize = enlargedPixmapWidget->size();
|
const QSize widgetSize = enlargedPixmapWidget->size();
|
||||||
|
|
||||||
int newX = cursorPos.x() + enlargedPixmapOffset;
|
int newX = cursorPos.x() + ENLARGED_PIXMAP_OFFSET;
|
||||||
int newY = cursorPos.y() + enlargedPixmapOffset;
|
int newY = cursorPos.y() + ENLARGED_PIXMAP_OFFSET;
|
||||||
|
|
||||||
if (newX + widgetSize.width() > screenGeometry.right()) {
|
if (newX + widgetSize.width() > screenGeometry.right()) {
|
||||||
newX = cursorPos.x() - widgetSize.width() - enlargedPixmapOffset;
|
newX = cursorPos.x() - widgetSize.width() - ENLARGED_PIXMAP_OFFSET;
|
||||||
}
|
}
|
||||||
if (newY + widgetSize.height() > screenGeometry.bottom()) {
|
if (newY + widgetSize.height() > screenGeometry.bottom()) {
|
||||||
newY = cursorPos.y() - widgetSize.height() - enlargedPixmapOffset;
|
newY = cursorPos.y() - widgetSize.height() - ENLARGED_PIXMAP_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
enlargedPixmapWidget->move(newX, newY);
|
enlargedPixmapWidget->move(newX, newY);
|
||||||
|
|
|
||||||
|
|
@ -68,23 +68,17 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ExactCard exactCard;
|
ExactCard exactCard;
|
||||||
qreal magicTheGatheringCardAspectRatio = 1.396;
|
|
||||||
qreal yuGiOhCardAspectRatio = 1.457;
|
|
||||||
qreal aspectRatio = magicTheGatheringCardAspectRatio;
|
|
||||||
int baseWidth = 200;
|
|
||||||
int baseHeight = 200;
|
|
||||||
double scaleFactor = 100;
|
double scaleFactor = 100;
|
||||||
QPixmap resizedPixmap;
|
QPixmap resizedPixmap;
|
||||||
bool pixmapDirty;
|
bool pixmapDirty;
|
||||||
bool hoverToZoomEnabled;
|
bool hoverToZoomEnabled;
|
||||||
bool raiseOnEnter;
|
bool raiseOnEnter;
|
||||||
int hoverActivateThresholdInMs = 500;
|
|
||||||
CardInfoPictureEnlargedWidget *enlargedPixmapWidget = nullptr;
|
CardInfoPictureEnlargedWidget *enlargedPixmapWidget = nullptr;
|
||||||
int enlargedPixmapOffset = 10;
|
|
||||||
QTimer *hoverTimer;
|
QTimer *hoverTimer;
|
||||||
QPropertyAnimation *animation;
|
QPropertyAnimation *animation;
|
||||||
QPoint originalPos; // Store the original position
|
QPoint originalPos; // Store the original position
|
||||||
const int animationOffset = 10; // Adjust this for how much the widget moves up
|
|
||||||
|
|
||||||
QMenu *createRightClickMenu();
|
QMenu *createRightClickMenu();
|
||||||
QMenu *createViewRelatedCardsMenu();
|
QMenu *createViewRelatedCardsMenu();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "card_group_display_widgets/flat_card_group_display_widget.h"
|
#include "card_group_display_widgets/flat_card_group_display_widget.h"
|
||||||
#include "card_group_display_widgets/overlapped_card_group_display_widget.h"
|
#include "card_group_display_widgets/overlapped_card_group_display_widget.h"
|
||||||
|
#include "libcockatrice/card/database/card_database_manager.h"
|
||||||
|
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
||||||
|
|
@ -22,6 +23,7 @@ DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
|
||||||
displayType(_displayType), bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity),
|
displayType(_displayType), bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity),
|
||||||
cardSizeWidget(_cardSizeWidget)
|
cardSizeWidget(_cardSizeWidget)
|
||||||
{
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QVBoxLayout(this);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
|
|
@ -45,6 +47,20 @@ DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &DeckCardZoneDisplayWidget::onCategoryRemoval);
|
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &DeckCardZoneDisplayWidget::onCategoryRemoval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// User Interaction
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, card, zoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::onHover(const ExactCard &card)
|
||||||
|
{
|
||||||
|
emit cardHovered(card);
|
||||||
|
}
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
void DeckCardZoneDisplayWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
||||||
{
|
{
|
||||||
for (auto &range : selected) {
|
for (auto &range : selected) {
|
||||||
|
|
@ -68,17 +84,9 @@ void DeckCardZoneDisplayWidget::onSelectionChanged(const QItemSelection &selecte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget)
|
// =====================================================================================================================
|
||||||
{
|
// Display Widget Management
|
||||||
cardGroupLayout->removeWidget(displayWidget);
|
// =====================================================================================================================
|
||||||
displayWidget->setParent(nullptr);
|
|
||||||
for (auto idx : indexToWidgetMap.keys()) {
|
|
||||||
if (!idx.isValid()) {
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete displayWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex index)
|
void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex index)
|
||||||
{
|
{
|
||||||
|
|
@ -140,6 +148,45 @@ void DeckCardZoneDisplayWidget::displayCards()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::refreshDisplayType(const DisplayType &_displayType)
|
||||||
|
{
|
||||||
|
displayType = _displayType;
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = cardGroupLayout->takeAt(0)) != nullptr) {
|
||||||
|
if (item->widget()) {
|
||||||
|
item->widget()->deleteLater();
|
||||||
|
} else if (item->layout()) {
|
||||||
|
item->layout()->deleteLater();
|
||||||
|
}
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexToWidgetMap.clear();
|
||||||
|
|
||||||
|
// We gotta wait for all the deleteLater's to finish so we fire after the next event cycle
|
||||||
|
|
||||||
|
auto timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, this, [this]() { displayCards(); });
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget)
|
||||||
|
{
|
||||||
|
cardGroupLayout->removeWidget(displayWidget);
|
||||||
|
displayWidget->setParent(nullptr);
|
||||||
|
for (auto idx : indexToWidgetMap.keys()) {
|
||||||
|
if (!idx.isValid()) {
|
||||||
|
indexToWidgetMap.remove(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete displayWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// DeckListModel Signal Responses
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::onCategoryAddition(const QModelIndex &parent, int first, int last)
|
void DeckCardZoneDisplayWidget::onCategoryAddition(const QModelIndex &parent, int first, int last)
|
||||||
{
|
{
|
||||||
if (!trackedIndex.isValid()) {
|
if (!trackedIndex.isValid()) {
|
||||||
|
|
@ -172,48 +219,6 @@ void DeckCardZoneDisplayWidget::onCategoryRemoval(const QModelIndex &parent, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
for (QObject *child : layout->children()) {
|
|
||||||
QWidget *widget = qobject_cast<QWidget *>(child);
|
|
||||||
if (widget) {
|
|
||||||
widget->setMaximumWidth(width());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
|
||||||
{
|
|
||||||
emit cardClicked(event, card, zoneName);
|
|
||||||
}
|
|
||||||
void DeckCardZoneDisplayWidget::onHover(const ExactCard &card)
|
|
||||||
{
|
|
||||||
emit cardHovered(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::refreshDisplayType(const DisplayType &_displayType)
|
|
||||||
{
|
|
||||||
displayType = _displayType;
|
|
||||||
QLayoutItem *item;
|
|
||||||
while ((item = cardGroupLayout->takeAt(0)) != nullptr) {
|
|
||||||
if (item->widget()) {
|
|
||||||
item->widget()->deleteLater();
|
|
||||||
} else if (item->layout()) {
|
|
||||||
item->layout()->deleteLater();
|
|
||||||
}
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
indexToWidgetMap.clear();
|
|
||||||
|
|
||||||
// We gotta wait for all the deleteLater's to finish so we fire after the next event cycle
|
|
||||||
|
|
||||||
auto timer = new QTimer(this);
|
|
||||||
timer->setSingleShot(true);
|
|
||||||
connect(timer, &QTimer::timeout, this, [this]() { displayCards(); });
|
|
||||||
timer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged(QString _activeGroupCriteria)
|
void DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged(QString _activeGroupCriteria)
|
||||||
{
|
{
|
||||||
activeGroupCriteria = _activeGroupCriteria;
|
activeGroupCriteria = _activeGroupCriteria;
|
||||||
|
|
@ -230,10 +235,13 @@ QList<QString> DeckCardZoneDisplayWidget::getGroupCriteriaValueList()
|
||||||
{
|
{
|
||||||
QList<QString> groupCriteriaValues;
|
QList<QString> groupCriteriaValues;
|
||||||
|
|
||||||
QList<ExactCard> cardsInZone = deckListModel->getCardsForZone(zoneName);
|
QList<const DecklistCardNode *> nodes = deckListModel->getCardNodesForZone(zoneName);
|
||||||
|
|
||||||
for (const ExactCard &cardInZone : cardsInZone) {
|
for (auto node : nodes) {
|
||||||
groupCriteriaValues.append(cardInZone.getInfo().getProperty(activeGroupCriteria));
|
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||||
|
if (info) {
|
||||||
|
groupCriteriaValues.append(info->getProperty(activeGroupCriteria));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
groupCriteriaValues.removeDuplicates();
|
groupCriteriaValues.removeDuplicates();
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ public:
|
||||||
QPersistentModelIndex trackedIndex;
|
QPersistentModelIndex trackedIndex;
|
||||||
QString zoneName;
|
QString zoneName;
|
||||||
void addCardsToOverlapWidget();
|
void addCardsToOverlapWidget();
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ AbstractAnalyticsPanelWidget::AbstractAnalyticsPanelWidget(QWidget *parent, Deck
|
||||||
bannerAndSettingsLayout->addWidget(bannerWidget, 1);
|
bannerAndSettingsLayout->addWidget(bannerWidget, 1);
|
||||||
|
|
||||||
// config button
|
// config button
|
||||||
configureButton = new QPushButton(tr("Configure"), this);
|
configureButton = new QPushButton(this);
|
||||||
|
configureButton->setIcon(QPixmap("theme:icons/cogwheel"));
|
||||||
configureButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
configureButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
connect(configureButton, &QPushButton::clicked, this, &AbstractAnalyticsPanelWidget::applyConfigFromDialog);
|
connect(configureButton, &QPushButton::clicked, this, &AbstractAnalyticsPanelWidget::applyConfigFromDialog);
|
||||||
bannerAndSettingsLayout->addWidget(configureButton, 0);
|
bannerAndSettingsLayout->addWidget(configureButton, 0);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ DrawProbabilityWidget::DrawProbabilityWidget(QWidget *parent, DeckListStatistics
|
||||||
{
|
{
|
||||||
controls = new QWidget(this);
|
controls = new QWidget(this);
|
||||||
controlLayout = new QHBoxLayout(controls);
|
controlLayout = new QHBoxLayout(controls);
|
||||||
|
controlLayout->setContentsMargins(11, 0, 11, 0);
|
||||||
|
|
||||||
labelPrefix = new QLabel(this);
|
labelPrefix = new QLabel(this);
|
||||||
controlLayout->addWidget(labelPrefix);
|
controlLayout->addWidget(labelPrefix);
|
||||||
|
|
@ -65,6 +66,7 @@ DrawProbabilityWidget::DrawProbabilityWidget(QWidget *parent, DeckListStatistics
|
||||||
resultTable = new QTableWidget(this);
|
resultTable = new QTableWidget(this);
|
||||||
resultTable->setColumnCount(3);
|
resultTable->setColumnCount(3);
|
||||||
resultTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
resultTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
|
resultTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
layout->addWidget(resultTable);
|
layout->addWidget(resultTable);
|
||||||
|
|
||||||
// Connections
|
// Connections
|
||||||
|
|
@ -168,9 +170,9 @@ void DrawProbabilityWidget::updateFilterOptions()
|
||||||
QMap<QString, int> categoryCounts;
|
QMap<QString, int> categoryCounts;
|
||||||
int totalDeckCards = 0;
|
int totalDeckCards = 0;
|
||||||
|
|
||||||
const auto nodes = analyzer->getModel()->getDeckList()->getCardNodes();
|
const auto nodes = analyzer->getModel()->getCardNodes();
|
||||||
for (auto *node : nodes) {
|
for (auto *node : nodes) {
|
||||||
CardInfoPtr info = CardDatabaseManager::query()->getCard({node->getName()}).getCardPtr();
|
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||||
if (!info) {
|
if (!info) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
#include <libcockatrice/utility/color.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
@ -71,14 +72,16 @@ void ManaBaseWidget::updateDisplay()
|
||||||
|
|
||||||
// Choose display mode
|
// Choose display mode
|
||||||
if (config.displayType == "bar") {
|
if (config.displayType == "bar") {
|
||||||
QHash<QString, QColor> colors = {{"W", QColor(248, 231, 185)}, {"U", QColor(14, 104, 171)},
|
const QList<QPair<QString, int>> sortedColors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(mapSorted);
|
||||||
{"B", QColor(21, 11, 0)}, {"R", QColor(211, 32, 42)},
|
static const QHash<QString, QColor> colorMap = {
|
||||||
{"G", QColor(0, 115, 62)}, {"C", QColor(150, 150, 150)}};
|
{"W", QColor(248, 231, 185)}, {"U", QColor(14, 104, 171)}, {"B", QColor(21, 11, 0)},
|
||||||
|
{"R", QColor(211, 32, 42)}, {"G", QColor(0, 115, 62)}, {"C", QColor(150, 150, 150)},
|
||||||
|
};
|
||||||
|
|
||||||
for (auto color : manaMap.keys()) {
|
for (const auto &[color, count] : sortedColors) {
|
||||||
QString label = QString("%1 %2 (%3)").arg(color).arg(manaMap[color]).arg(cardCount.value(color));
|
QString label = QString("%1 %2 (%3)").arg(color).arg(count).arg(cardCount.value(color));
|
||||||
|
|
||||||
BarWidget *bar = new BarWidget(label, manaMap[color], highest, colors.value(color, Qt::gray), this);
|
BarWidget *bar = new BarWidget(label, count, highest, colorMap.value(color, Qt::gray), this);
|
||||||
|
|
||||||
barLayout->addWidget(bar);
|
barLayout->addWidget(bar);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,89 +12,98 @@ DeckListStatisticsAnalyzer::DeckListStatisticsAnalyzer(QObject *parent,
|
||||||
DeckListStatisticsAnalyzerConfig _config)
|
DeckListStatisticsAnalyzerConfig _config)
|
||||||
: QObject(parent), model(_model), config(_config)
|
: QObject(parent), model(_model), config(_config)
|
||||||
{
|
{
|
||||||
connect(model, &DeckListModel::dataChanged, this, &DeckListStatisticsAnalyzer::analyze);
|
connect(model, &DeckListModel::cardsChanged, this, &DeckListStatisticsAnalyzer::analyze);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckListStatisticsAnalyzer::analyze()
|
void DeckListStatisticsAnalyzer::analyze()
|
||||||
{
|
{
|
||||||
clearData();
|
clearData();
|
||||||
|
|
||||||
QList<ExactCard> cards = model->getCards();
|
QList<const DecklistCardNode *> nodes = model->getCardNodes();
|
||||||
|
|
||||||
for (auto card : cards) {
|
for (auto node : nodes) {
|
||||||
auto info = card.getInfo();
|
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||||
const int cmc = info.getCmc().toInt();
|
if (!info) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int amount = node->getNumber();
|
||||||
|
QStringList copiesOfName;
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
copiesOfName.append(node->getName());
|
||||||
|
}
|
||||||
|
|
||||||
// Convert once
|
// Convert once
|
||||||
QStringList types = info.getMainCardType().split(' ');
|
const int cmc = info->getCmc().toInt();
|
||||||
QStringList subtypes = info.getCardType().split('-').last().split(" ");
|
QStringList types = info->getMainCardType().split(' ');
|
||||||
QString colors = info.getColors();
|
QStringList subtypes = info->getCardType().split('-').last().split(" ");
|
||||||
int power = info.getPowTough().split("/").first().toInt();
|
QString colors = info->getColors();
|
||||||
int toughness = info.getPowTough().split("/").last().toInt();
|
int power = info->getPowTough().split("/").first().toInt();
|
||||||
|
int toughness = info->getPowTough().split("/").last().toInt();
|
||||||
|
|
||||||
// For each copy of card
|
// For each copy of card
|
||||||
// ---------------- Mana Curve ----------------
|
// ---------------- Mana Curve ----------------
|
||||||
if (config.computeManaCurve) {
|
if (config.computeManaCurve) {
|
||||||
manaCurveMap[cmc]++;
|
manaCurveMap[cmc] += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// per-type curve
|
// per-type curve
|
||||||
for (auto &t : types) {
|
for (auto &t : types) {
|
||||||
manaCurveByType[t][cmc]++;
|
manaCurveByType[t][cmc] += amount;
|
||||||
manaCurveCardsByType[t][cmc].append(info.getName());
|
manaCurveCardsByType[t][cmc] << copiesOfName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-subtype curve
|
// Per-subtype curve
|
||||||
for (auto &st : subtypes) {
|
for (auto &st : subtypes) {
|
||||||
manaCurveBySubtype[st][cmc]++;
|
manaCurveBySubtype[st][cmc] += amount;
|
||||||
manaCurveCardsBySubtype[st][cmc].append(info.getName());
|
manaCurveCardsBySubtype[st][cmc] << copiesOfName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// per-color curve
|
// per-color curve
|
||||||
for (auto &c : colors) {
|
for (auto &c : colors) {
|
||||||
manaCurveByColor[c][cmc]++;
|
manaCurveByColor[c][cmc] += amount;
|
||||||
manaCurveCardsByColor[c][cmc].append(info.getName());
|
manaCurveCardsByColor[c][cmc] << copiesOfName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Power/toughness
|
// Power/toughness
|
||||||
manaCurveByPower[QString::number(power)][cmc]++;
|
manaCurveByPower[QString::number(power)][cmc] += amount;
|
||||||
manaCurveCardsByPower[QString::number(power)][cmc].append(info.getName());
|
manaCurveCardsByPower[QString::number(power)][cmc] << copiesOfName;
|
||||||
manaCurveByToughness[QString::number(toughness)][cmc]++;
|
manaCurveByToughness[QString::number(toughness)][cmc] += amount;
|
||||||
manaCurveCardsByToughness[QString::number(toughness)][cmc].append(info.getName());
|
manaCurveCardsByToughness[QString::number(toughness)][cmc] << copiesOfName;
|
||||||
|
|
||||||
// ========== Category Counts ===========
|
// ========== Category Counts ===========
|
||||||
for (auto &t : types) {
|
for (auto &t : types) {
|
||||||
typeCount[t]++;
|
typeCount[t] += amount;
|
||||||
}
|
}
|
||||||
for (auto &st : subtypes) {
|
for (auto &st : subtypes) {
|
||||||
subtypeCount[st]++;
|
subtypeCount[st] += amount;
|
||||||
}
|
}
|
||||||
for (auto &c : colors) {
|
for (auto &c : colors) {
|
||||||
colorCount[c]++;
|
colorCount[c] += amount;
|
||||||
}
|
}
|
||||||
manaValueCount[cmc]++;
|
manaValueCount[cmc] += amount;
|
||||||
|
|
||||||
// ---------------- Mana Base ----------------
|
// ---------------- Mana Base ----------------
|
||||||
if (config.computeManaBase) {
|
if (config.computeManaBase) {
|
||||||
auto prod = determineManaProduction(info.getText());
|
auto prod = determineManaProduction(info->getText());
|
||||||
for (auto it = prod.begin(); it != prod.end(); ++it) {
|
for (auto it = prod.begin(); it != prod.end(); ++it) {
|
||||||
if (it.value() > 0) {
|
if (it.value() > 0) {
|
||||||
productionPipCount[it.key()] += it.value();
|
productionPipCount[it.key()] += it.value() * amount;
|
||||||
productionCardCount[it.key()]++;
|
productionCardCount[it.key()] += amount;
|
||||||
}
|
}
|
||||||
manaBaseMap[it.key()] += it.value();
|
manaBaseMap[it.key()] += it.value() * amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- Devotion ----------------
|
// ---------------- Devotion ----------------
|
||||||
if (config.computeDevotion) {
|
if (config.computeDevotion) {
|
||||||
auto devo = countManaSymbols(info.getManaCost());
|
auto devo = countManaSymbols(info->getManaCost());
|
||||||
for (auto &d : devo) {
|
for (auto &d : devo) {
|
||||||
if (d.second > 0) {
|
if (d.second > 0) {
|
||||||
devotionPipCount[QString(d.first)] += d.second;
|
devotionPipCount[QString(d.first)] += d.second * amount;
|
||||||
devotionCardCount[QString(d.first)]++;
|
devotionCardCount[QString(d.first)] += amount;
|
||||||
}
|
}
|
||||||
manaDevotionMap[d.first] += d.second;
|
manaDevotionMap[d.first] += d.second * amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include "deck_editor_card_database_dock_widget.h"
|
||||||
|
|
||||||
|
DeckEditorCardDatabaseDockWidget::DeckEditorCardDatabaseDockWidget(AbstractTabDeckEditor *parent) : QDockWidget(parent)
|
||||||
|
{
|
||||||
|
setObjectName("databaseDisplayDock");
|
||||||
|
setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||||
|
setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
||||||
|
|
||||||
|
createDatabaseDisplayDock(parent);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorCardDatabaseDockWidget::createDatabaseDisplayDock(AbstractTabDeckEditor *deckEditor)
|
||||||
|
{
|
||||||
|
databaseDisplayWidget = new DeckEditorDatabaseDisplayWidget(this, deckEditor);
|
||||||
|
|
||||||
|
auto *frame = new QVBoxLayout;
|
||||||
|
frame->setObjectName("databaseDisplayFrame");
|
||||||
|
frame->addWidget(databaseDisplayWidget);
|
||||||
|
|
||||||
|
auto *dockContents = new QWidget();
|
||||||
|
dockContents->setObjectName("databaseDisplayDockContents");
|
||||||
|
dockContents->setLayout(frame);
|
||||||
|
setWidget(dockContents);
|
||||||
|
|
||||||
|
installEventFilter(deckEditor);
|
||||||
|
|
||||||
|
// connect signals
|
||||||
|
connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, deckEditor,
|
||||||
|
&AbstractTabDeckEditor::updateCard);
|
||||||
|
connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::addCardToMainDeck, deckEditor,
|
||||||
|
&AbstractTabDeckEditor::actAddCard);
|
||||||
|
connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::addCardToSideboard, deckEditor,
|
||||||
|
&AbstractTabDeckEditor::actAddCardToSideboard);
|
||||||
|
connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::decrementCardFromMainDeck, deckEditor,
|
||||||
|
&AbstractTabDeckEditor::actDecrementCard);
|
||||||
|
connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::decrementCardFromSideboard, deckEditor,
|
||||||
|
&AbstractTabDeckEditor::actDecrementCardFromSideboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
CardDatabase *DeckEditorCardDatabaseDockWidget::getDatabase() const
|
||||||
|
{
|
||||||
|
return databaseDisplayWidget->databaseModel->getDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorCardDatabaseDockWidget::retranslateUi()
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Card Database"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorCardDatabaseDockWidget::setFilterTree(FilterTree *filterTree)
|
||||||
|
{
|
||||||
|
databaseDisplayWidget->setFilterTree(filterTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorCardDatabaseDockWidget::clearAllDatabaseFilters()
|
||||||
|
{
|
||||||
|
databaseDisplayWidget->clearAllDatabaseFilters();
|
||||||
|
}
|
||||||
|
void DeckEditorCardDatabaseDockWidget::highlightAllSearchEdit()
|
||||||
|
{
|
||||||
|
databaseDisplayWidget->searchEdit->setSelection(0, databaseDisplayWidget->searchEdit->text().length());
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef COCKATRICE_DECK_EDITOR_CARD_DATABASE_DOCK_WIDGET_H
|
||||||
|
#define COCKATRICE_DECK_EDITOR_CARD_DATABASE_DOCK_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
|
||||||
|
|
||||||
|
#include <QDockWidget>
|
||||||
|
|
||||||
|
class AbstractTabDeckEditor;
|
||||||
|
class CardDatabase;
|
||||||
|
class DeckEditorDatabaseDisplayWidget;
|
||||||
|
class FilterTree;
|
||||||
|
|
||||||
|
class DeckEditorCardDatabaseDockWidget : public QDockWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DeckEditorCardDatabaseDockWidget(AbstractTabDeckEditor *parent);
|
||||||
|
|
||||||
|
DeckEditorDatabaseDisplayWidget *databaseDisplayWidget;
|
||||||
|
|
||||||
|
CardDatabase *getDatabase() const;
|
||||||
|
void setFilterTree(FilterTree *filterTree);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void retranslateUi();
|
||||||
|
void clearAllDatabaseFilters();
|
||||||
|
void highlightAllSearchEdit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createDatabaseDisplayDock(AbstractTabDeckEditor *deckEditor);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_DECK_EDITOR_CARD_DATABASE_DOCK_WIDGET_H
|
||||||