Compare commits
306 Commits
2025-06-23
...
tooomm-dox
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
067d9797be | ||
|
|
d6db21419c | ||
|
|
367507e054 | ||
|
|
715ee1d6fe | ||
|
|
ad06a81765 | ||
|
|
ebb02b27b2 | ||
|
|
d47dc35885 | ||
|
|
41aca8467a | ||
|
|
cd44392866 | ||
|
|
64bb5355ff | ||
|
|
1198db8891 | ||
|
|
9471adb4f7 | ||
|
|
b29909bdbe | ||
|
|
589e9a15a6 | ||
|
|
c218a66bcd | ||
|
|
8485bbe575 | ||
|
|
5d9d7d3aa5 | ||
|
|
ccdda39e78 | ||
|
|
2e2682aad4 | ||
|
|
a390c8ada7 | ||
|
|
da70344547 | ||
|
|
2b690f8c87 | ||
|
|
c8b419888a | ||
|
|
d3302d521f | ||
|
|
5c1bb27d5c | ||
|
|
dde36183ce | ||
|
|
7c7f2dd8d5 | ||
|
|
edb0a954e2 | ||
|
|
0a239712dd | ||
|
|
95c3434205 | ||
|
|
f0be6972cc | ||
|
|
a799cd097a | ||
|
|
b4e3f2cba9 | ||
|
|
658ae83157 | ||
|
|
d29e72ce72 | ||
|
|
30cc8ad6f9 | ||
|
|
f0ebd28148 | ||
|
|
364d0ca52b | ||
|
|
3ff2df2796 | ||
|
|
d57bec8ec6 | ||
|
|
2b64e65f45 | ||
|
|
eab4d435f8 | ||
|
|
de13c22552 | ||
|
|
8ee7163014 | ||
|
|
c5fde071e7 | ||
|
|
8abd04dab1 | ||
|
|
858361e6d3 | ||
|
|
9ece4bfd9b | ||
|
|
a1a3b02d3a | ||
|
|
bc2ae6c486 | ||
|
|
587a8bc524 | ||
|
|
122926c6cd | ||
|
|
bac6beeb50 | ||
|
|
c75a483ee6 | ||
|
|
1c5bfdbabe | ||
|
|
553952132f | ||
|
|
1931eb11a9 | ||
|
|
65aef396fb | ||
|
|
a21e45ed36 | ||
|
|
adee67115c | ||
|
|
aea468bc7f | ||
|
|
621c6a8d73 | ||
|
|
73591d5d0f | ||
|
|
846f16ddaa | ||
|
|
c46f6d1178 | ||
|
|
ab5d6db8a2 | ||
|
|
9957cb20e2 | ||
|
|
8788a7aada | ||
|
|
16392c28c5 | ||
|
|
a8ee0d7648 | ||
|
|
a405758222 | ||
|
|
537e29d937 | ||
|
|
9a3104c5ac | ||
|
|
722344967f | ||
|
|
73ce5e051c | ||
|
|
b8bbe141a0 | ||
|
|
3285596a93 | ||
|
|
73763b5ee6 | ||
|
|
27708d5964 | ||
|
|
827f22ed37 | ||
|
|
ace4063371 | ||
|
|
f62e29f5d5 | ||
|
|
5df00de246 | ||
|
|
28dfd62163 | ||
|
|
1c1599a9f4 | ||
|
|
6dff230e10 | ||
|
|
0f60824749 | ||
|
|
84e0732fb1 | ||
|
|
ae123587d7 | ||
|
|
2efcb48b7e | ||
|
|
3d9cae717d | ||
|
|
cc73a8cc85 | ||
|
|
648f028a63 | ||
|
|
840ee1379f | ||
|
|
3c85ca9cbc | ||
|
|
8e88749078 | ||
|
|
4c431e98a6 | ||
|
|
40cf3ced1a | ||
|
|
c9ccab8771 | ||
|
|
7d2700ca65 | ||
|
|
bfedc12fa8 | ||
|
|
c16267e60f | ||
|
|
0bd9b84931 | ||
|
|
e9a9475ed7 | ||
|
|
f00d415dd7 | ||
|
|
1e7ff3dbdf | ||
|
|
eb1c257484 | ||
|
|
4d652210dc | ||
|
|
9f2ac78609 | ||
|
|
484e8e64a6 | ||
|
|
e5d5dfa8d8 | ||
|
|
0ad31fea46 | ||
|
|
ec2d8f231d | ||
|
|
aeec56f800 | ||
|
|
7e6cad974f | ||
|
|
757e9f3415 | ||
|
|
6bc2293292 | ||
|
|
55aaca0e0d | ||
|
|
a8a3fca8c9 | ||
|
|
fb30515f72 | ||
|
|
9a39af6da0 | ||
|
|
6d75ce4b1c | ||
|
|
dbd1d30ca8 | ||
|
|
8f80996515 | ||
|
|
d206a70b8a | ||
|
|
bbec4d2c7e | ||
|
|
f24c36d6b1 | ||
|
|
adff828415 | ||
|
|
d914667238 | ||
|
|
1c209b3320 | ||
|
|
aa61032cdf | ||
|
|
3ae4a7d8a7 | ||
|
|
9fdecf21f2 | ||
|
|
e4d256790f | ||
|
|
d9f4faf4ec | ||
|
|
609a364971 | ||
|
|
2152ddd99b | ||
|
|
8caaf8515e | ||
|
|
ac822fa084 | ||
|
|
a265b865f6 | ||
|
|
8efc4f4817 | ||
|
|
817a3f979e | ||
|
|
8ebfc40de5 | ||
|
|
c42e953199 | ||
|
|
636aa72141 | ||
|
|
14e6e6eff4 | ||
|
|
474c1d0d89 | ||
|
|
b8983f27ab | ||
|
|
d9c65d4ae0 | ||
|
|
1ef07309d6 | ||
|
|
be1403c920 | ||
|
|
03e32f0a7c | ||
|
|
f4361d1b43 | ||
|
|
e1259e67d3 | ||
|
|
ca1b9bf75f | ||
|
|
3cff55b0bb | ||
|
|
c25b153185 | ||
|
|
9c58e6f90f | ||
|
|
cff16346ef | ||
|
|
30e6b52783 | ||
|
|
015570c833 | ||
|
|
7c31197b78 | ||
|
|
a69bfb8cb8 | ||
|
|
c5b361e94d | ||
|
|
201750c89f | ||
|
|
89a8d0f6b8 | ||
|
|
835e4af3e4 | ||
|
|
c33106eab4 | ||
|
|
bea8c3dbec | ||
|
|
b51d5d007b | ||
|
|
f8c4f774cf | ||
|
|
22c6756ce0 | ||
|
|
e318815025 | ||
|
|
0833f94502 | ||
|
|
ddbf5e1457 | ||
|
|
2a032f3116 | ||
|
|
5381562a5e | ||
|
|
f2ce5e9693 | ||
|
|
ed50fd98cd | ||
|
|
14991e1f9e | ||
|
|
5fa06746f1 | ||
|
|
d31b044529 | ||
|
|
754dd904d2 | ||
|
|
1503394662 | ||
|
|
436d69b710 | ||
|
|
891e7bf6e4 | ||
|
|
fad1280185 | ||
|
|
6187c7268f | ||
|
|
762ea47b8e | ||
|
|
23612ba6ec | ||
|
|
217646f031 | ||
|
|
91667d9ecd | ||
|
|
3501ee9a9d | ||
|
|
f0c3860032 | ||
|
|
17dcaf9afa | ||
|
|
f484c98152 | ||
|
|
46f68115b2 | ||
|
|
7ac22a6ce8 | ||
|
|
bed79ef89e | ||
|
|
54095b9a89 | ||
|
|
4b58060ab6 | ||
|
|
dbbb554735 | ||
|
|
9c3be1b851 | ||
|
|
190ab211e3 | ||
|
|
f4fbe90a72 | ||
|
|
a9cbd5a172 | ||
|
|
94ba1c83c6 | ||
|
|
9b3756e591 | ||
|
|
aff775f488 | ||
|
|
4de5274996 | ||
|
|
4e57868037 | ||
|
|
ab6b32b8ba | ||
|
|
46285a499e | ||
|
|
ce6cad5dfe | ||
|
|
d5ea86bc81 | ||
|
|
41ea424359 | ||
|
|
87b0259b97 | ||
|
|
2490e97ea0 | ||
|
|
eecfe9d387 | ||
|
|
9ca5ee52e7 | ||
|
|
fb23cc8c7a | ||
|
|
ff7ce39841 | ||
|
|
0f05d6bd74 | ||
|
|
93c15c8151 | ||
|
|
22c8268f02 | ||
|
|
216cd491cc | ||
|
|
5efc573783 | ||
|
|
bca0da6bd4 | ||
|
|
9601a1fa4e | ||
|
|
b8e545bfa4 | ||
|
|
5c16f0d027 | ||
|
|
1b4441baac | ||
|
|
0147a1d41f | ||
|
|
0f11fbe599 | ||
|
|
9c18e99fe2 | ||
|
|
6e0a7de9cc | ||
|
|
b141a65838 | ||
|
|
7f842bb1e8 | ||
|
|
bd65aae81e | ||
|
|
b8dedb568c | ||
|
|
ec94c29ed9 | ||
|
|
c77943d01c | ||
|
|
fc5fb956df | ||
|
|
2eba126ed7 | ||
|
|
da52d677c7 | ||
|
|
ab4373d025 | ||
|
|
5e88a0f0cc | ||
|
|
ba794c2b60 | ||
|
|
268559d8de | ||
|
|
473d147333 | ||
|
|
d5d9f9bedc | ||
|
|
f31d30bf84 | ||
|
|
03b216a6b4 | ||
|
|
3e6510b935 | ||
|
|
e87b35e0bb | ||
|
|
322fdb14de | ||
|
|
09381575a7 | ||
|
|
881243da6a | ||
|
|
851fad3e3f | ||
|
|
46d65f0b7e | ||
|
|
03bebbe4c2 | ||
|
|
1649f30389 | ||
|
|
38f76d449a | ||
|
|
f2cbdae829 | ||
|
|
3a42354efd | ||
|
|
fe7853a389 | ||
|
|
06738cae93 | ||
|
|
d6243a2dd2 | ||
|
|
04be0fe634 | ||
|
|
fd12a1f6be | ||
|
|
e10dd4ef42 | ||
|
|
62c02e3fce | ||
|
|
ae2c55c33b | ||
|
|
4a2a646943 | ||
|
|
ae47ee802b | ||
|
|
4fd2f1f974 | ||
|
|
b9f16e8cce | ||
|
|
70b4843bc4 | ||
|
|
95190c321c | ||
|
|
a9b3be33e0 | ||
|
|
e05dad4267 | ||
|
|
83b90d472f | ||
|
|
ee4ff6e732 | ||
|
|
2267d38352 | ||
|
|
4fbb47300e | ||
|
|
836e168a6c | ||
|
|
a9684f67cc | ||
|
|
686e90d0ed | ||
|
|
0b9b39fef7 | ||
|
|
67a3b03b07 | ||
|
|
388db4e995 | ||
|
|
a28a1aa601 | ||
|
|
ed82106359 | ||
|
|
c57b84cb17 | ||
|
|
2dfe9fcf45 | ||
|
|
51f978ac72 | ||
|
|
c216677e1e | ||
|
|
8a5d275136 | ||
|
|
a36b76ba15 | ||
|
|
f3913949b2 | ||
|
|
76fdbfaa2f | ||
|
|
6b44b9ae1e | ||
|
|
8615c4c3b0 | ||
|
|
f976bd3fff | ||
|
|
db55a2664f | ||
|
|
4f1b4b1283 |
29
.ci/Debian13/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
FROM debian:13
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
ca-certificates \
|
||||||
|
ccache \
|
||||||
|
clang-format \
|
||||||
|
cmake \
|
||||||
|
file \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
libgl-dev \
|
||||||
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
|
libprotobuf-dev \
|
||||||
|
libqt6multimedia6 \
|
||||||
|
libqt6sql6-mysql \
|
||||||
|
ninja-build \
|
||||||
|
protobuf-compiler \
|
||||||
|
qt6-image-formats-plugins \
|
||||||
|
qt6-l10n-tools \
|
||||||
|
qt6-multimedia-dev \
|
||||||
|
qt6-svg-dev \
|
||||||
|
qt6-tools-dev \
|
||||||
|
qt6-tools-dev-tools \
|
||||||
|
qt6-websockets-dev \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM fedora:41
|
FROM fedora:43
|
||||||
|
|
||||||
RUN dnf install -y \
|
RUN dnf install -y \
|
||||||
ccache \
|
ccache \
|
||||||
21
.ci/Servatrice_Debian11/Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
FROM debian:11
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
ccache \
|
||||||
|
clang-format \
|
||||||
|
cmake \
|
||||||
|
file \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
libmariadb-dev-compat \
|
||||||
|
libprotobuf-dev \
|
||||||
|
libqt5sql5-mysql \
|
||||||
|
libqt5websockets5-dev \
|
||||||
|
ninja-build \
|
||||||
|
protobuf-compiler \
|
||||||
|
qttools5-dev \
|
||||||
|
qttools5-dev-tools \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
130
.ci/compile.sh
@@ -11,7 +11,8 @@
|
|||||||
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
||||||
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
||||||
# --dir <dir> sets the name of the build dir, default is "build"
|
# --dir <dir> sets the name of the build dir, default is "build"
|
||||||
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR CMAKE_GENERATOR
|
# --target-macos-version <version> sets the min os version - only used for macOS builds
|
||||||
|
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION
|
||||||
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir>)
|
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir>)
|
||||||
# exitcode: 1 for failure, 3 for invalid arguments
|
# exitcode: 1 for failure, 3 for invalid arguments
|
||||||
|
|
||||||
@@ -46,6 +47,10 @@ while [[ $# != 0 ]]; do
|
|||||||
MAKE_SERVER=1
|
MAKE_SERVER=1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
'--no-client')
|
||||||
|
MAKE_NO_CLIENT=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
'--test')
|
'--test')
|
||||||
MAKE_TEST=1
|
MAKE_TEST=1
|
||||||
shift
|
shift
|
||||||
@@ -66,6 +71,10 @@ while [[ $# != 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
'--vcpkg')
|
||||||
|
USE_VCPKG=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
'--dir')
|
'--dir')
|
||||||
shift
|
shift
|
||||||
if [[ $# == 0 ]]; then
|
if [[ $# == 0 ]]; then
|
||||||
@@ -75,6 +84,15 @@ while [[ $# != 0 ]]; do
|
|||||||
BUILD_DIR="$1"
|
BUILD_DIR="$1"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
'--target-macos-version')
|
||||||
|
shift
|
||||||
|
if [[ $# == 0 ]]; then
|
||||||
|
echo "::error file=$0::--target-macos-version expects an argument"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
TARGET_MACOS_VERSION="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "::error file=$0::unrecognized option: $1"
|
echo "::error file=$0::unrecognized option: $1"
|
||||||
exit 3
|
exit 3
|
||||||
@@ -95,11 +113,17 @@ fi
|
|||||||
mkdir -p "$BUILD_DIR"
|
mkdir -p "$BUILD_DIR"
|
||||||
cd "$BUILD_DIR"
|
cd "$BUILD_DIR"
|
||||||
|
|
||||||
|
# Set minimum CMake Version
|
||||||
|
export CMAKE_POLICY_VERSION_MINIMUM=3.10
|
||||||
|
|
||||||
# Add cmake flags
|
# Add cmake flags
|
||||||
flags=("-DCMAKE_BUILD_TYPE=$BUILDTYPE")
|
flags=("-DCMAKE_BUILD_TYPE=$BUILDTYPE")
|
||||||
if [[ $MAKE_SERVER ]]; then
|
if [[ $MAKE_SERVER ]]; then
|
||||||
flags+=("-DWITH_SERVER=1")
|
flags+=("-DWITH_SERVER=1")
|
||||||
fi
|
fi
|
||||||
|
if [[ $MAKE_NO_CLIENT ]]; then
|
||||||
|
flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0" "-DWITH_DBCONVERTER=0")
|
||||||
|
fi
|
||||||
if [[ $MAKE_TEST ]]; then
|
if [[ $MAKE_TEST ]]; then
|
||||||
flags+=("-DTEST=1")
|
flags+=("-DTEST=1")
|
||||||
fi
|
fi
|
||||||
@@ -113,6 +137,9 @@ fi
|
|||||||
if [[ $PACKAGE_TYPE ]]; then
|
if [[ $PACKAGE_TYPE ]]; then
|
||||||
flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE")
|
flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE")
|
||||||
fi
|
fi
|
||||||
|
if [[ $USE_VCPKG ]]; then
|
||||||
|
flags+=("-DUSE_VCPKG=1")
|
||||||
|
fi
|
||||||
|
|
||||||
# Add cmake --build flags
|
# Add cmake --build flags
|
||||||
buildflags=(--config "$BUILDTYPE")
|
buildflags=(--config "$BUILDTYPE")
|
||||||
@@ -128,33 +155,108 @@ function ccachestatsverbose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
|
if [[ $RUNNER_OS == macOS ]]; then
|
||||||
|
|
||||||
|
if [[ $TARGET_MACOS_VERSION ]]; then
|
||||||
|
# CMAKE_OSX_DEPLOYMENT_TARGET is a vanilla cmake flag needed to compile to target macOS version
|
||||||
|
flags+=("-DCMAKE_OSX_DEPLOYMENT_TARGET=$TARGET_MACOS_VERSION")
|
||||||
|
|
||||||
|
# vcpkg dependencies need a vcpkg triplet file to compile to the target macOS version
|
||||||
|
# an easy way is to copy the x64-osx.cmake file and modify it
|
||||||
|
triplets_dir="/tmp/cmake/triplets"
|
||||||
|
triplet_version="custom-triplet"
|
||||||
|
triplet_file="$triplets_dir/$triplet_version.cmake"
|
||||||
|
arch=$(uname -m)
|
||||||
|
if [[ $arch == x86_64 ]]; then
|
||||||
|
arch="x64"
|
||||||
|
fi
|
||||||
|
mkdir -p "$triplets_dir"
|
||||||
|
cp "../vcpkg/triplets/$arch-osx.cmake" "$triplet_file"
|
||||||
|
echo "set(VCPKG_CMAKE_SYSTEM_VERSION $TARGET_MACOS_VERSION)" >>"$triplet_file"
|
||||||
|
echo "set(VCPKG_OSX_DEPLOYMENT_TARGET $TARGET_MACOS_VERSION)" >>"$triplet_file"
|
||||||
|
flags+=("-DVCPKG_OVERLAY_TRIPLETS=$triplets_dir")
|
||||||
|
flags+=("-DVCPKG_HOST_TRIPLET=$triplet_version")
|
||||||
|
flags+=("-DVCPKG_TARGET_TRIPLET=$triplet_version")
|
||||||
|
echo "::group::Generated triplet $triplet_file"
|
||||||
|
cat "$triplet_file"
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "::group::Signing Certificate"
|
||||||
|
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]; then
|
||||||
|
echo "$MACOS_CERTIFICATE" | base64 --decode >"certificate.p12"
|
||||||
|
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||||
|
security default-keychain -s build.keychain
|
||||||
|
security set-keychain-settings -t 3600 -l build.keychain
|
||||||
|
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||||
|
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||||
|
echo "macOS signing certificate successfully imported and keychain configured."
|
||||||
|
else
|
||||||
|
echo "No signing certificate configured. Skipping set up of keychain in macOS environment."
|
||||||
|
fi
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
if [[ $MAKE_PACKAGE ]]; then
|
||||||
|
# Workaround https://github.com/actions/runner-images/issues/7522
|
||||||
|
# have hdiutil repeat the command 10 times in hope of success
|
||||||
|
hdiutil_script="/tmp/hdiutil.sh"
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
echo '#!/bin/bash
|
||||||
|
i=0
|
||||||
|
while ! hdiutil "$@"; do
|
||||||
|
if (( ++i >= 10 )); then
|
||||||
|
echo "Error: hdiutil failed $i times!" >&2
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done' >"$hdiutil_script"
|
||||||
|
chmod +x "$hdiutil_script"
|
||||||
|
flags+=(-DCPACK_COMMAND_HDIUTIL="$hdiutil_script")
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [[ $RUNNER_OS == Windows ]]; then
|
||||||
|
# Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
|
||||||
|
# and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt
|
||||||
|
buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true)
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $USE_CCACHE ]]; then
|
if [[ $USE_CCACHE ]]; then
|
||||||
echo "::group::Show ccache stats (before)"
|
echo "::group::Show ccache stats"
|
||||||
ccachestatsverbose
|
ccachestatsverbose
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "::group::Configure CMake"
|
echo "::group::Configure cmake"
|
||||||
cmake --version
|
cmake --version
|
||||||
|
echo "Running cmake with flags: ${flags[*]}"
|
||||||
cmake .. "${flags[@]}"
|
cmake .. "${flags[@]}"
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
|
|
||||||
echo "::group::Build project"
|
echo "::group::Build project"
|
||||||
if [[ $RUNNER_OS == Windows ]]; then
|
echo "Running cmake --build with flags: ${buildflags[*]}"
|
||||||
# Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
|
cmake --build . "${buildflags[@]}"
|
||||||
# and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt
|
|
||||||
cmake --build . "${buildflags[@]}" -- -p:UseMultiToolTask=true -p:EnableClServerMode=true
|
|
||||||
else
|
|
||||||
cmake --build . "${buildflags[@]}"
|
|
||||||
fi
|
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
|
|
||||||
if [[ $USE_CCACHE ]]; then
|
if [[ $USE_CCACHE ]]; then
|
||||||
echo "::group::Show ccache stats (after)"
|
echo "::group::Show ccache stats again"
|
||||||
ccachestatsverbose
|
ccachestatsverbose
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $RUNNER_OS == macOS ]]; then
|
||||||
|
echo "::group::Inspect Mach-O binaries"
|
||||||
|
for app in cockatrice oracle servatrice dbconverter; do
|
||||||
|
binary="$GITHUB_WORKSPACE/build/$app/$app.app/Contents/MacOS/$app"
|
||||||
|
echo "Inspecting $app..."
|
||||||
|
vtool -show-build "$binary"
|
||||||
|
file "$binary"
|
||||||
|
lipo -info "$binary"
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $MAKE_TEST ]]; then
|
if [[ $MAKE_TEST ]]; then
|
||||||
echo "::group::Run tests"
|
echo "::group::Run tests"
|
||||||
ctest -C "$BUILDTYPE" --output-on-failure
|
ctest -C "$BUILDTYPE" --output-on-failure
|
||||||
@@ -169,12 +271,6 @@ fi
|
|||||||
|
|
||||||
if [[ $MAKE_PACKAGE ]]; then
|
if [[ $MAKE_PACKAGE ]]; then
|
||||||
echo "::group::Create package"
|
echo "::group::Create package"
|
||||||
|
|
||||||
if [[ $RUNNER_OS == macOS ]]; then
|
|
||||||
# Workaround https://github.com/actions/runner-images/issues/7522
|
|
||||||
echo "killing XProtectBehaviorService"; sudo pkill -9 XProtect >/dev/null || true;
|
|
||||||
echo "waiting for XProtectBehaviorService kill"; while pgrep "XProtect"; do sleep 3; done;
|
|
||||||
fi
|
|
||||||
cmake --build . --target package --config "$BUILDTYPE"
|
cmake --build . --target package --config "$BUILDTYPE"
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
|||||||
@@ -137,10 +137,11 @@ if [[ $SAVE ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Set compile function, runs the compile script on the image, passes arguments to the script
|
# Set compile function, runs the compile script on the image, passes arguments to the script
|
||||||
|
# shellcheck disable=2120
|
||||||
function RUN ()
|
function RUN ()
|
||||||
{
|
{
|
||||||
echo "running image:"
|
echo "running image:"
|
||||||
if [[ $(docker images) =~ "$IMAGE_NAME" ]]; then
|
if [[ $(docker images) =~ $IMAGE_NAME ]]; then
|
||||||
local args=(--mount "type=bind,source=$PWD,target=/src")
|
local args=(--mount "type=bind,source=$PWD,target=/src")
|
||||||
args+=(--workdir "/src")
|
args+=(--workdir "/src")
|
||||||
args+=(--user "$(id -u):$(id -g)")
|
args+=(--user "$(id -u):$(id -g)")
|
||||||
@@ -151,6 +152,7 @@ function RUN ()
|
|||||||
if [[ -n "$CMAKE_GENERATOR" ]]; then
|
if [[ -n "$CMAKE_GENERATOR" ]]; then
|
||||||
args+=(--env "CMAKE_GENERATOR=$CMAKE_GENERATOR")
|
args+=(--env "CMAKE_GENERATOR=$CMAKE_GENERATOR")
|
||||||
fi
|
fi
|
||||||
|
# shellcheck disable=2086
|
||||||
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
||||||
return $?
|
return $?
|
||||||
else
|
else
|
||||||
@@ -164,5 +166,6 @@ function RUN ()
|
|||||||
if [[ $INTERACTIVE ]]; then
|
if [[ $INTERACTIVE ]]; then
|
||||||
export BUILD_SCRIPT="-i"
|
export BUILD_SCRIPT="-i"
|
||||||
export RUN_ARGS="$RUN_ARGS -it"
|
export RUN_ARGS="$RUN_ARGS -it"
|
||||||
|
# shellcheck disable=2119
|
||||||
RUN
|
RUN
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -11,11 +11,19 @@ if ! git merge-base origin/master HEAD; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check formatting using format.sh
|
# Check formatting using format.sh
|
||||||
echo "Checking your code using clang-format/cmake-format..."
|
echo "Checking your code using format.sh..."
|
||||||
|
|
||||||
diff="$(./format.sh --diff --cmake --cf-version --branch origin/master)"
|
diff="$(./format.sh --diff --cmake --shell --print-version --branch origin/master)"
|
||||||
err=$?
|
err=$?
|
||||||
|
|
||||||
|
sep="
|
||||||
|
----------
|
||||||
|
"
|
||||||
|
used_version="${diff%%"$sep"*}"
|
||||||
|
diff="${diff#*"$sep"}"
|
||||||
|
changes_to_make="${diff%%"$sep"*}"
|
||||||
|
files_to_edit="${diff#*"$sep"}"
|
||||||
|
|
||||||
case $err in
|
case $err in
|
||||||
1)
|
1)
|
||||||
cat <<EOM
|
cat <<EOM
|
||||||
@@ -33,14 +41,13 @@ case $err in
|
|||||||
***********************************************************
|
***********************************************************
|
||||||
|
|
||||||
Used version:
|
Used version:
|
||||||
${diff%%
|
$used_version
|
||||||
----------
|
|
||||||
*}
|
Affected files:
|
||||||
|
$files_to_edit
|
||||||
|
|
||||||
The following changes should be made:
|
The following changes should be made:
|
||||||
${diff#*
|
$changes_to_make
|
||||||
----------
|
|
||||||
}
|
|
||||||
|
|
||||||
Exiting...
|
Exiting...
|
||||||
EOM
|
EOM
|
||||||
@@ -58,6 +65,9 @@ EOM
|
|||||||
*** ***
|
*** ***
|
||||||
***********************************************************
|
***********************************************************
|
||||||
|
|
||||||
|
Used version:
|
||||||
|
$used_version
|
||||||
|
|
||||||
Exiting...
|
Exiting...
|
||||||
EOM
|
EOM
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ Available pre-compiled binaries for installation:
|
|||||||
<b>Linux</b>
|
<b>Linux</b>
|
||||||
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
||||||
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
|
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
|
||||||
|
• <kbd>Debian 13</kbd> <sub><i>Trixie</i></sub>
|
||||||
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
||||||
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
|
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
|
||||||
|
• <kbd>Fedora 43</kbd>
|
||||||
• <kbd>Fedora 42</kbd>
|
• <kbd>Fedora 42</kbd>
|
||||||
• <kbd>Fedora 41</kbd>
|
|
||||||
|
|
||||||
<sub>We are also packaged in <kbd>Arch Linux</kbd>'s <a href="https://archlinux.org/packages/extra/x86_64/cockatrice">official extra repository</a>, courtesy of @FFY00.</sub>
|
<sub>We are also packaged in <kbd>Arch Linux</kbd>'s <a href="https://archlinux.org/packages/extra/x86_64/cockatrice">official extra repository</a>, courtesy of @FFY00.</sub>
|
||||||
<sub>General Linux support is available via a <kbd>flatpak</kbd> package at <a href="https://flathub.org/apps/io.github.Cockatrice.cockatrice">Flathub</a>!</sub>
|
<sub>General Linux support is available via a <kbd>flatpak</kbd> package at <a href="https://flathub.org/apps/io.github.Cockatrice.cockatrice">Flathub</a>!</sub>
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Used by CI to sign, noratize and staple build artifacts under macOS
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
APP_PATH="$1"
|
|
||||||
|
|
||||||
if [[ -z "$APP_PATH" ]]; then
|
|
||||||
echo "Error: No input path supplied. Usage: $0 <path-to-app-bundle>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -e "$APP_PATH" ]]; then
|
|
||||||
echo "Error: Input path '$APP_PATH' does not exist."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "::group::Set up certificate"
|
|
||||||
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]; then
|
|
||||||
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
|
|
||||||
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
||||||
security default-keychain -s build.keychain
|
|
||||||
security set-keychain-settings -t 3600 -l build.keychain
|
|
||||||
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
||||||
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
|
||||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
||||||
else
|
|
||||||
echo "No signing certificate configured."
|
|
||||||
fi
|
|
||||||
echo "::endgroup::"
|
|
||||||
|
|
||||||
echo "::group::Sign app"
|
|
||||||
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]; then
|
|
||||||
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
|
||||||
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose=3 "$APP_PATH"
|
|
||||||
else
|
|
||||||
echo "No signing certificate configured."
|
|
||||||
fi
|
|
||||||
echo "::endgroup::"
|
|
||||||
|
|
||||||
echo "::group::Notarize app"
|
|
||||||
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]; then
|
|
||||||
# Store the notarization credentials so that we can prevent a UI password dialog from blocking the CI
|
|
||||||
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$MACOS_NOTARIZATION_APPLE_ID" --team-id "$MACOS_NOTARIZATION_TEAM_ID" --password "$MACOS_NOTARIZATION_PWD"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# We can't notarize an app bundle directly, but we need to compress it as an archive.
|
|
||||||
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
|
|
||||||
# notarization service
|
|
||||||
echo "Creating temp notarization archive"
|
|
||||||
ditto -c -k --keepParent "$APP_PATH" "notarization.zip"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
|
|
||||||
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
|
|
||||||
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
|
|
||||||
# you're curious
|
|
||||||
# Submit for notarization and capture output
|
|
||||||
NOTARY_OUTPUT=$(xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait --output-format json)
|
|
||||||
|
|
||||||
# Parse the submission ID from the JSON output
|
|
||||||
SUBMISSION_ID=$(echo "$NOTARY_OUTPUT" | jq -r '.id')
|
|
||||||
|
|
||||||
# Parse the status field in the JSON
|
|
||||||
STATUS=$(echo "$NOTARY_OUTPUT" | jq -r '.status')
|
|
||||||
|
|
||||||
if [[ "$STATUS" != "Accepted" ]]; then
|
|
||||||
echo "Notarization failed (status: $STATUS). Fetching detailed log..."
|
|
||||||
# Fetch and print the notarization log
|
|
||||||
xcrun notarytool log "$SUBMISSION_ID" --keychain-profile "notarytool-profile"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "No Apple ID configured."
|
|
||||||
fi
|
|
||||||
echo "::endgroup::"
|
|
||||||
|
|
||||||
echo "::group::Staple app"
|
|
||||||
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]; then
|
|
||||||
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
|
|
||||||
# validated by macOS even when an internet connection is not available.
|
|
||||||
xcrun stapler staple "$APP_PATH"
|
|
||||||
else
|
|
||||||
echo "No Apple ID configured."
|
|
||||||
fi
|
|
||||||
echo "::endgroup::"
|
|
||||||
|
|
||||||
echo "::group::Cleanup"
|
|
||||||
# Cleanup keychain and files to avoid leaking credentials
|
|
||||||
echo "Deleting keychain"
|
|
||||||
security delete-keychain build.keychain
|
|
||||||
rm -f certificate.p12 notarization.zip
|
|
||||||
echo "::endgroup::"
|
|
||||||
@@ -25,6 +25,9 @@ IndentCaseLabels: true
|
|||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
SortIncludes: true
|
SortIncludes: true
|
||||||
IncludeBlocks: Regroup
|
IncludeBlocks: Regroup
|
||||||
|
StatementAttributeLikeMacros: [emit]
|
||||||
|
# requires clang-format 16
|
||||||
|
# RemoveSemicolon: true
|
||||||
---
|
---
|
||||||
Language: Proto
|
Language: Proto
|
||||||
AllowShortFunctionsOnASingleLine: None
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|||||||
2
.github/CONTRIBUTING.md
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
<!--! @page contributing Contributing -->
|
||||||
|
|
||||||
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](
|
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](
|
||||||
#code-style-guide) | [Translations](#translations) | [Release Management](
|
#code-style-guide) | [Translations](#translations) | [Release Management](
|
||||||
#release-management)
|
#release-management)
|
||||||
|
|||||||
399
.github/workflows/desktop-build.yml
vendored
@@ -4,25 +4,39 @@ permissions:
|
|||||||
contents: write
|
contents: write
|
||||||
id-token: write
|
id-token: write
|
||||||
attestations: write
|
attestations: write
|
||||||
|
actions: write # needed for ccache action to be able to delete gha caches
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths-ignore:
|
paths:
|
||||||
- '**.md'
|
- '*/**' # matches all files not in root
|
||||||
- 'webclient/**'
|
- '!**.md'
|
||||||
- '.github/workflows/web-*.yml'
|
- '!.github/**'
|
||||||
- '.github/workflows/translations-*.yml'
|
- '!.husky/**'
|
||||||
- '.github/workflows/docker-release.yml'
|
- '!.tx/**'
|
||||||
|
- '!doc/**'
|
||||||
|
- '!webclient/**'
|
||||||
|
- '.github/workflows/desktop-build.yml'
|
||||||
|
- 'CMakeLists.txt'
|
||||||
|
- 'vcpkg.json'
|
||||||
|
- 'vcpkg'
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths:
|
||||||
- '**.md'
|
- '*/**' # matches all files not in root
|
||||||
- 'webclient/**'
|
- '!**.md'
|
||||||
- '.github/workflows/web-*.yml'
|
- '!.github/**'
|
||||||
- '.github/workflows/translations-*.yml'
|
- '!.husky/**'
|
||||||
|
- '!.tx/**'
|
||||||
|
- '!doc/**'
|
||||||
|
- '!webclient/**'
|
||||||
|
- '.github/workflows/desktop-build.yml'
|
||||||
|
- 'CMakeLists.txt'
|
||||||
|
- 'vcpkg.json'
|
||||||
|
- 'vcpkg'
|
||||||
|
|
||||||
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on master)
|
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on master)
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -56,7 +70,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
if: steps.configure.outputs.tag != null
|
if: steps.configure.outputs.tag != null
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@@ -100,19 +114,29 @@ jobs:
|
|||||||
- distro: Debian
|
- distro: Debian
|
||||||
version: 11
|
version: 11
|
||||||
package: DEB
|
package: DEB
|
||||||
test: skip # Running tests on all distros is superfluous
|
|
||||||
|
- distro: Servatrice_Debian
|
||||||
|
version: 11
|
||||||
|
package: DEB
|
||||||
|
test: skip
|
||||||
|
server_only: yes
|
||||||
|
|
||||||
- distro: Debian
|
- distro: Debian
|
||||||
version: 12
|
version: 12
|
||||||
package: DEB
|
package: DEB
|
||||||
|
test: skip # Running tests on all distros is superfluous
|
||||||
|
|
||||||
|
- distro: Debian
|
||||||
|
version: 13
|
||||||
|
package: DEB
|
||||||
|
|
||||||
- distro: Fedora
|
- distro: Fedora
|
||||||
version: 41
|
version: 42
|
||||||
package: RPM
|
package: RPM
|
||||||
test: skip # Running tests on all distros is superfluous
|
test: skip # Running tests on all distros is superfluous
|
||||||
|
|
||||||
- distro: Fedora
|
- distro: Fedora
|
||||||
version: 42
|
version: 43
|
||||||
package: RPM
|
package: RPM
|
||||||
|
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
@@ -138,11 +162,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Restore compiler cache (ccache)
|
- name: Restore compiler cache (ccache)
|
||||||
id: ccache_restore
|
id: ccache_restore
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v5
|
||||||
env:
|
env:
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
with:
|
with:
|
||||||
@@ -172,15 +196,16 @@ jobs:
|
|||||||
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
||||||
package: '${{matrix.package}}'
|
package: '${{matrix.package}}'
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||||
|
NO_CLIENT: ${{matrix.server_only == 'yes' && '--no-client' || '' }}
|
||||||
run: |
|
run: |
|
||||||
source .ci/docker.sh
|
source .ci/docker.sh
|
||||||
RUN --server --release --package "$package" --dir "$BUILD_DIR" \
|
RUN --server --release --package "$package" --dir "$BUILD_DIR" \
|
||||||
--ccache "$CCACHE_SIZE"
|
--ccache "$CCACHE_SIZE" $NO_CLIENT
|
||||||
.ci/name_build.sh
|
.ci/name_build.sh
|
||||||
|
|
||||||
- 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@v4
|
uses: actions/cache/save@v5
|
||||||
with:
|
with:
|
||||||
path: ${{env.CACHE}}
|
path: ${{env.CACHE}}
|
||||||
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
@@ -188,7 +213,7 @@ 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@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.distro}}${{matrix.version}}-package
|
name: ${{matrix.distro}}${{matrix.version}}-package
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
@@ -208,7 +233,7 @@ jobs:
|
|||||||
- 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@v2
|
uses: actions/attest-build-provenance@v3
|
||||||
with:
|
with:
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
subject-name: ${{steps.build.outputs.name}}
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
||||||
@@ -216,179 +241,139 @@ jobs:
|
|||||||
- name: Verify binary attestation
|
- name: Verify binary attestation
|
||||||
if: steps.attestation.outcome == 'success'
|
if: steps.attestation.outcome == 'success'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
|
||||||
|
|
||||||
build-macos:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- target: 13
|
|
||||||
soc: Intel
|
|
||||||
os: macos-13
|
|
||||||
xcode: "14.3.1"
|
|
||||||
type: Release
|
|
||||||
make_package: 1
|
|
||||||
|
|
||||||
- target: 14
|
|
||||||
soc: Apple
|
|
||||||
os: macos-14
|
|
||||||
xcode: "15.4"
|
|
||||||
type: Release
|
|
||||||
make_package: 1
|
|
||||||
|
|
||||||
- target: 15
|
|
||||||
soc: Apple
|
|
||||||
os: macos-15
|
|
||||||
xcode: "16.2"
|
|
||||||
type: Release
|
|
||||||
make_package: 1
|
|
||||||
|
|
||||||
- target: 15
|
|
||||||
soc: Apple
|
|
||||||
os: macos-15
|
|
||||||
xcode: "16.2"
|
|
||||||
type: Debug
|
|
||||||
|
|
||||||
name: macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
|
||||||
needs: configure
|
|
||||||
runs-on: ${{matrix.os}}
|
|
||||||
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
|
||||||
env:
|
|
||||||
CCACHE_DIR: ${{github.workspace}}/.ccache/${{matrix.os}}-${{matrix.type}}
|
|
||||||
CCACHE_SIZE: 500M
|
|
||||||
DEVELOPER_DIR:
|
|
||||||
/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer
|
|
||||||
CMAKE_GENERATOR: 'Ninja'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install dependencies using Homebrew
|
|
||||||
shell: bash
|
|
||||||
# CMake cannot find the MySQL connector
|
|
||||||
# Neither of these works: mariadb-connector-c mysql-connector-c++
|
|
||||||
env:
|
|
||||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
|
||||||
run: |
|
|
||||||
brew update
|
|
||||||
brew install ccache protobuf qt --force-bottle
|
|
||||||
|
|
||||||
- name: Restore compiler cache (ccache)
|
|
||||||
id: ccache_restore
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
env:
|
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
|
||||||
with:
|
|
||||||
path: ${{env.CCACHE_DIR}}
|
|
||||||
key: ccache-${{matrix.os}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
|
||||||
restore-keys: ccache-${{matrix.os}}-${{matrix.type}}-
|
|
||||||
|
|
||||||
- name: Build on Xcode ${{matrix.xcode}}
|
|
||||||
shell: bash
|
|
||||||
id: build
|
|
||||||
env:
|
|
||||||
BUILDTYPE: '${{matrix.type}}'
|
|
||||||
MAKE_PACKAGE: '${{matrix.make_package}}'
|
|
||||||
PACKAGE_SUFFIX: '-macOS${{matrix.target}}_${{matrix.soc}}'
|
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
|
||||||
run: .ci/compile.sh --server --test --ccache "$CCACHE_SIZE"
|
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
|
||||||
if: github.ref == 'refs/heads/master'
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: ${{env.CCACHE_DIR}}
|
|
||||||
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
|
||||||
|
|
||||||
- name: Sign app bundle
|
|
||||||
if: matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
|
||||||
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
|
||||||
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
|
||||||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
|
||||||
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
|
||||||
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
|
||||||
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
|
|
||||||
run: .ci/sign_macos.sh ${{steps.build.outputs.path}}
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
id: upload_artifact
|
|
||||||
if: matrix.make_package
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: macOS${{matrix.target}}${{ matrix.soc == 'Intel' && '_Intel' || '' }}${{ matrix.type == 'Debug' && '_Debug' || '' }}-package
|
|
||||||
path: ${{steps.build.outputs.path}}
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Upload to release
|
|
||||||
id: upload_release
|
|
||||||
if: matrix.make_package && needs.configure.outputs.tag != null
|
|
||||||
shell: bash
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
|
||||||
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
|
||||||
|
|
||||||
- name: Attest binary provenance
|
|
||||||
id: attestation
|
|
||||||
if: steps.upload_release.outcome == 'success'
|
|
||||||
uses: actions/attest-build-provenance@v2
|
|
||||||
with:
|
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
|
||||||
|
|
||||||
- name: Verify binary attestation
|
|
||||||
if: steps.attestation.outcome == 'success'
|
|
||||||
shell: bash
|
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
||||||
|
|
||||||
build-windows:
|
build-vcpkg:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- target: 7
|
- os: macOS
|
||||||
qt_version: 5.15.*
|
target: 13
|
||||||
qt_arch: msvc2019_64
|
runner: macos-15-intel
|
||||||
|
soc: Intel
|
||||||
- target: 10
|
xcode: "16.4"
|
||||||
|
type: Release
|
||||||
|
override_target: 13
|
||||||
|
make_package: 1
|
||||||
|
package_suffix: "-macOS13_Intel"
|
||||||
|
artifact_name: macOS13_Intel-package
|
||||||
qt_version: 6.6.*
|
qt_version: 6.6.*
|
||||||
qt_arch: msvc2019_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
|
||||||
|
use_ccache: 1
|
||||||
|
|
||||||
name: Windows ${{matrix.target}}
|
- os: macOS
|
||||||
|
target: 14
|
||||||
|
runner: macos-14
|
||||||
|
soc: Apple
|
||||||
|
xcode: "15.4"
|
||||||
|
type: Release
|
||||||
|
make_package: 1
|
||||||
|
package_suffix: "-macOS14"
|
||||||
|
artifact_name: macOS14-package
|
||||||
|
qt_version: 6.6.*
|
||||||
|
qt_arch: clang_64
|
||||||
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
|
cache_qt: false
|
||||||
|
cmake_generator: Ninja
|
||||||
|
use_ccache: 1
|
||||||
|
|
||||||
|
- os: macOS
|
||||||
|
target: 15
|
||||||
|
runner: macos-15
|
||||||
|
soc: Apple
|
||||||
|
xcode: "16.4"
|
||||||
|
type: Release
|
||||||
|
make_package: 1
|
||||||
|
package_suffix: "-macOS15"
|
||||||
|
artifact_name: macOS15-package
|
||||||
|
qt_version: 6.6.*
|
||||||
|
qt_arch: clang_64
|
||||||
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
|
cache_qt: false
|
||||||
|
cmake_generator: Ninja
|
||||||
|
use_ccache: 1
|
||||||
|
|
||||||
|
- os: macOS
|
||||||
|
target: 15
|
||||||
|
runner: macos-15
|
||||||
|
soc: Apple
|
||||||
|
xcode: "16.4"
|
||||||
|
type: Debug
|
||||||
|
qt_version: 6.6.*
|
||||||
|
qt_arch: clang_64
|
||||||
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
|
cache_qt: false
|
||||||
|
cmake_generator: Ninja
|
||||||
|
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
|
||||||
|
target: 10
|
||||||
|
runner: windows-2022
|
||||||
|
type: Release
|
||||||
|
make_package: 1
|
||||||
|
package_suffix: "-Win10"
|
||||||
|
artifact_name: Windows10-installer
|
||||||
|
qt_version: 6.6.*
|
||||||
|
qt_arch: win64_msvc2019_64
|
||||||
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
|
cache_qt: true
|
||||||
|
cmake_generator: "Visual Studio 17 2022"
|
||||||
|
cmake_generator_platform: x64
|
||||||
|
|
||||||
|
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||||
needs: configure
|
needs: configure
|
||||||
runs-on: windows-2022
|
runs-on: ${{matrix.runner}}
|
||||||
env:
|
|
||||||
CMAKE_GENERATOR: 'Visual Studio 17 2022'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
- name: Add msbuild to PATH
|
- name: Add msbuild to PATH
|
||||||
|
if: matrix.os == 'Windows'
|
||||||
id: add-msbuild
|
id: add-msbuild
|
||||||
uses: microsoft/setup-msbuild@v2
|
uses: microsoft/setup-msbuild@v2
|
||||||
with:
|
with:
|
||||||
msbuild-architecture: x64
|
msbuild-architecture: x64
|
||||||
|
|
||||||
- name: Checkout
|
# Using jianmingyong/ccache-action to setup ccache without using brew
|
||||||
uses: actions/checkout@v4
|
# It tries to download a binary of ccache from GitHub Release and falls back to building from source if it fails
|
||||||
|
- name: Setup ccache
|
||||||
|
if: matrix.use_ccache == 1
|
||||||
|
uses: jianmingyong/ccache-action@v1
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
install-type: "binary"
|
||||||
|
ccache-key-prefix: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}
|
||||||
|
max-size: 500M
|
||||||
|
gh-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Install Qt ${{matrix.qt_version}}
|
- name: Install Qt ${{matrix.qt_version}}
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
cache: true
|
|
||||||
setup-python: true
|
|
||||||
version: ${{matrix.qt_version}}
|
version: ${{matrix.qt_version}}
|
||||||
arch: win64_${{matrix.qt_arch}}
|
arch: ${{matrix.qt_arch}}
|
||||||
tools: ${{matrix.qt_tools}}
|
|
||||||
modules: ${{matrix.qt_modules}}
|
modules: ${{matrix.qt_modules}}
|
||||||
|
cache: ${{matrix.cache_qt}}
|
||||||
|
|
||||||
- name: Setup vcpkg cache
|
- name: Setup vcpkg cache
|
||||||
id: vcpkg-cache
|
id: vcpkg-cache
|
||||||
@@ -396,30 +381,84 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# uses environment variables, see compile.sh for more details
|
||||||
- name: Build Cockatrice
|
- name: Build Cockatrice
|
||||||
id: build
|
id: build
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
PACKAGE_SUFFIX: '-Win${{matrix.target}}'
|
BUILDTYPE: '${{matrix.type}}'
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
MAKE_PACKAGE: '${{matrix.make_package}}'
|
||||||
CMAKE_GENERATOR_PLATFORM: 'x64'
|
PACKAGE_SUFFIX: '${{matrix.package_suffix}}'
|
||||||
QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win64_${{matrix.qt_arch}}'
|
CMAKE_GENERATOR: ${{matrix.cmake_generator}}
|
||||||
|
CMAKE_GENERATOR_PLATFORM: ${{matrix.cmake_generator_platform}}
|
||||||
|
USE_CCACHE: ${{matrix.use_ccache}}
|
||||||
VCPKG_DISABLE_METRICS: 1
|
VCPKG_DISABLE_METRICS: 1
|
||||||
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
|
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
|
||||||
# No need for --parallel flag, MTT is added in the compile script to let cmake/msbuild manage core count,
|
# macOS-specific environment variables, will be ignored on Windows
|
||||||
# project and process parallelism: https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
|
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
||||||
run: .ci/compile.sh --server --release --test --package
|
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
||||||
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
|
DEVELOPER_DIR: '/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer'
|
||||||
|
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
||||||
|
run: .ci/compile.sh --server --test --vcpkg
|
||||||
|
|
||||||
|
- name: Sign app bundle
|
||||||
|
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||||
|
env:
|
||||||
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
|
run: |
|
||||||
|
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
|
||||||
|
then
|
||||||
|
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||||
|
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose ${{steps.build.outputs.path}}
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Notarize app bundle
|
||||||
|
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||||
|
env:
|
||||||
|
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
||||||
|
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
||||||
|
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
|
||||||
|
run: |
|
||||||
|
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]
|
||||||
|
then
|
||||||
|
# Store the notarization credentials so that we can prevent a UI password dialog from blocking the CI
|
||||||
|
echo "Create keychain profile"
|
||||||
|
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$MACOS_NOTARIZATION_APPLE_ID" --team-id "$MACOS_NOTARIZATION_TEAM_ID" --password "$MACOS_NOTARIZATION_PWD"
|
||||||
|
|
||||||
|
# We can't notarize an app bundle directly, but we need to compress it as an archive.
|
||||||
|
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
|
||||||
|
# notarization service
|
||||||
|
echo "Creating temp notarization archive"
|
||||||
|
ditto -c -k --keepParent ${{steps.build.outputs.path}} "notarization.zip"
|
||||||
|
|
||||||
|
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
|
||||||
|
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
|
||||||
|
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
|
||||||
|
# you're curious
|
||||||
|
echo "Notarize app"
|
||||||
|
xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait
|
||||||
|
|
||||||
|
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
|
||||||
|
# validated by macOS even when an internet connection is not available.
|
||||||
|
echo "Attach staple"
|
||||||
|
xcrun stapler staple ${{steps.build.outputs.path}}
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
id: upload_artifact
|
id: upload_artifact
|
||||||
uses: actions/upload-artifact@v4
|
if: matrix.make_package
|
||||||
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: Windows${{matrix.target}}-installer
|
name: ${{matrix.artifact_name}}
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload pdb database
|
- name: Upload pdb database
|
||||||
uses: actions/upload-artifact@v4
|
if: matrix.os == 'Windows'
|
||||||
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: Windows${{matrix.target}}-debug-pdbs
|
name: Windows${{matrix.target}}-debug-pdbs
|
||||||
path: |
|
path: |
|
||||||
@@ -441,7 +480,7 @@ jobs:
|
|||||||
- 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@v2
|
uses: actions/attest-build-provenance@v3
|
||||||
with:
|
with:
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
subject-name: ${{steps.build.outputs.name}}
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
||||||
@@ -449,4 +488,6 @@ jobs:
|
|||||||
- name: Verify binary attestation
|
- name: Verify binary attestation
|
||||||
if: steps.attestation.outcome == 'success'
|
if: steps.attestation.outcome == 'success'
|
||||||
shell: bash
|
shell: bash
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{github.token}}
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
||||||
|
|||||||
25
.github/workflows/desktop-lint.yml
vendored
@@ -1,13 +1,22 @@
|
|||||||
name: Code Style (C++)
|
name: Code Style (C++)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
# push trigger not needed for linting, we do not allow direct pushes to master
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths:
|
||||||
- '**.md'
|
- '*/**' # matches all files not in root
|
||||||
- 'webclient/**'
|
- '!**.md'
|
||||||
- '.github/workflows/web-*.yml'
|
- '!.ci/**'
|
||||||
- '.github/workflows/translations-*.yml'
|
- '!.github/**'
|
||||||
- '.github/workflows/docker-release.yml'
|
- '!.husky/**'
|
||||||
|
- '!.tx/**'
|
||||||
|
- '!doc/**'
|
||||||
|
- '!webclient/**'
|
||||||
|
- '.ci/lint_cpp.sh'
|
||||||
|
- '.github/workflows/desktop-lint.yml'
|
||||||
|
- '.clang-format'
|
||||||
|
- '.cmake-format.json'
|
||||||
|
- 'format.sh'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
@@ -15,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 20 # should be enough to find merge base
|
fetch-depth: 20 # should be enough to find merge base
|
||||||
|
|
||||||
@@ -23,7 +32,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends clang-format cmake-format
|
sudo apt-get install -y --no-install-recommends clang-format cmake-format shellcheck
|
||||||
|
|
||||||
- name: Check code formatting
|
- name: Check code formatting
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
7
.github/workflows/docker-release.yml
vendored
@@ -11,12 +11,7 @@ on:
|
|||||||
- master
|
- master
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/docker-release.yml'
|
- '.github/workflows/docker-release.yml'
|
||||||
- 'CMakeLists.txt'
|
|
||||||
- 'Dockerfile'
|
- 'Dockerfile'
|
||||||
- 'servatrice/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'cmake/**'
|
|
||||||
- '!**.md'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
@@ -28,7 +23,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Docker metadata
|
- name: Docker metadata
|
||||||
id: metadata
|
id: metadata
|
||||||
|
|||||||
61
.github/workflows/documentation-build.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: Generate Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*' # Only re-generate docs when a new tagged version is pushed
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'doc/doxygen/**'
|
||||||
|
- '.github/workflows/documentation-build.yml'
|
||||||
|
- 'Doxyfile'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
COCKATRICE_REF: ${{ github.ref_name }} # Tag name if the commit is tagged, otherwise branch name
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docs:
|
||||||
|
name: Doxygen
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install Graphviz
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y graphviz
|
||||||
|
dot -V
|
||||||
|
|
||||||
|
- name: Install Doxygen
|
||||||
|
uses: ssciwr/doxygen-install@v1
|
||||||
|
with:
|
||||||
|
version: "1.14.0"
|
||||||
|
|
||||||
|
- name: Update Doxygen Configuration
|
||||||
|
run: |
|
||||||
|
git diff Doxyfile
|
||||||
|
doxygen -u Doxyfile
|
||||||
|
if git diff --quiet Doxyfile; then
|
||||||
|
echo "::notice::No config changes in Doxyfile detected."
|
||||||
|
else
|
||||||
|
echo "::error::Config changes in Doxyfile detected! Please update the file by running 'doxygen -u Doxyfile'."
|
||||||
|
echo ""
|
||||||
|
git diff --color=always Doxyfile
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Generate Documentation
|
||||||
|
if: always()
|
||||||
|
run: doxygen Doxyfile
|
||||||
|
|
||||||
|
- name: Deploy to cockatrice.github.io
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: peaceiris/actions-gh-pages@v4
|
||||||
|
with:
|
||||||
|
deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
|
||||||
|
external_repository: Cockatrice/cockatrice.github.io
|
||||||
|
publish_branch: master
|
||||||
|
publish_dir: ./docs/html
|
||||||
|
destination_dir: docs # Docs will live under https://cockatrice.github.io/docs/
|
||||||
5
.github/workflows/translations-pull.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
- cron: '0 0 15 1,4,7,10 *'
|
- cron: '0 0 15 1,4,7,10 *'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
|
- '.tx/**'
|
||||||
- '.github/workflows/translations-pull.yml'
|
- '.github/workflows/translations-pull.yml'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,7 +20,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Pull translated strings from Transifex
|
- name: Pull translated strings from Transifex
|
||||||
uses: transifex/cli-action@v2
|
uses: transifex/cli-action@v2
|
||||||
@@ -32,7 +33,7 @@ jobs:
|
|||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: create_pr
|
id: create_pr
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cockatrice/translations/*.ts
|
cockatrice/translations/*.ts
|
||||||
|
|||||||
13
.github/workflows/translations-push.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
- cron: '0 0 1 1,4,7,10 *'
|
- cron: '0 0 1 1,4,7,10 *'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
|
- '.ci/update_translation_source_strings.sh'
|
||||||
- '.github/workflows/translations-push.yml'
|
- '.github/workflows/translations-push.yml'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,7 +20,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install lupdate
|
- name: Install lupdate
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -30,10 +31,10 @@ jobs:
|
|||||||
- name: Update Cockatrice translation source
|
- name: Update Cockatrice translation source
|
||||||
id: cockatrice
|
id: cockatrice
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
run: |
|
||||||
FILE: 'cockatrice/cockatrice_en@source.ts'
|
FILE="cockatrice/cockatrice_en@source.ts"
|
||||||
DIRS: 'cockatrice/src common'
|
export DIRS="cockatrice/src $(find . -maxdepth 1 -type d -name 'libcockatrice_*')"
|
||||||
run: .ci/update_translation_source_strings.sh
|
FILE="$FILE" DIRS="$DIRS" .ci/update_translation_source_strings.sh
|
||||||
|
|
||||||
- name: Update Oracle translation source
|
- name: Update Oracle translation source
|
||||||
id: oracle
|
id: oracle
|
||||||
@@ -56,7 +57,7 @@ jobs:
|
|||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: create_pr
|
id: create_pr
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cockatrice/cockatrice_en@source.ts
|
cockatrice/cockatrice_en@source.ts
|
||||||
|
|||||||
10
.github/workflows/web-build.yml
vendored
@@ -5,14 +5,16 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/web-*.yml'
|
- '.husky/**'
|
||||||
- 'webclient/**'
|
- 'webclient/**'
|
||||||
- '!**.md'
|
- '!**.md'
|
||||||
|
- '.github/workflows/web-build.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/web-*.yml'
|
- '.husky/**'
|
||||||
- 'webclient/**'
|
- 'webclient/**'
|
||||||
- '!**.md'
|
- '!**.md'
|
||||||
|
- '.github/workflows/web-build.yml'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-web:
|
build-web:
|
||||||
@@ -33,10 +35,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{matrix.node_version}}
|
node-version: ${{matrix.node_version}}
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|||||||
7
.github/workflows/web-lint.yml
vendored
@@ -1,11 +1,12 @@
|
|||||||
name: Code Style (TypeScript)
|
name: Code Style (TypeScript)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
# push trigger not needed for linting, we do not allow direct pushes to master
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/web-*.yml'
|
|
||||||
- 'webclient/**'
|
- 'webclient/**'
|
||||||
- '!**.md'
|
- '!**.md'
|
||||||
|
- '.github/workflows/web-lint.yml'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ESLint:
|
ESLint:
|
||||||
@@ -17,10 +18,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: 'webclient/package-lock.json'
|
cache-dependency-path: 'webclient/package-lock.json'
|
||||||
|
|||||||
1
.gitignore
vendored
@@ -14,3 +14,4 @@ compile_commands.json
|
|||||||
.cache
|
.cache
|
||||||
.gdb_history
|
.gdb_history
|
||||||
cockatrice/resources/config/qtlogging.ini
|
cockatrice/resources/config/qtlogging.ini
|
||||||
|
docs/
|
||||||
|
|||||||
4
.gitmodules
vendored
@@ -1,3 +1,7 @@
|
|||||||
[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
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ option(WITH_ORACLE "build oracle" ON)
|
|||||||
option(WITH_DBCONVERTER "build dbconverter" ON)
|
option(WITH_DBCONVERTER "build dbconverter" ON)
|
||||||
# Compile tests
|
# Compile tests
|
||||||
option(TEST "build tests" OFF)
|
option(TEST "build tests" OFF)
|
||||||
|
# Use vcpkg regardless of OS
|
||||||
|
option(USE_VCPKG "Use vcpkg regardless of OS" OFF)
|
||||||
|
|
||||||
# Default to "Release" build type
|
# Default to "Release" build type
|
||||||
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
|
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
|
||||||
@@ -48,8 +50,8 @@ if(USE_CCACHE)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32 OR USE_VCPKG)
|
||||||
# Use vcpkg toolchain on Windows
|
# Use vcpkg toolchain on Windows (and on macOS in CI)
|
||||||
set(CMAKE_TOOLCHAIN_FILE
|
set(CMAKE_TOOLCHAIN_FILE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake
|
${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||||
CACHE STRING "Vcpkg toolchain file"
|
CACHE STRING "Vcpkg toolchain file"
|
||||||
@@ -301,6 +303,7 @@ if(UNIX)
|
|||||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice")
|
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice")
|
||||||
if(Qt6_FOUND)
|
if(Qt6_FOUND)
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins")
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libqt6sql6-mysql") # for connecting servatrice to a mysql db
|
||||||
elseif(Qt5_FOUND)
|
elseif(Qt5_FOUND)
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
|
||||||
endif()
|
endif()
|
||||||
@@ -325,7 +328,19 @@ endif()
|
|||||||
|
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|
||||||
add_subdirectory(common)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_interfaces ${CMAKE_BINARY_DIR}/libcockatrice_interfaces)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_protocol ${CMAKE_BINARY_DIR}/libcockatrice_protocol)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_network ${CMAKE_BINARY_DIR}/libcockatrice_network)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_deck_list ${CMAKE_BINARY_DIR}/libcockatrice_deck_list)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_rng ${CMAKE_BINARY_DIR}/libcockatrice_rng)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_card ${CMAKE_BINARY_DIR}/libcockatrice_card)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_utility ${CMAKE_BINARY_DIR}/libcockatrice_utility)
|
||||||
|
if(WITH_ORACLE OR WITH_CLIENT)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_settings ${CMAKE_BINARY_DIR}/libcockatrice_settings)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_models ${CMAKE_BINARY_DIR}/libcockatrice_models)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_filters ${CMAKE_BINARY_DIR}/libcockatrice_filters)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WITH_SERVER)
|
if(WITH_SERVER)
|
||||||
add_subdirectory(servatrice)
|
add_subdirectory(servatrice)
|
||||||
set(CPACK_INSTALL_CMAKE_PROJECTS "Servatrice;Servatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
set(CPACK_INSTALL_CMAKE_PROJECTS "Servatrice;Servatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
||||||
|
|||||||
33
Dockerfile
@@ -1,8 +1,9 @@
|
|||||||
FROM ubuntu:24.04
|
# -------- Build Stage --------
|
||||||
|
FROM ubuntu:24.04 AS build
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y\
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
build-essential \
|
build-essential \
|
||||||
cmake \
|
cmake \
|
||||||
file \
|
file \
|
||||||
@@ -16,20 +17,28 @@ RUN apt-get update && apt-get install -y\
|
|||||||
qt6-tools-dev \
|
qt6-tools-dev \
|
||||||
qt6-tools-dev-tools
|
qt6-tools-dev-tools
|
||||||
|
|
||||||
COPY ./CMakeLists.txt ./LICENSE ./README.md /home/servatrice/code/
|
WORKDIR /src
|
||||||
COPY ./cmake /home/servatrice/code/cmake
|
COPY . .
|
||||||
COPY ./common /home/servatrice/code/common
|
RUN mkdir build && cd build && \
|
||||||
COPY ./servatrice /home/servatrice/code/servatrice
|
cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install
|
||||||
|
|
||||||
WORKDIR /home/servatrice/code
|
|
||||||
|
|
||||||
WORKDIR build
|
# -------- Runtime Stage (clean) --------
|
||||||
RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 &&\
|
FROM ubuntu:24.04
|
||||||
make &&\
|
|
||||||
make install
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libprotobuf32t64 \
|
||||||
|
libqt6sql6-mysql \
|
||||||
|
libqt6websockets6 \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Only copy installed binaries, not source
|
||||||
|
COPY --from=build /usr/local /usr/local
|
||||||
|
|
||||||
WORKDIR /home/servatrice
|
WORKDIR /home/servatrice
|
||||||
|
|
||||||
EXPOSE 4748
|
EXPOSE 4748
|
||||||
|
|
||||||
ENTRYPOINT [ "servatrice", "--log-to-console" ]
|
ENTRYPOINT [ "servatrice", "--log-to-console" ]
|
||||||
|
|||||||
9
LICENSE
@@ -2,7 +2,7 @@
|
|||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
<https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
@@ -304,8 +304,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
@@ -329,8 +328,8 @@ necessary. Here is a sample; alter the names:
|
|||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
<signature of Moe Ghoul>, 1 April 1989
|
||||||
Ty Coon, President of Vice
|
Moe Ghoul, President of Vice
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
This General Public License does not permit incorporating your program into
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
|||||||
11
README.md
@@ -46,7 +46,8 @@ Latest <kbd>beta</kbd> version:
|
|||||||
|
|
||||||
- [Magic-Token](https://github.com/Cockatrice/Magic-Token): MtG token data to use in Cockatrice
|
- [Magic-Token](https://github.com/Cockatrice/Magic-Token): MtG token data to use in Cockatrice
|
||||||
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Script to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) to use in Cockatrice
|
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Script to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) to use in Cockatrice
|
||||||
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official webpage of the Cockatrice project
|
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official Cockatrice webpage
|
||||||
|
- [Cockatrice @Flathub](https://github.com/flathub/io.github.Cockatrice.cockatrice): Configuration for our Linux `flatpak` package
|
||||||
|
|
||||||
|
|
||||||
# Community Resources [](https://discord.gg/3Z9yzmA)
|
# Community Resources [](https://discord.gg/3Z9yzmA)
|
||||||
@@ -54,6 +55,7 @@ Latest <kbd>beta</kbd> version:
|
|||||||
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 projet 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 Code Documentation](https://cockatrice.github.io/docs)
|
||||||
- [Official Discord](https://discord.gg/3Z9yzmA)
|
- [Official Discord](https://discord.gg/3Z9yzmA)
|
||||||
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
|
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
|
||||||
|
|
||||||
@@ -75,10 +77,15 @@ This tag is used for issues that we are looking for somebody to pick up. Often t
|
|||||||
For both tags, we're willing to provide help to contributors in showing them where and how they can make changes, as well as code reviews for submitted changes.<br>
|
For both tags, we're willing to provide help to contributors in showing them where and how they can make changes, as well as code reviews for submitted changes.<br>
|
||||||
We'll happily advice on how best to implement a feature, or we can show you where the codebase is doing something similar before you get too far along - put a note on an issue you want to discuss more on!
|
We'll happily advice on how best to implement a feature, or we can show you where the codebase is doing something similar before you get too far along - put a note on an issue you want to discuss more on!
|
||||||
|
|
||||||
|
You can also have a look at our `Todo List` in our [Code Documentation](https://cockatrice.github.io/docs) or search the repo for [`\todo` comments](https://github.com/search?q=repo%3ACockatrice%2FCockatrice%20%5Ctodo&type=code).
|
||||||
|
|
||||||
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation. We encourage you to improve the documentation by suggesting edits based on this guide.
|
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation. We encourage you to improve the documentation by suggesting edits based on this guide.
|
||||||
|
|
||||||
|
#### Repository Activity
|
||||||
|

|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><b>Kudos to our amazing contributors ❤️</b></summary>
|
<summary><b>Kudos to all our amazing contributors ❤️</b></summary>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/Cockatrice/Cockatrice/graphs/contributors">
|
<a href="https://github.com/Cockatrice/Cockatrice/graphs/contributors">
|
||||||
<img src="https://contrib.rocks/image?repo=Cockatrice/Cockatrice" />
|
<img src="https://contrib.rocks/image?repo=Cockatrice/Cockatrice" />
|
||||||
|
|||||||
@@ -115,4 +115,7 @@ string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" ORACLE_QT_MO
|
|||||||
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" DB_CONVERTER_QT_MODULES "${_DBCONVERTER_NEEDED}")
|
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" DB_CONVERTER_QT_MODULES "${_DBCONVERTER_NEEDED}")
|
||||||
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" TEST_QT_MODULES "${_TEST_NEEDED}")
|
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" TEST_QT_MODULES "${_TEST_NEEDED}")
|
||||||
|
|
||||||
|
# Core-only export (useful for headless libs)
|
||||||
|
set(QT_CORE_MODULE "${COCKATRICE_QT_VERSION_NAME}::Core")
|
||||||
|
|
||||||
message(STATUS "Found Qt ${${COCKATRICE_QT_VERSION_NAME}_VERSION} at: ${${COCKATRICE_QT_VERSION_NAME}_DIR}")
|
message(STATUS "Found Qt ${${COCKATRICE_QT_VERSION_NAME}_VERSION} at: ${${COCKATRICE_QT_VERSION_NAME}_DIR}")
|
||||||
|
|||||||
@@ -7,253 +7,286 @@ project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${
|
|||||||
set(cockatrice_SOURCES
|
set(cockatrice_SOURCES
|
||||||
${VERSION_STRING_CPP}
|
${VERSION_STRING_CPP}
|
||||||
# sort by alphabetical order, so that there is no debate about where to add new sources to the list
|
# sort by alphabetical order, so that there is no debate about where to add new sources to the list
|
||||||
src/client/game_logic/abstract_client.cpp
|
src/client/network/update/client/update_downloader.cpp
|
||||||
src/client/game_logic/key_signals.cpp
|
src/client/network/interfaces/deck_stats_interface.cpp
|
||||||
src/client/get_text_with_max.cpp
|
src/client/network/interfaces/tapped_out_interface.cpp
|
||||||
src/client/menus/deck_editor/deck_editor_menu.cpp
|
src/client/network/parsers/deck_link_to_api_transformer.cpp
|
||||||
src/client/network/client_update_checker.cpp
|
src/client/network/update/client/client_update_checker.cpp
|
||||||
src/client/network/release_channel.cpp
|
src/client/network/update/client/release_channel.cpp
|
||||||
src/client/network/replay_timeline_widget.cpp
|
src/client/network/update/card_spoiler/spoiler_background_updater.cpp
|
||||||
src/client/network/sets_model.cpp
|
|
||||||
src/client/network/spoiler_background_updater.cpp
|
|
||||||
src/client/sound_engine.cpp
|
src/client/sound_engine.cpp
|
||||||
src/client/tabs/abstract_tab_deck_editor.cpp
|
src/client/settings/cache_settings.cpp
|
||||||
src/client/tabs/api/edhrec/tab_edhrec.cpp
|
src/client/settings/card_counter_settings.cpp
|
||||||
src/client/tabs/api/edhrec/tab_edhrec_main.cpp
|
src/client/settings/shortcut_treeview.cpp
|
||||||
src/client/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp
|
src/client/settings/shortcuts_settings.cpp
|
||||||
src/client/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp
|
src/interface/deck_loader/card_node_function.cpp
|
||||||
src/client/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp
|
src/interface/deck_loader/deck_file_format.cpp
|
||||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
|
src/interface/deck_loader/deck_loader.cpp
|
||||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
|
src/interface/deck_loader/loaded_deck.cpp
|
||||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp
|
src/interface/widgets/dialogs/dlg_connect.cpp
|
||||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
|
src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp
|
||||||
src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
|
src/interface/widgets/dialogs/dlg_create_game.cpp
|
||||||
src/client/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp
|
src/interface/widgets/dialogs/dlg_default_tags_editor.cpp
|
||||||
src/client/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp
|
src/interface/widgets/dialogs/dlg_edit_avatar.cpp
|
||||||
src/client/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp
|
src/interface/widgets/dialogs/dlg_edit_password.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
|
src/interface/widgets/dialogs/dlg_edit_tokens.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp
|
src/interface/widgets/dialogs/dlg_edit_user.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp
|
src/interface/widgets/dialogs/dlg_filter_games.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp
|
src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp
|
src/interface/widgets/dialogs/dlg_forgot_password_request.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp
|
src/interface/widgets/dialogs/dlg_forgot_password_reset.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp
|
src/interface/widgets/dialogs/dlg_load_deck.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp
|
src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
|
src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
|
src/interface/widgets/dialogs/dlg_load_remote_deck.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp
|
src/interface/widgets/dialogs/dlg_manage_sets.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp
|
src/interface/widgets/dialogs/dlg_register.cpp
|
||||||
src/client/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp
|
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
|
||||||
src/client/tabs/tab.cpp
|
src/interface/widgets/dialogs/dlg_settings.cpp
|
||||||
src/client/tabs/tab_account.cpp
|
src/interface/widgets/dialogs/dlg_startup_card_check.cpp
|
||||||
src/client/tabs/tab_admin.cpp
|
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
||||||
src/client/tabs/tab_deck_editor.cpp
|
src/interface/widgets/dialogs/dlg_update.cpp
|
||||||
src/client/tabs/tab_deck_storage.cpp
|
src/interface/widgets/dialogs/dlg_view_log.cpp
|
||||||
src/client/tabs/tab_game.cpp
|
src/interface/widgets/dialogs/tip_of_the_day.cpp
|
||||||
src/client/tabs/tab_logs.cpp
|
src/filters/deck_filter_string.cpp
|
||||||
src/client/tabs/tab_message.cpp
|
src/filters/filter_builder.cpp
|
||||||
src/client/tabs/tab_replays.cpp
|
src/filters/filter_tree_model.cpp
|
||||||
src/client/tabs/tab_room.cpp
|
src/filters/syntax_help.cpp
|
||||||
src/client/tabs/tab_server.cpp
|
src/game/abstract_game.cpp
|
||||||
src/client/tabs/tab_supervisor.cpp
|
|
||||||
src/client/tabs/tab_visual_database_display.cpp
|
|
||||||
src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
|
|
||||||
src/client/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp
|
|
||||||
src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
|
||||||
src/client/tapped_out_interface.cpp
|
|
||||||
src/client/translate_counter_name.cpp
|
|
||||||
src/client/ui/layouts/flow_layout.cpp
|
|
||||||
src/client/ui/layouts/overlap_layout.cpp
|
|
||||||
src/client/ui/line_edit_completer.cpp
|
|
||||||
src/client/ui/phases_toolbar.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader_local.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader_request_status_display_widget.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader_status_bar.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader_worker.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader_worker_work.cpp
|
|
||||||
src/client/ui/picture_loader/picture_to_load.cpp
|
|
||||||
src/client/ui/pixel_map_generator.cpp
|
|
||||||
src/client/ui/theme_manager.cpp
|
|
||||||
src/client/ui/tip_of_the_day.cpp
|
|
||||||
src/client/ui/widgets/cards/additional_info/color_identity_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/additional_info/mana_cost_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_group_display_widgets/flat_card_group_display_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_group_display_widgets/overlapped_card_group_display_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_display_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_frame_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_picture_enlarged_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_picture_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_text_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_size_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_analytics/mana_base_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_analytics/mana_devotion_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/general/display/banner_widget.cpp
|
|
||||||
src/client/ui/widgets/general/display/bar_widget.cpp
|
|
||||||
src/client/ui/widgets/general/display/dynamic_font_size_label.cpp
|
|
||||||
src/client/ui/widgets/general/display/dynamic_font_size_push_button.cpp
|
|
||||||
src/client/ui/widgets/general/display/labeled_input.cpp
|
|
||||||
src/client/ui/widgets/general/display/percent_bar_widget.cpp
|
|
||||||
src/client/ui/widgets/general/display/shadow_background_label.cpp
|
|
||||||
src/client/ui/widgets/general/layout_containers/flow_widget.cpp
|
|
||||||
src/client/ui/widgets/general/layout_containers/overlap_control_widget.cpp
|
|
||||||
src/client/ui/widgets/general/layout_containers/overlap_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/all_zones_card_amount_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/card_amount_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_display_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_search_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_selection_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_sorting_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/set_name_and_collectors_number_display_widget.cpp
|
|
||||||
src/client/ui/widgets/quick_settings/settings_button_widget.cpp
|
|
||||||
src/client/ui/widgets/quick_settings/settings_popup_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
|
|
||||||
src/client/ui/window_main.cpp
|
|
||||||
src/client/update_downloader.cpp
|
|
||||||
src/deck/custom_line_edit.cpp
|
|
||||||
src/deck/deck_list_model.cpp
|
|
||||||
src/deck/deck_loader.cpp
|
|
||||||
src/deck/deck_stats_interface.cpp
|
|
||||||
src/dialogs/dlg_connect.cpp
|
|
||||||
src/dialogs/dlg_convert_deck_to_cod_format.cpp
|
|
||||||
src/dialogs/dlg_create_game.cpp
|
|
||||||
src/dialogs/dlg_create_token.cpp
|
|
||||||
src/dialogs/dlg_default_tags_editor.cpp
|
|
||||||
src/dialogs/dlg_edit_avatar.cpp
|
|
||||||
src/dialogs/dlg_edit_password.cpp
|
|
||||||
src/dialogs/dlg_edit_tokens.cpp
|
|
||||||
src/dialogs/dlg_edit_user.cpp
|
|
||||||
src/dialogs/dlg_filter_games.cpp
|
|
||||||
src/dialogs/dlg_forgot_password_challenge.cpp
|
|
||||||
src/dialogs/dlg_forgot_password_request.cpp
|
|
||||||
src/dialogs/dlg_forgot_password_reset.cpp
|
|
||||||
src/dialogs/dlg_load_deck.cpp
|
|
||||||
src/dialogs/dlg_load_deck_from_clipboard.cpp
|
|
||||||
src/dialogs/dlg_load_remote_deck.cpp
|
|
||||||
src/dialogs/dlg_manage_sets.cpp
|
|
||||||
src/dialogs/dlg_move_top_cards_until.cpp
|
|
||||||
src/dialogs/dlg_register.cpp
|
|
||||||
src/dialogs/dlg_roll_dice.cpp
|
|
||||||
src/dialogs/dlg_select_set_for_cards.cpp
|
|
||||||
src/dialogs/dlg_settings.cpp
|
|
||||||
src/dialogs/dlg_tip_of_the_day.cpp
|
|
||||||
src/dialogs/dlg_update.cpp
|
|
||||||
src/dialogs/dlg_view_log.cpp
|
|
||||||
src/game/board/abstract_card_drag_item.cpp
|
src/game/board/abstract_card_drag_item.cpp
|
||||||
src/game/board/abstract_card_item.cpp
|
src/game/board/abstract_card_item.cpp
|
||||||
src/game/board/abstract_counter.cpp
|
src/game/board/abstract_counter.cpp
|
||||||
src/game/board/abstract_graphics_item.cpp
|
|
||||||
src/game/board/arrow_item.cpp
|
src/game/board/arrow_item.cpp
|
||||||
src/game/board/arrow_target.cpp
|
src/game/board/arrow_target.cpp
|
||||||
src/game/board/card_drag_item.cpp
|
src/game/board/card_drag_item.cpp
|
||||||
src/game/board/card_item.cpp
|
src/game/board/card_item.cpp
|
||||||
src/game/board/card_list.cpp
|
src/game/board/card_list.cpp
|
||||||
src/game/board/counter_general.cpp
|
src/game/board/counter_general.cpp
|
||||||
src/game/cards/card_completer_proxy_model.cpp
|
src/game/board/translate_counter_name.cpp
|
||||||
src/game/cards/card_database.cpp
|
|
||||||
src/game/cards/card_database_manager.cpp
|
|
||||||
src/game/cards/card_database_model.cpp
|
|
||||||
src/game/cards/card_database_parser/card_database_parser.cpp
|
|
||||||
src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
|
||||||
src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
|
||||||
src/game/cards/card_info.cpp
|
|
||||||
src/game/cards/card_search_model.cpp
|
|
||||||
src/game/deckview/deck_view.cpp
|
src/game/deckview/deck_view.cpp
|
||||||
src/game/deckview/deck_view_container.cpp
|
src/game/deckview/deck_view_container.cpp
|
||||||
src/game/filters/deck_filter_string.cpp
|
src/game/deckview/tabbed_deck_view_container.cpp
|
||||||
src/game/filters/filter_builder.cpp
|
src/game/dialogs/dlg_create_token.cpp
|
||||||
src/game/filters/filter_card.cpp
|
src/game/dialogs/dlg_move_top_cards_until.cpp
|
||||||
src/game/filters/filter_string.cpp
|
src/game/dialogs/dlg_roll_dice.cpp
|
||||||
src/game/filters/filter_tree.cpp
|
src/game/game.cpp
|
||||||
src/game/filters/filter_tree_model.cpp
|
src/game/game_event_handler.cpp
|
||||||
src/game/filters/syntax_help.cpp
|
src/game/game_meta_info.cpp
|
||||||
src/game/game_scene.cpp
|
src/game/game_scene.cpp
|
||||||
src/game/game_selector.cpp
|
src/game/game_state.cpp
|
||||||
src/game/game_view.cpp
|
src/game/game_view.cpp
|
||||||
src/game/games_model.cpp
|
|
||||||
src/game/hand_counter.cpp
|
src/game/hand_counter.cpp
|
||||||
|
src/game/log/message_log_widget.cpp
|
||||||
src/game/phase.cpp
|
src/game/phase.cpp
|
||||||
|
src/game/phases_toolbar.cpp
|
||||||
|
src/game/player/menu/card_menu.cpp
|
||||||
|
src/game/player/menu/custom_zone_menu.cpp
|
||||||
|
src/game/player/menu/grave_menu.cpp
|
||||||
|
src/game/player/menu/hand_menu.cpp
|
||||||
|
src/game/player/menu/library_menu.cpp
|
||||||
|
src/game/player/menu/move_menu.cpp
|
||||||
|
src/game/player/menu/player_menu.cpp
|
||||||
|
src/game/player/menu/pt_menu.cpp
|
||||||
|
src/game/player/menu/rfg_menu.cpp
|
||||||
|
src/game/player/menu/say_menu.cpp
|
||||||
|
src/game/player/menu/sideboard_menu.cpp
|
||||||
|
src/game/player/menu/utility_menu.cpp
|
||||||
src/game/player/player.cpp
|
src/game/player/player.cpp
|
||||||
|
src/game/player/player_actions.cpp
|
||||||
|
src/game/player/player_area.cpp
|
||||||
|
src/game/player/player_event_handler.cpp
|
||||||
|
src/game/player/player_graphics_item.cpp
|
||||||
|
src/game/player/player_info.cpp
|
||||||
src/game/player/player_list_widget.cpp
|
src/game/player/player_list_widget.cpp
|
||||||
|
src/game/player/player_manager.cpp
|
||||||
src/game/player/player_target.cpp
|
src/game/player/player_target.cpp
|
||||||
|
src/game/replay.cpp
|
||||||
src/game/zones/card_zone.cpp
|
src/game/zones/card_zone.cpp
|
||||||
src/game/zones/hand_zone.cpp
|
src/game/zones/hand_zone.cpp
|
||||||
|
src/game/zones/logic/card_zone_logic.cpp
|
||||||
|
src/game/zones/logic/hand_zone_logic.cpp
|
||||||
|
src/game/zones/logic/pile_zone_logic.cpp
|
||||||
|
src/game/zones/logic/stack_zone_logic.cpp
|
||||||
|
src/game/zones/logic/table_zone_logic.cpp
|
||||||
|
src/game/zones/logic/view_zone_logic.cpp
|
||||||
src/game/zones/pile_zone.cpp
|
src/game/zones/pile_zone.cpp
|
||||||
src/game/zones/select_zone.cpp
|
src/game/zones/select_zone.cpp
|
||||||
src/game/zones/stack_zone.cpp
|
src/game/zones/stack_zone.cpp
|
||||||
src/game/zones/table_zone.cpp
|
src/game/zones/table_zone.cpp
|
||||||
src/game/zones/view_zone.cpp
|
src/game/zones/view_zone.cpp
|
||||||
src/game/zones/view_zone_widget.cpp
|
src/game/zones/view_zone_widget.cpp
|
||||||
|
src/game_graphics/board/abstract_graphics_item.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_loader.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_loader_local.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_loader_status_bar.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_loader_worker.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_loader_worker_work.cpp
|
||||||
|
src/interface/card_picture_loader/card_picture_to_load.cpp
|
||||||
|
src/interface/layouts/flow_layout.cpp
|
||||||
|
src/interface/layouts/overlap_layout.cpp
|
||||||
|
src/interface/widgets/utility/line_edit_completer.cpp
|
||||||
|
src/interface/pixel_map_generator.cpp
|
||||||
|
src/interface/theme_manager.cpp
|
||||||
|
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
|
||||||
|
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
|
||||||
|
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_group_display_widgets/flat_card_group_display_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_group_display_widgets/overlapped_card_group_display_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_display_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_frame_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_picture_art_crop_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_picture_enlarged_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_picture_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_info_text_widget.cpp
|
||||||
|
src/interface/widgets/cards/card_size_widget.cpp
|
||||||
|
src/interface/widgets/cards/deck_card_zone_display_widget.cpp
|
||||||
|
src/interface/widgets/cards/deck_preview_card_picture_widget.cpp
|
||||||
|
src/interface/widgets/deck_analytics/deck_analytics_widget.cpp
|
||||||
|
src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp
|
||||||
|
src/interface/widgets/deck_analytics/mana_base_widget.cpp
|
||||||
|
src/interface/widgets/deck_analytics/mana_curve_widget.cpp
|
||||||
|
src/interface/widgets/deck_analytics/mana_devotion_widget.cpp
|
||||||
|
src/interface/widgets/deck_editor/deck_list_history_manager_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_deck_dock_widget.cpp
|
||||||
|
src/interface/widgets/deck_editor/deck_editor_filter_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/general/background_sources.cpp
|
||||||
|
src/interface/widgets/general/display/background_plate_widget.cpp
|
||||||
|
src/interface/widgets/general/display/banner_widget.cpp
|
||||||
|
src/interface/widgets/general/display/bar_widget.cpp
|
||||||
|
src/interface/widgets/general/display/color_bar.cpp
|
||||||
|
src/interface/widgets/general/display/dynamic_font_size_label.cpp
|
||||||
|
src/interface/widgets/general/display/dynamic_font_size_push_button.cpp
|
||||||
|
src/interface/widgets/general/display/labeled_input.cpp
|
||||||
|
src/interface/widgets/general/display/percent_bar_widget.cpp
|
||||||
|
src/interface/widgets/general/display/shadow_background_label.cpp
|
||||||
|
src/interface/widgets/general/home_styled_button.cpp
|
||||||
|
src/interface/widgets/general/home_widget.cpp
|
||||||
|
src/interface/widgets/general/layout_containers/flow_widget.cpp
|
||||||
|
src/interface/widgets/general/layout_containers/overlap_control_widget.cpp
|
||||||
|
src/interface/widgets/general/layout_containers/overlap_widget.cpp
|
||||||
|
src/interface/widgets/menus/deck_editor_menu.cpp
|
||||||
|
src/interface/widgets/printing_selector/all_zones_card_amount_widget.cpp
|
||||||
|
src/interface/widgets/printing_selector/card_amount_widget.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_overlay_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_sorting_widget.cpp
|
||||||
|
src/interface/widgets/printing_selector/set_name_and_collectors_number_display_widget.cpp
|
||||||
|
src/interface/widgets/quick_settings/settings_button_widget.cpp
|
||||||
|
src/interface/widgets/quick_settings/settings_popup_widget.cpp
|
||||||
|
src/interface/widgets/replay/replay_manager.cpp
|
||||||
|
src/interface/widgets/replay/replay_timeline_widget.cpp
|
||||||
|
src/interface/widgets/server/chat_view/chat_view.cpp
|
||||||
|
src/interface/widgets/server/game_selector.cpp
|
||||||
|
src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
|
||||||
|
src/interface/widgets/server/games_model.cpp
|
||||||
|
src/interface/widgets/server/handle_public_servers.cpp
|
||||||
|
src/interface/widgets/server/remote/remote_decklist_tree_widget.cpp
|
||||||
|
src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp
|
||||||
|
src/interface/widgets/server/user/user_context_menu.cpp
|
||||||
|
src/interface/widgets/server/user/user_info_box.cpp
|
||||||
|
src/interface/widgets/server/user/user_info_connection.cpp
|
||||||
|
src/interface/widgets/server/user/user_list_manager.cpp
|
||||||
|
src/interface/widgets/server/user/user_list_widget.cpp
|
||||||
|
src/interface/widgets/utility/custom_line_edit.cpp
|
||||||
|
src/interface/widgets/utility/get_text_with_max.cpp
|
||||||
|
src/interface/widgets/utility/sequence_edit.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_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_name_filter_widget.cpp
|
||||||
|
src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
|
||||||
|
src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_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_deck_editor/visual_deck_display_options_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_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
|
||||||
|
src/interface/window_main.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/server/chat_view/chat_view.cpp
|
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
|
||||||
src/server/handle_public_servers.cpp
|
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
|
||||||
src/server/local_client.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
|
||||||
src/server/local_server.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h
|
||||||
src/server/local_server_interface.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
|
||||||
src/server/message_log_widget.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
|
||||||
src/server/pending_command.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
|
||||||
src/server/remote/remote_client.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp
|
||||||
src/server/remote/remote_decklist_tree_widget.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp
|
||||||
src/server/remote/remote_replay_list_tree_widget.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp
|
||||||
src/server/user/user_context_menu.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp
|
||||||
src/server/user/user_info_box.cpp
|
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
|
||||||
src/server/user/user_info_connection.cpp
|
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
|
||||||
src/server/user/user_list_manager.cpp
|
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
|
||||||
src/server/user/user_list_widget.cpp
|
src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp
|
||||||
src/settings/cache_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
|
||||||
src/settings/card_counter_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
|
||||||
src/settings/card_database_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
|
||||||
src/settings/card_override_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp
|
||||||
src/settings/debug_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp
|
||||||
src/settings/download_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp
|
||||||
src/settings/game_filters_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp
|
||||||
src/settings/layouts_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp
|
||||||
src/settings/message_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp
|
||||||
src/settings/recents_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp
|
||||||
src/settings/servers_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp
|
||||||
src/settings/settings_manager.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp
|
||||||
src/settings/shortcut_treeview.cpp
|
src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp
|
||||||
src/settings/shortcuts_settings.cpp
|
src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp
|
||||||
src/utility/card_info_comparator.cpp
|
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
|
||||||
src/utility/levenshtein.cpp
|
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
|
||||||
src/utility/logger.cpp
|
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp
|
||||||
src/utility/sequence_edit.cpp
|
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp
|
||||||
|
src/interface/widgets/tabs/tab.cpp
|
||||||
|
src/interface/widgets/tabs/tab_account.cpp
|
||||||
|
src/interface/widgets/tabs/tab_admin.cpp
|
||||||
|
src/interface/widgets/tabs/tab_deck_editor.cpp
|
||||||
|
src/interface/widgets/tabs/tab_deck_storage.cpp
|
||||||
|
src/interface/widgets/tabs/tab_game.cpp
|
||||||
|
src/interface/widgets/tabs/tab_home.cpp
|
||||||
|
src/interface/widgets/tabs/tab_logs.cpp
|
||||||
|
src/interface/widgets/tabs/tab_message.cpp
|
||||||
|
src/interface/widgets/tabs/tab_replays.cpp
|
||||||
|
src/interface/widgets/tabs/tab_room.cpp
|
||||||
|
src/interface/widgets/tabs/tab_server.cpp
|
||||||
|
src/interface/widgets/tabs/tab_supervisor.cpp
|
||||||
|
src/interface/widgets/tabs/tab_visual_database_display.cpp
|
||||||
|
src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
|
||||||
|
src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp
|
||||||
|
src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
||||||
|
src/interface/key_signals.cpp
|
||||||
|
src/interface/logger.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(sounds)
|
add_subdirectory(sounds)
|
||||||
@@ -265,15 +298,23 @@ configure_file(
|
|||||||
set(cockatrice_RESOURCES cockatrice.qrc)
|
set(cockatrice_RESOURCES cockatrice.qrc)
|
||||||
|
|
||||||
if(UPDATE_TRANSLATIONS)
|
if(UPDATE_TRANSLATIONS)
|
||||||
|
# Cockatrice main sources
|
||||||
file(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp
|
file(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp
|
||||||
${CMAKE_SOURCE_DIR}/cockatrice/src/*.h
|
${CMAKE_SOURCE_DIR}/cockatrice/src/*.h
|
||||||
)
|
)
|
||||||
file(GLOB_RECURSE translate_common_SRCS ${CMAKE_SOURCE_DIR}/common/*.cpp ${CMAKE_SOURCE_DIR}/common/*.h)
|
|
||||||
set(translate_SRCS ${translate_cockatrice_SRCS} ${translate_common_SRCS})
|
# All libcockatrice_* libraries (recursively)
|
||||||
|
file(GLOB_RECURSE translate_lib_SRCS ${CMAKE_SOURCE_DIR}/libcockatrice_*/**/*.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/libcockatrice_*/**/*.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# Combine all sources for translation
|
||||||
|
set(translate_SRCS ${translate_cockatrice_SRCS} ${translate_lib_SRCS})
|
||||||
|
|
||||||
set(cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/cockatrice_en@source.ts")
|
set(cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/cockatrice_en@source.ts")
|
||||||
else()
|
else()
|
||||||
file(GLOB cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts")
|
file(GLOB cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts")
|
||||||
endif(UPDATE_TRANSLATIONS)
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
|
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
|
||||||
@@ -303,12 +344,6 @@ set(DESKTOPDIR
|
|||||||
CACHE STRING "desktop file destination"
|
CACHE STRING "desktop file destination"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Include directories
|
|
||||||
include_directories(../common)
|
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIR})
|
|
||||||
include_directories(${CMAKE_BINARY_DIR}/common)
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
set(COCKATRICE_MAC_QM_INSTALL_DIR "cockatrice.app/Contents/Resources/translations")
|
set(COCKATRICE_MAC_QM_INSTALL_DIR "cockatrice.app/Contents/Resources/translations")
|
||||||
set(COCKATRICE_UNIX_QM_INSTALL_DIR "share/cockatrice/translations")
|
set(COCKATRICE_UNIX_QM_INSTALL_DIR "share/cockatrice/translations")
|
||||||
set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations")
|
set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations")
|
||||||
@@ -348,9 +383,31 @@ elseif(Qt5_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(Qt5_FOUND)
|
if(Qt5_FOUND)
|
||||||
target_link_libraries(cockatrice cockatrice_common ${COCKATRICE_QT_MODULES})
|
target_link_libraries(
|
||||||
|
cockatrice
|
||||||
|
libcockatrice_card
|
||||||
|
libcockatrice_deck_list
|
||||||
|
libcockatrice_filters
|
||||||
|
libcockatrice_utility
|
||||||
|
libcockatrice_network
|
||||||
|
libcockatrice_models
|
||||||
|
libcockatrice_rng
|
||||||
|
libcockatrice_settings
|
||||||
|
${COCKATRICE_QT_MODULES}
|
||||||
|
)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(cockatrice PUBLIC cockatrice_common ${COCKATRICE_QT_MODULES})
|
target_link_libraries(
|
||||||
|
cockatrice
|
||||||
|
PUBLIC libcockatrice_card
|
||||||
|
libcockatrice_deck_list
|
||||||
|
libcockatrice_filters
|
||||||
|
libcockatrice_utility
|
||||||
|
libcockatrice_network
|
||||||
|
libcockatrice_models
|
||||||
|
libcockatrice_rng
|
||||||
|
libcockatrice_settings
|
||||||
|
${COCKATRICE_QT_MODULES}
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
|||||||
@@ -7,11 +7,14 @@
|
|||||||
|
|
||||||
<file>resources/icons/arrow_bottom_green.svg</file>
|
<file>resources/icons/arrow_bottom_green.svg</file>
|
||||||
<file>resources/icons/arrow_down_green.svg</file>
|
<file>resources/icons/arrow_down_green.svg</file>
|
||||||
|
<file>resources/icons/arrow_history.svg</file>
|
||||||
<file>resources/icons/arrow_left_green.svg</file>
|
<file>resources/icons/arrow_left_green.svg</file>
|
||||||
|
<file>resources/icons/arrow_redo.svg</file>
|
||||||
<file>resources/icons/arrow_right_blue.svg</file>
|
<file>resources/icons/arrow_right_blue.svg</file>
|
||||||
<file>resources/icons/arrow_right_green.svg</file>
|
<file>resources/icons/arrow_right_green.svg</file>
|
||||||
<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/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>
|
||||||
@@ -25,6 +28,7 @@
|
|||||||
<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/pencil.svg</file>
|
<file>resources/icons/pencil.svg</file>
|
||||||
|
<file>resources/icons/pin.svg</file>
|
||||||
<file>resources/icons/player.svg</file>
|
<file>resources/icons/player.svg</file>
|
||||||
<file>resources/icons/ready_start.svg</file>
|
<file>resources/icons/ready_start.svg</file>
|
||||||
<file>resources/icons/reload.svg</file>
|
<file>resources/icons/reload.svg</file>
|
||||||
@@ -33,6 +37,7 @@
|
|||||||
<file>resources/icons/scales.svg</file>
|
<file>resources/icons/scales.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/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>
|
||||||
@@ -46,6 +51,8 @@
|
|||||||
<file>resources/icons/mana/U.svg</file>
|
<file>resources/icons/mana/U.svg</file>
|
||||||
<file>resources/icons/mana/W.svg</file>
|
<file>resources/icons/mana/W.svg</file>
|
||||||
|
|
||||||
|
<file>resources/backgrounds/home.png</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>
|
||||||
<file>resources/config/interface.svg</file>
|
<file>resources/config/interface.svg</file>
|
||||||
|
|||||||
BIN
cockatrice/resources/backgrounds/home.png
Normal file
|
After Width: | Height: | Size: 12 MiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 9.9 KiB |
@@ -1,65 +1,72 @@
|
|||||||
[Rules]
|
[Rules]
|
||||||
# The default log level is info
|
# The default log level is info
|
||||||
*.debug = false
|
*.debug = false
|
||||||
|
#*.info = true
|
||||||
|
#*.warning = true
|
||||||
|
#*.critical = true
|
||||||
|
#*.fatal = true
|
||||||
|
|
||||||
# Uncomment a rule to disable logging for that category,
|
# Uncomment a rule to see debug level logs for that category,
|
||||||
# or set .debug = true for that category to see debug level logs
|
# or set <category> = false to disable logging
|
||||||
|
|
||||||
# main = false
|
#main = true
|
||||||
# qt_translator = false
|
#qt_translator = true
|
||||||
# window_main.* = false
|
#window_main.* = true
|
||||||
# release_channel = false
|
#release_channel = true
|
||||||
# spoiler_background_updater = false
|
#spoiler_background_updater = true
|
||||||
# theme_manager = false
|
#theme_manager = true
|
||||||
# sound_engine = false
|
#sound_engine = true
|
||||||
# tapped_out_interface = false
|
#tapped_out_interface = true
|
||||||
|
|
||||||
# tab_game = false
|
#tab_game = true
|
||||||
# tab_message = false
|
#tab_message = true
|
||||||
# tab_supervisor = false
|
#tab_supervisor = true
|
||||||
|
|
||||||
# dlg_edit_avatar = false
|
#dlg_edit_avatar = true
|
||||||
# dlg_settings = false
|
#dlg_load_deck_from_website = true
|
||||||
# dlg_tip_of_the_day = false
|
#dlg_settings = true
|
||||||
# dlg_update = false
|
#dlg_tip_of_the_day = true
|
||||||
|
#dlg_update = true
|
||||||
|
|
||||||
# settings_cache = false
|
#settings_cache = true
|
||||||
# servers_settings = false
|
#servers_settings = true
|
||||||
# shortcuts_settings = false
|
#shortcuts_settings = true
|
||||||
|
|
||||||
# local_client = false
|
#local_client = true
|
||||||
# remote_client = false
|
#remote_client = true
|
||||||
|
|
||||||
# player = false
|
#player = true
|
||||||
# game_scene = false
|
#game_scene = true
|
||||||
# game_scene.player_addition_removal = false
|
#game_scene.player_addition_removal = true
|
||||||
# card_zone = false
|
#card_zone = true
|
||||||
# view_zone = false
|
#view_zone = true
|
||||||
|
|
||||||
# user_info_connection = false
|
#game_event_handler = true
|
||||||
|
|
||||||
# picture_loader = false
|
#user_info_connection = true
|
||||||
# picture_loader.worker = false
|
|
||||||
# picture_loader.card_back_cache_fail = false
|
|
||||||
# picture_loader.picture_to_load = false
|
|
||||||
# deck_loader = false
|
|
||||||
# card_database = false
|
|
||||||
# card_database.loading = false
|
|
||||||
# card_database.loading.success_or_failure = false
|
|
||||||
# cockatrice_xml.* = false
|
|
||||||
# cockatrice_xml.xml_3_parser = false
|
|
||||||
# cockatrice_xml.xml_4_parser = false
|
|
||||||
# card_info = false
|
|
||||||
# card_list = false
|
|
||||||
|
|
||||||
#flow_layout = false
|
#card_picture_loader = true
|
||||||
#flow_widget = false
|
#card_picture_loader.worker = true
|
||||||
#flow_widget.size = false
|
#card_picture_loader.card_back_cache_fail = true
|
||||||
|
#card_picture_loader.picture_to_load = true
|
||||||
|
#deck_loader = true
|
||||||
|
#card_database = true
|
||||||
|
#card_database.loading = true
|
||||||
|
#card_database.loading.success_or_failure = true
|
||||||
|
#cockatrice_xml.* = true
|
||||||
|
#cockatrice_xml.xml_3_parser = true
|
||||||
|
#cockatrice_xml.xml_4_parser = true
|
||||||
|
#card_info = true
|
||||||
|
#card_list = true
|
||||||
|
|
||||||
# card_info_picture_widget = false
|
#flow_layout = true
|
||||||
|
#flow_widget = true
|
||||||
|
#flow_widget.size = true
|
||||||
|
|
||||||
# pixel_map_generator = false
|
#card_info_picture_widget = true
|
||||||
|
|
||||||
# deck_filter_string = false
|
#pixel_map_generator = true
|
||||||
# filter_string = false
|
|
||||||
# syntax_help = false
|
#deck_filter_string = true
|
||||||
|
#filter_string = true
|
||||||
|
#syntax_help = true
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@page deck_search_syntax_help Deck Search Syntax Help
|
||||||
|
|
||||||
## Deck Search Syntax Help
|
## Deck Search Syntax Help
|
||||||
-----
|
-----
|
||||||
The search bar recognizes a set of special commands.<br>
|
The search bar recognizes a set of special commands.<br>
|
||||||
@@ -13,15 +15,18 @@ searches are case insensitive.
|
|||||||
<dd>[n:red n:deck n:wins](#n:red n:deck n:wins) <small>(Any deck with a name containing the words red, deck, and wins)</small></dd>
|
<dd>[n:red n:deck n:wins](#n:red n:deck n:wins) <small>(Any deck with a name containing the words red, deck, and wins)</small></dd>
|
||||||
<dd>[n:"red deck wins"](#n:%22red deck wins%22) <small>(Any deck with a name containing the exact phrase "red deck wins")</small></dd>
|
<dd>[n:"red deck wins"](#n:%22red deck wins%22) <small>(Any deck with a name containing the exact phrase "red deck wins")</small></dd>
|
||||||
|
|
||||||
<dt><u>F</u>ile Name:</dt>
|
<dt><u>F</u>ile <u>N</u>ame:</dt>
|
||||||
<dd>[f:aggro](#f:aggro) <small>(Any deck with a filename containing the word aggro)</small></dd>
|
<dd>[fn:aggro](#fn:aggro) <small>(Any deck with a filename containing the word aggro)</small></dd>
|
||||||
<dd>[f:red f:deck f:wins](#f:red f:deck f:wins) <small>(Any deck with a filename containing the words red, deck, and wins)</small></dd>
|
<dd>[fn:red fn:deck fn:wins](#fn:red fn:deck fn:wins) <small>(Any deck with a filename containing the words red, deck, and wins)</small></dd>
|
||||||
<dd>[f:"red deck wins"](#f:%22red deck wins%22) <small>(Any deck with a filename containing the exact phrase "red deck wins")</small></dd>
|
<dd>[fn:"red deck wins"](#fn:%22red deck wins%22) <small>(Any deck with a filename containing the exact phrase "red deck wins")</small></dd>
|
||||||
|
|
||||||
<dt>Relative <u>P</u>ath (starting from the deck folder):</dt>
|
<dt>Relative <u>P</u>ath (starting from the deck folder):</dt>
|
||||||
<dd>[p:aggro](#p:aggro) <small>(Any deck that has "aggro" somewhere in its relative path)</small></dd>
|
<dd>[p:aggro](#p:aggro) <small>(Any deck that has "aggro" somewhere in its relative path)</small></dd>
|
||||||
<dd>[p:edh/](#p:edh/) <small>(Any deck with "edh/" in its relative path, A.K.A. decks in the "edh" folder)</small></dd>
|
<dd>[p:edh/](#p:edh/) <small>(Any deck with "edh/" in its relative path, A.K.A. decks in the "edh" folder)</small></dd>
|
||||||
|
|
||||||
|
<dt><u>F</u>ormat:</dt>
|
||||||
|
<dd>[f:standard](#f:standard) <small>(Any deck with format set to standard)</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>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@page search_syntax_help Search Syntax Help
|
||||||
|
|
||||||
## Search Syntax Help
|
## Search Syntax Help
|
||||||
-----
|
-----
|
||||||
The search bar recognizes a set of special commands similar to some other card databases.<br>
|
The search bar recognizes a set of special commands similar to some other card databases.<br>
|
||||||
|
|||||||
8
cockatrice/resources/icons/arrow_history.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||||
|
<title>
|
||||||
|
history
|
||||||
|
</title>
|
||||||
|
<path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6H9z"/>
|
||||||
|
<path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 332 B |
40
cockatrice/resources/icons/arrow_redo.svg
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="windows-1252"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px"
|
||||||
|
y="0px" width="485.212px" height="485.212px" viewBox="0 0 485.212 485.212"
|
||||||
|
style="enable-background:new 0 0 485.212 485.212;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M242.607,424.559c-75.252,0-136.468-61.209-136.468-136.465c0-75.252,61.216-136.466,136.468-136.466v90.978 l151.629-121.302L242.607,0v90.978c-108.687,0-197.117,88.432-197.117,197.117c0,108.691,88.43,197.118,197.117,197.118 c108.687,0,197.114-88.427,197.114-197.118h-60.645C379.077,363.35,317.859,424.559,242.607,424.559z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1018 B |
40
cockatrice/resources/icons/arrow_undo.svg
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="windows-1252"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px"
|
||||||
|
y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M256,448c79.406,0,144-64.594,144-144s-64.594-144-144-144v96L96,128L256,0v96c114.688,0,208,93.313,208,208 c0,114.688-93.312,208-208,208c-114.687,0-208-93.312-208-208h64C112,383.406,176.594,448,256,448z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 874 B |
24
cockatrice/resources/icons/pin.svg
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="64" height="64">
|
||||||
|
<g transform="matrix(0 1 -1 0 99.465813 0)" opacity="0.7">
|
||||||
|
<path fill="#000000" fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
stroke="#ffffff"
|
||||||
|
stroke-width="4"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
d="M65.5 62
|
||||||
|
L78 49
|
||||||
|
C73.5 44.5 69.5 42 63 44
|
||||||
|
L45 31 C47 25 46 22 41.5 18
|
||||||
|
L19 41.5
|
||||||
|
C23 45.5 25 46.5 31 45
|
||||||
|
L44 62.5
|
||||||
|
C42.3 69 45 73.5 49 78
|
||||||
|
L61.5 65.5
|
||||||
|
L84 87
|
||||||
|
L87 87
|
||||||
|
L87.5 86.5
|
||||||
|
L87.5 83.5 Z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 736 B |
25
cockatrice/resources/icons/share.svg
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
|
||||||
|
<svg height="800"
|
||||||
|
width="800"
|
||||||
|
version="1.1"
|
||||||
|
id="_x32_"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs id="defs1"/>
|
||||||
|
<style type="text/css"
|
||||||
|
id="style1">
|
||||||
|
.st0{fill:#64C0FF;stroke:black;stroke-width:3;stroke-miterlimit:4;stroke-opacity:1}
|
||||||
|
</style>
|
||||||
|
<g id="g1"
|
||||||
|
transform="matrix(0.87097097,0,0,1.0008579,38.609049,-0.21963163)"
|
||||||
|
style="stroke-width:3.42738;stroke-dasharray:none">
|
||||||
|
<path class="st0"
|
||||||
|
d="M 512,255.995 277.045,65.394 v 103.574 c -17.255,0 -36.408,0 -57.542,0 -208.59,0 -249.35,153.44 -201.394,266.128 9.586,-103.098 142.053,-100.701 237.358,-100.701 7.247,0 14.446,0 21.578,0 v 112.211 z"
|
||||||
|
id="path1"
|
||||||
|
style="stroke-width:20;stroke:#000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -350,11 +350,11 @@
|
|||||||
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
|
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
|
||||||
transform="translate(0,952.36218)"
|
transform="translate(0,952.36218)"
|
||||||
id="right" />
|
id="left" />
|
||||||
<path
|
<path
|
||||||
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
|
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
|
||||||
id="left"
|
id="right"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
<path
|
<path
|
||||||
style="display:inline;fill:url(#linearGradient3);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.77952756;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
style="display:inline;fill:url(#linearGradient3);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.77952756;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -321,11 +321,11 @@
|
|||||||
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
|
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
|
||||||
transform="translate(0,952.36218)"
|
transform="translate(0,952.36218)"
|
||||||
id="right" />
|
id="left" />
|
||||||
<path
|
<path
|
||||||
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
|
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
|
||||||
id="left"
|
id="right"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
<path
|
<path
|
||||||
d="m 46.656521,12.167234 18.055171,18.054184 a 6.6081919,6.6078288 0 0 1 -0.126303,9.352065 6.6804126,6.6800456 0 0 1 -8.233169,1.011048 l -7.944268,7.943843 6.463762,6.445343 a 6.9331851,6.9328042 0 0 1 5.741536,2.022073 l 28.057729,28.092294 a 6.9962797,6.9958953 0 0 1 -9.894222,9.893685 L 50.719018,66.907526 A 7.0595711,7.0591833 0 0 1 49.18433,59.270613 l -5.741527,-5.741238 -7.944298,7.943843 A 6.716523,6.7161541 0 0 1 25.134866,69.832263 L 7.079684,51.778091 a 6.716523,6.7161541 0 0 1 8.39566,-10.345064 L 36.31101,20.59853 a 6.716523,6.7161541 0 0 1 10.345612,-8.431329 z"
|
d="m 46.656521,12.167234 18.055171,18.054184 a 6.6081919,6.6078288 0 0 1 -0.126303,9.352065 6.6804126,6.6800456 0 0 1 -8.233169,1.011048 l -7.944268,7.943843 6.463762,6.445343 a 6.9331851,6.9328042 0 0 1 5.741536,2.022073 l 28.057729,28.092294 a 6.9962797,6.9958953 0 0 1 -9.894222,9.893685 L 50.719018,66.907526 A 7.0595711,7.0591833 0 0 1 49.18433,59.270613 l -5.741527,-5.741238 -7.944298,7.943843 A 6.716523,6.7161541 0 0 1 25.134866,69.832263 L 7.079684,51.778091 a 6.716523,6.7161541 0 0 1 8.39566,-10.345064 L 36.31101,20.59853 a 6.716523,6.7161541 0 0 1 10.345612,-8.431329 z"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -340,11 +340,11 @@
|
|||||||
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
|
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
|
||||||
transform="translate(0,952.36218)"
|
transform="translate(0,952.36218)"
|
||||||
id="right" />
|
id="left" />
|
||||||
<path
|
<path
|
||||||
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
|
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
|
||||||
id="left"
|
id="right"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
<path
|
<path
|
||||||
sodipodi:type="star"
|
sodipodi:type="star"
|
||||||
@@ -363,6 +363,6 @@
|
|||||||
d="m 38.011063,984.77381 -10.143601,-5.23583 -10.063711,5.38779 1.845023,-11.2651 -8.233948,-7.90624 11.283888,-1.72639 4.974851,-10.27411 5.128803,10.19813 11.308575,1.55649 -8.114112,8.02918 z"
|
d="m 38.011063,984.77381 -10.143601,-5.23583 -10.063711,5.38779 1.845023,-11.2651 -8.233948,-7.90624 11.283888,-1.72639 4.974851,-10.27411 5.128803,10.19813 11.308575,1.55649 -8.114112,8.02918 z"
|
||||||
inkscape:transform-center-x="0.094945927"
|
inkscape:transform-center-x="0.094945927"
|
||||||
inkscape:transform-center-y="-3.9764964"
|
inkscape:transform-center-y="-3.9764964"
|
||||||
transform="matrix(2.3768784,0,0,2.4799382,-15.920285,-1400.1716)" />
|
transform="matrix(-2.3768784,0,0,2.4799382,115.920285,-1400.1716)" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,14 +1,14 @@
|
|||||||
#include "deck_stats_interface.h"
|
#include "deck_stats_interface.h"
|
||||||
|
|
||||||
#include "decklist.h"
|
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||||
|
#include <version_string.h>
|
||||||
|
|
||||||
DeckStatsInterface::DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent)
|
DeckStatsInterface::DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent)
|
||||||
: QObject(parent), cardDatabase(_cardDatabase)
|
: QObject(parent), cardDatabase(_cardDatabase)
|
||||||
@@ -63,6 +63,7 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
|
|||||||
|
|
||||||
QNetworkRequest request(QUrl("https://deckstats.net/index.php"));
|
QNetworkRequest request(QUrl("https://deckstats.net/index.php"));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
||||||
|
|
||||||
manager->post(request, data);
|
manager->post(request, data);
|
||||||
}
|
}
|
||||||
@@ -70,7 +71,7 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
|
|||||||
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
|
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
|
||||||
{
|
{
|
||||||
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
|
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
|
||||||
CardInfoPtr dbCard = cardDatabase.getCard(card->getName());
|
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
||||||
if (dbCard && !dbCard->getIsToken()) {
|
if (dbCard && !dbCard->getIsToken()) {
|
||||||
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
|
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
|
||||||
addedCard->setNumber(card->getNumber());
|
addedCard->setNumber(card->getNumber());
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* @file deck_stats_interface.h
|
||||||
|
* @ingroup ApiInterfaces
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef DECKSTATS_INTERFACE_H
|
#ifndef DECKSTATS_INTERFACE_H
|
||||||
#define DECKSTATS_INTERFACE_H
|
#define DECKSTATS_INTERFACE_H
|
||||||
|
|
||||||
#include "../game/cards/card_database.h"
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
#include "decklist.h"
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
class QNetworkAccessManager;
|
class QNetworkAccessManager;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
#include "tapped_out_interface.h"
|
#include "tapped_out_interface.h"
|
||||||
|
|
||||||
#include "decklist.h"
|
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||||
|
#include <version_string.h>
|
||||||
|
|
||||||
TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent)
|
TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent)
|
||||||
: QObject(parent), cardDatabase(_cardDatabase)
|
: QObject(parent), cardDatabase(_cardDatabase)
|
||||||
@@ -88,6 +88,7 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
|
|||||||
|
|
||||||
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
|
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
||||||
|
|
||||||
manager->post(request, data);
|
manager->post(request, data);
|
||||||
}
|
}
|
||||||
@@ -95,7 +96,7 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
|
|||||||
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
||||||
{
|
{
|
||||||
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
|
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
|
||||||
CardInfoPtr dbCard = cardDatabase.getCard(card->getName());
|
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
||||||
if (!dbCard || dbCard->getIsToken())
|
if (!dbCard || dbCard->getIsToken())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* @file tapped_out_interface.h
|
||||||
|
* @ingroup ApiInterfaces
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef TAPPEDOUT_INTERFACE_H
|
#ifndef TAPPEDOUT_INTERFACE_H
|
||||||
#define TAPPEDOUT_INTERFACE_H
|
#define TAPPEDOUT_INTERFACE_H
|
||||||
|
|
||||||
#include "../game/cards/card_database.h"
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
#include "decklist.h"
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(TappedOutInterfaceLog, "tapped_out_interface");
|
inline Q_LOGGING_CATEGORY(TappedOutInterfaceLog, "tapped_out_interface");
|
||||||
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include "deck_link_to_api_transformer.h"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
namespace DeckLinkToApiTransformer
|
||||||
|
{
|
||||||
|
|
||||||
|
static const QString TAPPEDOUT_BASE = "https://tappedout.net/mtg-decks/";
|
||||||
|
static const QString TAPPEDOUT_SUFFIX = "/?fmt=txt";
|
||||||
|
|
||||||
|
static const QString ARCHIDEKT_BASE = "https://archidekt.com/api/decks/";
|
||||||
|
static const QString ARCHIDEKT_SUFFIX = "/?format=json";
|
||||||
|
|
||||||
|
static const QString MOXFIELD_BASE = "https://api.moxfield.com/v2/decks/all/";
|
||||||
|
static const QString MOXFIELD_SUFFIX = "/";
|
||||||
|
|
||||||
|
static const QString DECKSTATS_SUFFIX = "?include_comments=1&export_mtgarena=1";
|
||||||
|
|
||||||
|
bool parseDeckUrl(const QString &url, ParsedDeckInfo &outInfo)
|
||||||
|
{
|
||||||
|
static QRegularExpression rxTappedOut("tappedout\\.net/(?:mtg-decks/)?([^/?#]+)");
|
||||||
|
static QRegularExpression rxArchidekt("archidekt\\.com/decks/(\\d+)");
|
||||||
|
static QRegularExpression rxMoxfield("moxfield\\.com/decks/([a-zA-Z0-9_-]+)");
|
||||||
|
static QRegularExpression rxDeckstats("deckstats\\.net/decks/(\\d+/[a-zA-Z0-9_-]+)");
|
||||||
|
|
||||||
|
QRegularExpressionMatch match;
|
||||||
|
|
||||||
|
if ((match = rxTappedOut.match(url)).hasMatch()) {
|
||||||
|
QString slug = match.captured(1);
|
||||||
|
outInfo = ParsedDeckInfo{.baseUrl = TAPPEDOUT_BASE,
|
||||||
|
.deckID = slug,
|
||||||
|
.fullUrl = TAPPEDOUT_BASE + slug + TAPPEDOUT_SUFFIX,
|
||||||
|
.provider = DeckProvider::TappedOut};
|
||||||
|
return true;
|
||||||
|
} else if ((match = rxArchidekt.match(url)).hasMatch()) {
|
||||||
|
QString deckID = match.captured(1);
|
||||||
|
outInfo = ParsedDeckInfo{.baseUrl = ARCHIDEKT_BASE,
|
||||||
|
.deckID = deckID,
|
||||||
|
.fullUrl = ARCHIDEKT_BASE + deckID + ARCHIDEKT_SUFFIX,
|
||||||
|
.provider = DeckProvider::Archidekt};
|
||||||
|
return true;
|
||||||
|
} else if ((match = rxMoxfield.match(url)).hasMatch()) {
|
||||||
|
QString deckID = match.captured(1);
|
||||||
|
outInfo = ParsedDeckInfo{.baseUrl = MOXFIELD_BASE,
|
||||||
|
.deckID = deckID,
|
||||||
|
.fullUrl = MOXFIELD_BASE + deckID + MOXFIELD_SUFFIX,
|
||||||
|
.provider = DeckProvider::Moxfield};
|
||||||
|
return true;
|
||||||
|
} else if ((match = rxDeckstats.match(url)).hasMatch()) {
|
||||||
|
QString deckPath = match.captured(1);
|
||||||
|
outInfo = ParsedDeckInfo{.baseUrl = "https://deckstats.net/decks/",
|
||||||
|
.deckID = deckPath,
|
||||||
|
.fullUrl = "https://deckstats.net/decks/" + deckPath + DECKSTATS_SUFFIX,
|
||||||
|
.provider = DeckProvider::Deckstats};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace DeckLinkToApiTransformer
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* @file deck_link_to_api_transformer.h
|
||||||
|
* @ingroup ApiInterfaces
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DECK_LINK_TO_API_TRANSFORMER_H
|
||||||
|
#define DECK_LINK_TO_API_TRANSFORMER_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
enum class DeckProvider
|
||||||
|
{
|
||||||
|
TappedOut,
|
||||||
|
Archidekt,
|
||||||
|
Moxfield,
|
||||||
|
Deckstats,
|
||||||
|
Unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParsedDeckInfo
|
||||||
|
{
|
||||||
|
QString baseUrl;
|
||||||
|
QString deckID;
|
||||||
|
QString fullUrl;
|
||||||
|
DeckProvider provider;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace DeckLinkToApiTransformer
|
||||||
|
{
|
||||||
|
|
||||||
|
// Returns true if the input URL is recognized and fills outInfo.
|
||||||
|
bool parseDeckUrl(const QString &url, ParsedDeckInfo &outInfo);
|
||||||
|
|
||||||
|
} // namespace DeckLinkToApiTransformer
|
||||||
|
|
||||||
|
#endif // DECK_LINK_TO_API_TRANSFORMER_H
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* @file interface_json_deck_parser.h
|
||||||
|
* @ingroup ApiInterfaces
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INTERFACE_JSON_DECK_PARSER_H
|
||||||
|
#define INTERFACE_JSON_DECK_PARSER_H
|
||||||
|
|
||||||
|
#include "../../../interface/deck_loader/card_node_function.h"
|
||||||
|
#include "../../../interface/deck_loader/deck_loader.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
class IJsonDeckParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IJsonDeckParser() = default;
|
||||||
|
|
||||||
|
virtual DeckList parse(const QJsonObject &obj) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArchidektJsonParser : public IJsonDeckParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeckList parse(const QJsonObject &obj) override
|
||||||
|
{
|
||||||
|
DeckList deckList;
|
||||||
|
|
||||||
|
QString deckName = obj.value("name").toString();
|
||||||
|
QString deckDescription = obj.value("description").toString();
|
||||||
|
|
||||||
|
deckList.setName(deckName);
|
||||||
|
deckList.setComments(deckDescription);
|
||||||
|
|
||||||
|
QString outputText;
|
||||||
|
QTextStream outStream(&outputText);
|
||||||
|
|
||||||
|
for (auto entry : obj.value("cards").toArray()) {
|
||||||
|
auto quantity = entry.toObject().value("quantity").toInt();
|
||||||
|
|
||||||
|
auto card = entry.toObject().value("card").toObject();
|
||||||
|
auto oracleCard = card.value("oracleCard").toObject();
|
||||||
|
QString cardName = oracleCard.value("name").toString();
|
||||||
|
QString setName = card.value("edition").toObject().value("editioncode").toString().toUpper();
|
||||||
|
QString collectorNumber = card.value("collectorNumber").toString();
|
||||||
|
|
||||||
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
deckList.loadFromStream_Plain(outStream, false);
|
||||||
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
|
return deckList;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoxfieldJsonParser : public IJsonDeckParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeckList parse(const QJsonObject &obj) override
|
||||||
|
{
|
||||||
|
DeckList deckList;
|
||||||
|
|
||||||
|
QString deckName = obj.value("name").toString();
|
||||||
|
QString deckDescription = obj.value("description").toString();
|
||||||
|
|
||||||
|
deckList.setName(deckName);
|
||||||
|
deckList.setComments(deckDescription);
|
||||||
|
|
||||||
|
QString outputText;
|
||||||
|
QTextStream outStream(&outputText);
|
||||||
|
|
||||||
|
for (auto entry : obj.value("mainboard").toObject()) {
|
||||||
|
auto quantity = entry.toObject().value("quantity").toInt();
|
||||||
|
|
||||||
|
auto card = entry.toObject().value("card").toObject();
|
||||||
|
QString cardName = card.value("name").toString();
|
||||||
|
QString setName = card.value("set").toString().toUpper();
|
||||||
|
QString collectorNumber = card.value("cn").toString();
|
||||||
|
|
||||||
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
outStream << '\n';
|
||||||
|
|
||||||
|
for (auto entry : obj.value("sideboard").toObject()) {
|
||||||
|
auto quantity = entry.toObject().value("quantity").toInt();
|
||||||
|
|
||||||
|
auto card = entry.toObject().value("card").toObject();
|
||||||
|
QString cardName = card.value("name").toString();
|
||||||
|
QString setName = card.value("set").toString().toUpper();
|
||||||
|
QString collectorNumber = card.value("cn").toString();
|
||||||
|
|
||||||
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
deckList.loadFromStream_Plain(outStream, false);
|
||||||
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
|
QJsonObject commandersObj = obj.value("commanders").toObject();
|
||||||
|
if (!commandersObj.isEmpty()) {
|
||||||
|
for (auto it = commandersObj.begin(); it != commandersObj.end(); ++it) {
|
||||||
|
QJsonObject cardData = it.value().toObject().value("card").toObject();
|
||||||
|
QString commanderName = cardData.value("name").toString();
|
||||||
|
QString setName = cardData.value("set").toString().toUpper();
|
||||||
|
QString collectorNumber = cardData.value("cn").toString();
|
||||||
|
QString providerId = cardData.value("scryfall_id").toString();
|
||||||
|
|
||||||
|
deckList.setBannerCard({commanderName, providerId});
|
||||||
|
deckList.addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return deckList;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INTERFACE_JSON_DECK_PARSER_H
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
#include "spoiler_background_updater.h"
|
#include "spoiler_background_updater.h"
|
||||||
|
|
||||||
#include "../../game/cards/card_database.h"
|
#include "../../../../interface/window_main.h"
|
||||||
#include "../../game/cards/card_database_manager.h"
|
#include "../../../../main.h"
|
||||||
#include "../../main.h"
|
#include "../../../settings/cache_settings.h"
|
||||||
#include "../../settings/cache_settings.h"
|
|
||||||
#include "../ui/window_main.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
#include <version_string.h>
|
||||||
|
|
||||||
#define SPOILERS_STATUS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/SpoilerSeasonEnabled"
|
#define SPOILERS_STATUS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/SpoilerSeasonEnabled"
|
||||||
#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml"
|
#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml"
|
||||||
@@ -41,7 +40,9 @@ void SpoilerBackgroundUpdater::startSpoilerDownloadProcess(QString url, bool sav
|
|||||||
void SpoilerBackgroundUpdater::downloadFromURL(QUrl url, bool saveResults)
|
void SpoilerBackgroundUpdater::downloadFromURL(QUrl url, bool saveResults)
|
||||||
{
|
{
|
||||||
auto *nam = new QNetworkAccessManager(this);
|
auto *nam = new QNetworkAccessManager(this);
|
||||||
QNetworkReply *reply = nam->get(QNetworkRequest(url));
|
auto request = QNetworkRequest(url);
|
||||||
|
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
||||||
|
QNetworkReply *reply = nam->get(request);
|
||||||
|
|
||||||
if (saveResults) {
|
if (saveResults) {
|
||||||
// This will write out to the file (used for spoiler.xml)
|
// This will write out to the file (used for spoiler.xml)
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @file spoiler_background_updater.h
|
||||||
|
* @ingroup Client
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
|
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
|
||||||
#define COCKATRICE_SPOILER_DOWNLOADER_H
|
#define COCKATRICE_SPOILER_DOWNLOADER_H
|
||||||
|
|
||||||
@@ -16,7 +22,7 @@ public:
|
|||||||
inline QString getCardUpdaterBinaryName()
|
inline QString getCardUpdaterBinaryName()
|
||||||
{
|
{
|
||||||
return "oracle";
|
return "oracle";
|
||||||
};
|
}
|
||||||
QByteArray getHash(const QString fileName);
|
QByteArray getHash(const QString fileName);
|
||||||
QByteArray getHash(QByteArray data);
|
QByteArray getHash(QByteArray data);
|
||||||
static bool deleteSpoilerFile();
|
static bool deleteSpoilerFile();
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "client_update_checker.h"
|
#include "client_update_checker.h"
|
||||||
|
|
||||||
#include "../../settings/cache_settings.h"
|
#include "../../../settings/cache_settings.h"
|
||||||
#include "release_channel.h"
|
#include "release_channel.h"
|
||||||
|
|
||||||
ClientUpdateChecker::ClientUpdateChecker(QObject *parent) : QObject(parent)
|
ClientUpdateChecker::ClientUpdateChecker(QObject *parent) : QObject(parent)
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @file client_update_checker.h
|
||||||
|
* @ingroup ClientUpdate
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef CLIENT_UPDATE_CHECKER_H
|
#ifndef CLIENT_UPDATE_CHECKER_H
|
||||||
#define CLIENT_UPDATE_CHECKER_H
|
#define CLIENT_UPDATE_CHECKER_H
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @file release_channel.h
|
||||||
|
* @ingroup ClientUpdate
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef RELEASECHANNEL_H
|
#ifndef RELEASECHANNEL_H
|
||||||
#define RELEASECHANNEL_H
|
#define RELEASECHANNEL_H
|
||||||
|
|
||||||
@@ -51,27 +57,27 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QString getName() const
|
[[nodiscard]] QString getName() const
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
QString getDescriptionUrl() const
|
[[nodiscard]] QString getDescriptionUrl() const
|
||||||
{
|
{
|
||||||
return descriptionUrl;
|
return descriptionUrl;
|
||||||
}
|
}
|
||||||
QString getDownloadUrl() const
|
[[nodiscard]] QString getDownloadUrl() const
|
||||||
{
|
{
|
||||||
return downloadUrl;
|
return downloadUrl;
|
||||||
}
|
}
|
||||||
QString getCommitHash() const
|
[[nodiscard]] QString getCommitHash() const
|
||||||
{
|
{
|
||||||
return commitHash;
|
return commitHash;
|
||||||
}
|
}
|
||||||
QDate getPublishDate() const
|
[[nodiscard]] QDate getPublishDate() const
|
||||||
{
|
{
|
||||||
return publishDate;
|
return publishDate;
|
||||||
}
|
}
|
||||||
bool isCompatibleVersionFound() const
|
[[nodiscard]] bool isCompatibleVersionFound() const
|
||||||
{
|
{
|
||||||
return compatibleVersionFound;
|
return compatibleVersionFound;
|
||||||
}
|
}
|
||||||
@@ -91,15 +97,15 @@ protected:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
static bool downloadMatchesCurrentOS(const QString &fileName);
|
static bool downloadMatchesCurrentOS(const QString &fileName);
|
||||||
virtual QString getReleaseChannelUrl() const = 0;
|
[[nodiscard]] virtual QString getReleaseChannelUrl() const = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Release *getLastRelease()
|
Release *getLastRelease()
|
||||||
{
|
{
|
||||||
return lastRelease;
|
return lastRelease;
|
||||||
}
|
}
|
||||||
virtual QString getManualDownloadUrl() const = 0;
|
[[nodiscard]] virtual QString getManualDownloadUrl() const = 0;
|
||||||
virtual QString getName() const = 0;
|
[[nodiscard]] virtual QString getName() const = 0;
|
||||||
void checkForUpdates();
|
void checkForUpdates();
|
||||||
signals:
|
signals:
|
||||||
void finishedCheck(bool needToUpdate, bool isCompatible, Release *release);
|
void finishedCheck(bool needToUpdate, bool isCompatible, Release *release);
|
||||||
@@ -116,12 +122,12 @@ public:
|
|||||||
explicit StableReleaseChannel() = default;
|
explicit StableReleaseChannel() = default;
|
||||||
~StableReleaseChannel() override = default;
|
~StableReleaseChannel() override = default;
|
||||||
|
|
||||||
QString getManualDownloadUrl() const override;
|
[[nodiscard]] QString getManualDownloadUrl() const override;
|
||||||
|
|
||||||
QString getName() const override;
|
[[nodiscard]] QString getName() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString getReleaseChannelUrl() const override;
|
[[nodiscard]] QString getReleaseChannelUrl() const override;
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
void releaseListFinished() override;
|
void releaseListFinished() override;
|
||||||
@@ -137,12 +143,12 @@ public:
|
|||||||
BetaReleaseChannel() = default;
|
BetaReleaseChannel() = default;
|
||||||
~BetaReleaseChannel() override = default;
|
~BetaReleaseChannel() override = default;
|
||||||
|
|
||||||
QString getManualDownloadUrl() const override;
|
[[nodiscard]] QString getManualDownloadUrl() const override;
|
||||||
|
|
||||||
QString getName() const override;
|
[[nodiscard]] QString getName() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString getReleaseChannelUrl() const override;
|
[[nodiscard]] QString getReleaseChannelUrl() const override;
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
void releaseListFinished() override;
|
void releaseListFinished() override;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "update_downloader.h"
|
#include "update_downloader.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(nullptr)
|
UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(nullptr)
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
//
|
/**
|
||||||
// Created by miguel on 28/12/15.
|
* @file update_downloader.h
|
||||||
//
|
* @ingroup ClientUpdate
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
|
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
|
||||||
#define COCKATRICE_UPDATEDOWNLOADER_H
|
#define COCKATRICE_UPDATEDOWNLOADER_H
|
||||||
|
|
||||||
#include <QDate>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QUrl>
|
|
||||||
#include <QtNetwork>
|
#include <QtNetwork>
|
||||||
|
|
||||||
class UpdateDownloader : public QObject
|
class UpdateDownloader : public QObject
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#include "cache_settings.h"
|
#include "cache_settings.h"
|
||||||
|
|
||||||
#include "../client/network/release_channel.h"
|
#include "../network/update/client/release_channel.h"
|
||||||
#include "card_counter_settings.h"
|
#include "card_counter_settings.h"
|
||||||
#include "card_override_settings.h"
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -12,9 +11,15 @@
|
|||||||
#include <QGlobalStatic>
|
#include <QGlobalStatic>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <libcockatrice/settings/card_override_settings.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(SettingsCache, settingsCache);
|
Q_GLOBAL_STATIC(SettingsCache, settingsCache)
|
||||||
|
|
||||||
|
SettingsCache &SettingsCache::instance()
|
||||||
|
{
|
||||||
|
return *settingsCache; // returns a QT managed singleton reference
|
||||||
|
}
|
||||||
|
|
||||||
QString SettingsCache::getDataPath()
|
QString SettingsCache::getDataPath()
|
||||||
{
|
{
|
||||||
@@ -61,9 +66,9 @@ void SettingsCache::translateLegacySettings()
|
|||||||
QStringList setsGroups = legacySetting.childGroups();
|
QStringList setsGroups = legacySetting.childGroups();
|
||||||
for (int i = 0; i < setsGroups.size(); i++) {
|
for (int i = 0; i < setsGroups.size(); i++) {
|
||||||
legacySetting.beginGroup(setsGroups.at(i));
|
legacySetting.beginGroup(setsGroups.at(i));
|
||||||
cardDatabase().setEnabled(setsGroups.at(i), legacySetting.value("enabled").toBool());
|
cardDatabase()->setEnabled(setsGroups.at(i), legacySetting.value("enabled").toBool());
|
||||||
cardDatabase().setIsKnown(setsGroups.at(i), legacySetting.value("isknown").toBool());
|
cardDatabase()->setIsKnown(setsGroups.at(i), legacySetting.value("isknown").toBool());
|
||||||
cardDatabase().setSortKey(setsGroups.at(i), legacySetting.value("sortkey").toUInt());
|
cardDatabase()->setSortKey(setsGroups.at(i), legacySetting.value("sortkey").toUInt());
|
||||||
legacySetting.endGroup();
|
legacySetting.endGroup();
|
||||||
}
|
}
|
||||||
QStringList setsKeys = legacySetting.allKeys();
|
QStringList setsKeys = legacySetting.allKeys();
|
||||||
@@ -194,6 +199,11 @@ SettingsCache::SettingsCache()
|
|||||||
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
|
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
|
||||||
|
|
||||||
checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
|
checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
|
||||||
|
startupCardUpdateCheckPromptForUpdate =
|
||||||
|
settings->value("personal/startupCardUpdateCheckPromptForUpdate", true).toBool();
|
||||||
|
startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
|
||||||
|
cardUpdateCheckInterval = settings->value("personal/cardUpdateCheckInterval", 7).toInt();
|
||||||
|
lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
|
||||||
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
||||||
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
||||||
updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt();
|
updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt();
|
||||||
@@ -212,6 +222,9 @@ SettingsCache::SettingsCache()
|
|||||||
|
|
||||||
themeName = settings->value("theme/name").toString();
|
themeName = settings->value("theme/name").toString();
|
||||||
|
|
||||||
|
homeTabBackgroundSource = settings->value("home/background", "themed").toString();
|
||||||
|
homeTabBackgroundShuffleFrequency = settings->value("home/background/shuffleTimer", 0).toInt();
|
||||||
|
|
||||||
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();
|
||||||
tabAccountOpen = settings->value("tabs/account", true).toBool();
|
tabAccountOpen = settings->value("tabs/account", true).toBool();
|
||||||
@@ -248,6 +261,7 @@ SettingsCache::SettingsCache()
|
|||||||
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
|
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
|
||||||
clickPlaysAllSelected = settings->value("interface/clickPlaysAllSelected", true).toBool();
|
clickPlaysAllSelected = settings->value("interface/clickPlaysAllSelected", true).toBool();
|
||||||
playToStack = settings->value("interface/playtostack", true).toBool();
|
playToStack = settings->value("interface/playtostack", 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();
|
tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray();
|
||||||
@@ -296,10 +310,15 @@ SettingsCache::SettingsCache()
|
|||||||
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
|
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
|
||||||
defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
|
defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
|
||||||
visualDatabaseDisplayFilterToMostRecentSetsEnabled =
|
visualDatabaseDisplayFilterToMostRecentSetsEnabled =
|
||||||
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
|
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", false).toBool();
|
||||||
visualDatabaseDisplayFilterToMostRecentSetsAmount =
|
visualDatabaseDisplayFilterToMostRecentSetsAmount =
|
||||||
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
|
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
|
||||||
visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
|
visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
|
||||||
|
visualDeckEditorCardSize = settings->value("interface/visualdeckeditorcardsize", 100).toInt();
|
||||||
|
visualDatabaseDisplayCardSize = settings->value("interface/visualdatabasedisplaycardsize", 100).toInt();
|
||||||
|
edhrecCardSize = settings->value("interface/edhreccardsize", 100).toInt();
|
||||||
|
archidektPreviewSize = settings->value("interface/archidektpreviewsize", 100).toInt();
|
||||||
|
|
||||||
horizontalHand = settings->value("hand/horizontal", true).toBool();
|
horizontalHand = settings->value("hand/horizontal", true).toBool();
|
||||||
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
||||||
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
|
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
|
||||||
@@ -350,6 +369,7 @@ SettingsCache::SettingsCache()
|
|||||||
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
|
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
|
||||||
createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool();
|
createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool();
|
||||||
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
||||||
|
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
|
||||||
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
||||||
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();
|
||||||
@@ -544,6 +564,20 @@ void SettingsCache::setThemeName(const QString &_themeName)
|
|||||||
emit themeChanged();
|
emit themeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setHomeTabBackgroundSource(const QString &_backgroundSource)
|
||||||
|
{
|
||||||
|
homeTabBackgroundSource = _backgroundSource;
|
||||||
|
settings->setValue("home/background", homeTabBackgroundSource);
|
||||||
|
emit homeTabBackgroundSourceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setHomeTabBackgroundShuffleFrequency(int _frequency)
|
||||||
|
{
|
||||||
|
homeTabBackgroundShuffleFrequency = _frequency;
|
||||||
|
settings->setValue("home/background/shuffleTimer", homeTabBackgroundShuffleFrequency);
|
||||||
|
emit homeTabBackgroundShuffleFrequencyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
||||||
{
|
{
|
||||||
tabVisualDeckStorageOpen = value;
|
tabVisualDeckStorageOpen = value;
|
||||||
@@ -636,6 +670,12 @@ void SettingsCache::setPlayToStack(QT_STATE_CHANGED_T _playToStack)
|
|||||||
settings->setValue("interface/playtostack", playToStack);
|
settings->setValue("interface/playtostack", playToStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases)
|
||||||
|
{
|
||||||
|
doNotDeleteArrowsInSubPhases = static_cast<bool>(_doNotDeleteArrowsInSubPhases);
|
||||||
|
settings->setValue("interface/doNotDeleteArrowsInSubPhases", doNotDeleteArrowsInSubPhases);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setStartingHandSize(int _startingHandSize)
|
void SettingsCache::setStartingHandSize(int _startingHandSize)
|
||||||
{
|
{
|
||||||
startingHandSize = _startingHandSize;
|
startingHandSize = _startingHandSize;
|
||||||
@@ -828,6 +868,34 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
|
|||||||
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
|
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setVisualDeckEditorCardSize(int _visualDeckEditorCardSize)
|
||||||
|
{
|
||||||
|
visualDeckEditorCardSize = _visualDeckEditorCardSize;
|
||||||
|
settings->setValue("interface/visualdeckeditorcardsize", visualDeckEditorCardSize);
|
||||||
|
emit visualDeckEditorCardSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize)
|
||||||
|
{
|
||||||
|
visualDatabaseDisplayCardSize = _visualDatabaseDisplayCardSize;
|
||||||
|
settings->setValue("interface/visualdatabasedisplaycardsize", visualDatabaseDisplayCardSize);
|
||||||
|
emit visualDatabaseDisplayCardSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setEDHRecCardSize(int _edhrecCardSize)
|
||||||
|
{
|
||||||
|
edhrecCardSize = _edhrecCardSize;
|
||||||
|
settings->setValue("interface/edhreccardsize", edhrecCardSize);
|
||||||
|
emit edhRecCardSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setArchidektPreviewCardSize(int _archidektPreviewCardSize)
|
||||||
|
{
|
||||||
|
archidektPreviewSize = _archidektPreviewCardSize;
|
||||||
|
settings->setValue("interface/archidektpreviewsize", archidektPreviewSize);
|
||||||
|
emit archidektPreviewSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setDefaultDeckEditorType(int value)
|
void SettingsCache::setDefaultDeckEditorType(int value)
|
||||||
{
|
{
|
||||||
defaultDeckEditorType = value;
|
defaultDeckEditorType = value;
|
||||||
@@ -1355,7 +1423,13 @@ void SettingsCache::setDefaultStartingLifeTotal(const int _defaultStartingLifeTo
|
|||||||
{
|
{
|
||||||
defaultStartingLifeTotal = _defaultStartingLifeTotal;
|
defaultStartingLifeTotal = _defaultStartingLifeTotal;
|
||||||
settings->setValue("game/defaultstartinglifetotal", defaultStartingLifeTotal);
|
settings->setValue("game/defaultstartinglifetotal", defaultStartingLifeTotal);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad)
|
||||||
|
{
|
||||||
|
shareDecklistsOnLoad = _shareDecklistsOnLoad;
|
||||||
|
settings->setValue("game/sharedecklistsonload", shareDecklistsOnLoad);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value)
|
void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value)
|
||||||
{
|
{
|
||||||
@@ -1363,6 +1437,30 @@ void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value)
|
|||||||
settings->setValue("personal/startupUpdateCheck", checkUpdatesOnStartup);
|
settings->setValue("personal/startupUpdateCheck", checkUpdatesOnStartup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setStartupCardUpdateCheckPromptForUpdate(bool value)
|
||||||
|
{
|
||||||
|
startupCardUpdateCheckPromptForUpdate = value;
|
||||||
|
settings->setValue("personal/startupCardUpdateCheckPromptForUpdate", startupCardUpdateCheckPromptForUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setStartupCardUpdateCheckAlwaysUpdate(bool value)
|
||||||
|
{
|
||||||
|
startupCardUpdateCheckAlwaysUpdate = value;
|
||||||
|
settings->setValue("personal/startupCardUpdateCheckAlwaysUpdate", startupCardUpdateCheckAlwaysUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setCardUpdateCheckInterval(int value)
|
||||||
|
{
|
||||||
|
cardUpdateCheckInterval = value;
|
||||||
|
settings->setValue("personal/cardUpdateCheckInterval", cardUpdateCheckInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setLastCardUpdateCheck(QDate value)
|
||||||
|
{
|
||||||
|
lastCardUpdateCheck = value;
|
||||||
|
settings->setValue("personal/lastCardUpdateCheck", lastCardUpdateCheck);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
||||||
{
|
{
|
||||||
rememberGameSettings = _rememberGameSettings;
|
rememberGameSettings = _rememberGameSettings;
|
||||||
@@ -1447,11 +1545,6 @@ void SettingsCache::resetPaths()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCache &SettingsCache::instance()
|
|
||||||
{
|
|
||||||
return *settingsCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
CardCounterSettings &SettingsCache::cardCounters() const
|
CardCounterSettings &SettingsCache::cardCounters() const
|
||||||
{
|
{
|
||||||
return *cardCounterSettings;
|
return *cardCounterSettings;
|
||||||
@@ -1,22 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* @file cache_settings.h
|
||||||
|
* @ingroup Settings
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef SETTINGSCACHE_H
|
#ifndef SETTINGSCACHE_H
|
||||||
#define SETTINGSCACHE_H
|
#define SETTINGSCACHE_H
|
||||||
|
|
||||||
#include "../utility/macros.h"
|
|
||||||
#include "card_database_settings.h"
|
|
||||||
#include "card_override_settings.h"
|
|
||||||
#include "debug_settings.h"
|
|
||||||
#include "download_settings.h"
|
|
||||||
#include "game_filters_settings.h"
|
|
||||||
#include "layouts_settings.h"
|
|
||||||
#include "message_settings.h"
|
|
||||||
#include "recents_settings.h"
|
|
||||||
#include "servers_settings.h"
|
|
||||||
#include "shortcuts_settings.h"
|
#include "shortcuts_settings.h"
|
||||||
|
|
||||||
|
#include <QDate>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QObject>
|
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <libcockatrice/interfaces/interface_card_database_path_provider.h>
|
||||||
|
#include <libcockatrice/interfaces/interface_network_settings_provider.h>
|
||||||
|
#include <libcockatrice/settings/card_database_settings.h>
|
||||||
|
#include <libcockatrice/settings/card_override_settings.h>
|
||||||
|
#include <libcockatrice/settings/debug_settings.h>
|
||||||
|
#include <libcockatrice/settings/download_settings.h>
|
||||||
|
#include <libcockatrice/settings/game_filters_settings.h>
|
||||||
|
#include <libcockatrice/settings/layouts_settings.h>
|
||||||
|
#include <libcockatrice/settings/message_settings.h>
|
||||||
|
#include <libcockatrice/settings/recents_settings.h>
|
||||||
|
#include <libcockatrice/settings/servers_settings.h>
|
||||||
|
#include <libcockatrice/utility/macros.h>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(SettingsCacheLog, "settings_cache");
|
inline Q_LOGGING_CATEGORY(SettingsCacheLog, "settings_cache");
|
||||||
|
|
||||||
@@ -125,15 +133,16 @@ inline QStringList defaultTags = {
|
|||||||
class QSettings;
|
class QSettings;
|
||||||
class CardCounterSettings;
|
class CardCounterSettings;
|
||||||
|
|
||||||
class SettingsCache : public QObject
|
class SettingsCache : public ICardDatabasePathProvider, public INetworkSettingsProvider
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void langChanged();
|
void langChanged();
|
||||||
void picsPathChanged();
|
void picsPathChanged();
|
||||||
void cardDatabasePathChanged();
|
|
||||||
void themeChanged();
|
void themeChanged();
|
||||||
|
void homeTabBackgroundSourceChanged();
|
||||||
|
void homeTabBackgroundShuffleFrequencyChanged();
|
||||||
void picDownloadChanged();
|
void picDownloadChanged();
|
||||||
void showStatusBarChanged(bool state);
|
void showStatusBarChanged(bool state);
|
||||||
void displayCardNamesChanged();
|
void displayCardNamesChanged();
|
||||||
@@ -157,6 +166,10 @@ signals:
|
|||||||
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
|
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
|
||||||
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
|
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
|
||||||
void visualDeckEditorSampleHandSizeAmountChanged(int amount);
|
void visualDeckEditorSampleHandSizeAmountChanged(int amount);
|
||||||
|
void visualDeckEditorCardSizeChanged();
|
||||||
|
void visualDatabaseDisplayCardSizeChanged();
|
||||||
|
void edhRecCardSizeChanged();
|
||||||
|
void archidektPreviewSizeChanged();
|
||||||
void horizontalHandChanged();
|
void horizontalHandChanged();
|
||||||
void handJustificationChanged();
|
void handJustificationChanged();
|
||||||
void invertVerticalCoordinateChanged();
|
void invertVerticalCoordinateChanged();
|
||||||
@@ -194,14 +207,20 @@ private:
|
|||||||
QByteArray setsDialogGeometry;
|
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;
|
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
||||||
bool tabVisualDeckStorageOpen, tabServerOpen, tabAccountOpen, tabDeckStorageOpen, tabReplaysOpen, tabAdminOpen,
|
bool tabVisualDeckStorageOpen, tabServerOpen, tabAccountOpen, tabDeckStorageOpen, tabReplaysOpen, tabAdminOpen,
|
||||||
tabLogOpen;
|
tabLogOpen;
|
||||||
bool checkUpdatesOnStartup;
|
bool checkUpdatesOnStartup;
|
||||||
|
bool startupCardUpdateCheckPromptForUpdate;
|
||||||
|
bool startupCardUpdateCheckAlwaysUpdate;
|
||||||
|
bool checkCardUpdatesOnStartup;
|
||||||
|
int cardUpdateCheckInterval;
|
||||||
|
QDate lastCardUpdateCheck;
|
||||||
bool notifyAboutUpdates;
|
bool notifyAboutUpdates;
|
||||||
bool notifyAboutNewVersion;
|
bool notifyAboutNewVersion;
|
||||||
bool showTipsOnStartup;
|
bool showTipsOnStartup;
|
||||||
QList<int> seenTips;
|
QList<int> seenTips;
|
||||||
|
int homeTabBackgroundShuffleFrequency;
|
||||||
bool mbDownloadSpoilers;
|
bool mbDownloadSpoilers;
|
||||||
int updateReleaseChannel;
|
int updateReleaseChannel;
|
||||||
int maxFontSize;
|
int maxFontSize;
|
||||||
@@ -212,6 +231,7 @@ private:
|
|||||||
bool doubleClickToPlay;
|
bool doubleClickToPlay;
|
||||||
bool clickPlaysAllSelected;
|
bool clickPlaysAllSelected;
|
||||||
bool playToStack;
|
bool playToStack;
|
||||||
|
bool doNotDeleteArrowsInSubPhases;
|
||||||
int startingHandSize;
|
int startingHandSize;
|
||||||
bool annotateTokens;
|
bool annotateTokens;
|
||||||
QByteArray tabGameSplitterSizes;
|
QByteArray tabGameSplitterSizes;
|
||||||
@@ -233,6 +253,10 @@ private:
|
|||||||
QStringList visualDeckStorageDefaultTagsList;
|
QStringList visualDeckStorageDefaultTagsList;
|
||||||
bool visualDeckStorageSearchFolderNames;
|
bool visualDeckStorageSearchFolderNames;
|
||||||
int visualDeckStorageCardSize;
|
int visualDeckStorageCardSize;
|
||||||
|
int visualDeckEditorCardSize;
|
||||||
|
int visualDatabaseDisplayCardSize;
|
||||||
|
int edhrecCardSize;
|
||||||
|
int archidektPreviewSize;
|
||||||
bool visualDeckStorageDrawUnusedColorIdentities;
|
bool visualDeckStorageDrawUnusedColorIdentities;
|
||||||
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
int visualDeckStorageTooltipType;
|
int visualDeckStorageTooltipType;
|
||||||
@@ -296,11 +320,12 @@ private:
|
|||||||
bool spectatorsCanSeeEverything;
|
bool spectatorsCanSeeEverything;
|
||||||
bool createGameAsSpectator;
|
bool createGameAsSpectator;
|
||||||
int defaultStartingLifeTotal;
|
int defaultStartingLifeTotal;
|
||||||
|
bool shareDecklistsOnLoad;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
int timeout;
|
int timeout;
|
||||||
void translateLegacySettings();
|
void translateLegacySettings();
|
||||||
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
|
[[nodiscard]] QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
|
||||||
QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
||||||
void loadPaths();
|
void loadPaths();
|
||||||
bool rememberGameSettings;
|
bool rememberGameSettings;
|
||||||
QList<ReleaseChannel *> releaseChannels;
|
QList<ReleaseChannel *> releaseChannels;
|
||||||
@@ -312,356 +337,405 @@ public:
|
|||||||
SettingsCache();
|
SettingsCache();
|
||||||
QString getDataPath();
|
QString getDataPath();
|
||||||
QString getSettingsPath();
|
QString getSettingsPath();
|
||||||
QString getCachePath() const;
|
[[nodiscard]] QString getCachePath() const;
|
||||||
QString getNetworkCachePath() const;
|
[[nodiscard]] QString getNetworkCachePath() const;
|
||||||
const QByteArray &getMainWindowGeometry() const
|
[[nodiscard]] const QByteArray &getMainWindowGeometry() const
|
||||||
{
|
{
|
||||||
return mainWindowGeometry;
|
return mainWindowGeometry;
|
||||||
}
|
}
|
||||||
const QByteArray &getTokenDialogGeometry() const
|
[[nodiscard]] const QByteArray &getTokenDialogGeometry() const
|
||||||
{
|
{
|
||||||
return tokenDialogGeometry;
|
return tokenDialogGeometry;
|
||||||
}
|
}
|
||||||
const QByteArray &getSetsDialogGeometry() const
|
[[nodiscard]] const QByteArray &getSetsDialogGeometry() const
|
||||||
{
|
{
|
||||||
return setsDialogGeometry;
|
return setsDialogGeometry;
|
||||||
}
|
}
|
||||||
QString getLang() const
|
[[nodiscard]] QString getLang() const
|
||||||
{
|
{
|
||||||
return lang;
|
return lang;
|
||||||
}
|
}
|
||||||
QString getDeckPath() const
|
[[nodiscard]] QString getDeckPath() const
|
||||||
{
|
{
|
||||||
return deckPath;
|
return deckPath;
|
||||||
}
|
}
|
||||||
QString getFiltersPath() const
|
[[nodiscard]] QString getFiltersPath() const
|
||||||
{
|
{
|
||||||
return filtersPath;
|
return filtersPath;
|
||||||
}
|
}
|
||||||
QString getReplaysPath() const
|
[[nodiscard]] QString getReplaysPath() const
|
||||||
{
|
{
|
||||||
return replaysPath;
|
return replaysPath;
|
||||||
}
|
}
|
||||||
QString getThemesPath() const
|
[[nodiscard]] QString getThemesPath() const
|
||||||
{
|
{
|
||||||
return themesPath;
|
return themesPath;
|
||||||
}
|
}
|
||||||
QString getPicsPath() const
|
[[nodiscard]] QString getPicsPath() const
|
||||||
{
|
{
|
||||||
return picsPath;
|
return picsPath;
|
||||||
}
|
}
|
||||||
QString getRedirectCachePath() const
|
[[nodiscard]] QString getRedirectCachePath() const
|
||||||
{
|
{
|
||||||
return redirectCachePath;
|
return redirectCachePath;
|
||||||
}
|
}
|
||||||
QString getCustomPicsPath() const
|
[[nodiscard]] QString getCustomPicsPath() const
|
||||||
{
|
{
|
||||||
return customPicsPath;
|
return customPicsPath;
|
||||||
}
|
}
|
||||||
QString getCustomCardDatabasePath() const
|
[[nodiscard]] QString getCustomCardDatabasePath() const override
|
||||||
{
|
{
|
||||||
return customCardDatabasePath;
|
return customCardDatabasePath;
|
||||||
}
|
}
|
||||||
QString getCardDatabasePath() const
|
[[nodiscard]] QString getCardDatabasePath() const override
|
||||||
{
|
{
|
||||||
return cardDatabasePath;
|
return cardDatabasePath;
|
||||||
}
|
}
|
||||||
QString getSpoilerCardDatabasePath() const
|
[[nodiscard]] QString getSpoilerCardDatabasePath() const override
|
||||||
{
|
{
|
||||||
return spoilerDatabasePath;
|
return spoilerDatabasePath;
|
||||||
}
|
}
|
||||||
QString getTokenDatabasePath() const
|
[[nodiscard]] QString getTokenDatabasePath() const override
|
||||||
{
|
{
|
||||||
return tokenDatabasePath;
|
return tokenDatabasePath;
|
||||||
}
|
}
|
||||||
QString getThemeName() const
|
[[nodiscard]] QString getThemeName() const
|
||||||
{
|
{
|
||||||
return themeName;
|
return themeName;
|
||||||
}
|
}
|
||||||
bool getTabVisualDeckStorageOpen() const
|
[[nodiscard]] QString getHomeTabBackgroundSource() const
|
||||||
|
{
|
||||||
|
return homeTabBackgroundSource;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getHomeTabBackgroundShuffleFrequency() const
|
||||||
|
{
|
||||||
|
return homeTabBackgroundShuffleFrequency;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
|
||||||
{
|
{
|
||||||
return tabVisualDeckStorageOpen;
|
return tabVisualDeckStorageOpen;
|
||||||
}
|
}
|
||||||
bool getTabServerOpen() const
|
[[nodiscard]] bool getTabServerOpen() const
|
||||||
{
|
{
|
||||||
return tabServerOpen;
|
return tabServerOpen;
|
||||||
}
|
}
|
||||||
bool getTabAccountOpen() const
|
[[nodiscard]] bool getTabAccountOpen() const
|
||||||
{
|
{
|
||||||
return tabAccountOpen;
|
return tabAccountOpen;
|
||||||
}
|
}
|
||||||
bool getTabDeckStorageOpen() const
|
[[nodiscard]] bool getTabDeckStorageOpen() const
|
||||||
{
|
{
|
||||||
return tabDeckStorageOpen;
|
return tabDeckStorageOpen;
|
||||||
}
|
}
|
||||||
bool getTabReplaysOpen() const
|
[[nodiscard]] bool getTabReplaysOpen() const
|
||||||
{
|
{
|
||||||
return tabReplaysOpen;
|
return tabReplaysOpen;
|
||||||
}
|
}
|
||||||
bool getTabAdminOpen() const
|
[[nodiscard]] bool getTabAdminOpen() const
|
||||||
{
|
{
|
||||||
return tabAdminOpen;
|
return tabAdminOpen;
|
||||||
}
|
}
|
||||||
bool getTabLogOpen() const
|
[[nodiscard]] bool getTabLogOpen() const
|
||||||
{
|
{
|
||||||
return tabLogOpen;
|
return tabLogOpen;
|
||||||
}
|
}
|
||||||
QString getChatMentionColor() const
|
[[nodiscard]] QString getChatMentionColor() const
|
||||||
{
|
{
|
||||||
return chatMentionColor;
|
return chatMentionColor;
|
||||||
}
|
}
|
||||||
QString getChatHighlightColor() const
|
[[nodiscard]] QString getChatHighlightColor() const
|
||||||
{
|
{
|
||||||
return chatHighlightColor;
|
return chatHighlightColor;
|
||||||
}
|
}
|
||||||
bool getPicDownload() const
|
[[nodiscard]] bool getPicDownload() const
|
||||||
{
|
{
|
||||||
return picDownload;
|
return picDownload;
|
||||||
}
|
}
|
||||||
bool getShowStatusBar() const
|
[[nodiscard]] bool getShowStatusBar() const
|
||||||
{
|
{
|
||||||
return showStatusBar;
|
return showStatusBar;
|
||||||
}
|
}
|
||||||
bool getNotificationsEnabled() const
|
[[nodiscard]] bool getNotificationsEnabled() const
|
||||||
{
|
{
|
||||||
return notificationsEnabled;
|
return notificationsEnabled;
|
||||||
}
|
}
|
||||||
bool getSpectatorNotificationsEnabled() const
|
[[nodiscard]] bool getSpectatorNotificationsEnabled() const
|
||||||
{
|
{
|
||||||
return spectatorNotificationsEnabled;
|
return spectatorNotificationsEnabled;
|
||||||
}
|
}
|
||||||
bool getBuddyConnectNotificationsEnabled() const
|
[[nodiscard]] bool getBuddyConnectNotificationsEnabled() const
|
||||||
{
|
{
|
||||||
return buddyConnectNotificationsEnabled;
|
return buddyConnectNotificationsEnabled;
|
||||||
}
|
}
|
||||||
bool getCheckUpdatesOnStartup() const
|
[[nodiscard]] bool getCheckUpdatesOnStartup() const
|
||||||
{
|
{
|
||||||
return checkUpdatesOnStartup;
|
return checkUpdatesOnStartup;
|
||||||
}
|
}
|
||||||
bool getNotifyAboutUpdates() const
|
bool getStartupCardUpdateCheckPromptForUpdate()
|
||||||
|
{
|
||||||
|
return startupCardUpdateCheckPromptForUpdate;
|
||||||
|
}
|
||||||
|
bool getStartupCardUpdateCheckAlwaysUpdate()
|
||||||
|
{
|
||||||
|
return startupCardUpdateCheckAlwaysUpdate;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getCardUpdateCheckInterval() const
|
||||||
|
{
|
||||||
|
return cardUpdateCheckInterval;
|
||||||
|
}
|
||||||
|
[[nodiscard]] QDate getLastCardUpdateCheck() const
|
||||||
|
{
|
||||||
|
return lastCardUpdateCheck;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getCardUpdateCheckRequired() const
|
||||||
|
{
|
||||||
|
return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() &&
|
||||||
|
getLastCardUpdateCheck() != QDateTime::currentDateTime().date();
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getNotifyAboutUpdates() const override
|
||||||
{
|
{
|
||||||
return notifyAboutUpdates;
|
return notifyAboutUpdates;
|
||||||
}
|
}
|
||||||
bool getNotifyAboutNewVersion() const
|
[[nodiscard]] bool getNotifyAboutNewVersion() const
|
||||||
{
|
{
|
||||||
return notifyAboutNewVersion;
|
return notifyAboutNewVersion;
|
||||||
}
|
}
|
||||||
bool getShowTipsOnStartup() const
|
[[nodiscard]] bool getShowTipsOnStartup() const
|
||||||
{
|
{
|
||||||
return showTipsOnStartup;
|
return showTipsOnStartup;
|
||||||
}
|
}
|
||||||
QList<int> getSeenTips() const
|
[[nodiscard]] QList<int> getSeenTips() const
|
||||||
{
|
{
|
||||||
return seenTips;
|
return seenTips;
|
||||||
}
|
}
|
||||||
int getUpdateReleaseChannelIndex() const
|
[[nodiscard]] int getUpdateReleaseChannelIndex() const
|
||||||
{
|
{
|
||||||
return updateReleaseChannel;
|
return updateReleaseChannel;
|
||||||
}
|
}
|
||||||
ReleaseChannel *getUpdateReleaseChannel() const
|
[[nodiscard]] ReleaseChannel *getUpdateReleaseChannel() const
|
||||||
{
|
{
|
||||||
return releaseChannels.at(qMax(0, updateReleaseChannel));
|
return releaseChannels.at(qMax(0, updateReleaseChannel));
|
||||||
}
|
}
|
||||||
QList<ReleaseChannel *> getUpdateReleaseChannels() const
|
[[nodiscard]] QList<ReleaseChannel *> getUpdateReleaseChannels() const
|
||||||
{
|
{
|
||||||
return releaseChannels;
|
return releaseChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getDoubleClickToPlay() const
|
[[nodiscard]] bool getDoubleClickToPlay() const
|
||||||
{
|
{
|
||||||
return doubleClickToPlay;
|
return doubleClickToPlay;
|
||||||
}
|
}
|
||||||
bool getClickPlaysAllSelected() const
|
[[nodiscard]] bool getClickPlaysAllSelected() const
|
||||||
{
|
{
|
||||||
return clickPlaysAllSelected;
|
return clickPlaysAllSelected;
|
||||||
}
|
}
|
||||||
bool getPlayToStack() const
|
[[nodiscard]] bool getPlayToStack() const
|
||||||
{
|
{
|
||||||
return playToStack;
|
return playToStack;
|
||||||
}
|
}
|
||||||
int getStartingHandSize() const
|
[[nodiscard]] bool getDoNotDeleteArrowsInSubPhases() const
|
||||||
|
{
|
||||||
|
return doNotDeleteArrowsInSubPhases;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getStartingHandSize() const
|
||||||
{
|
{
|
||||||
return startingHandSize;
|
return startingHandSize;
|
||||||
}
|
}
|
||||||
bool getAnnotateTokens() const
|
[[nodiscard]] bool getAnnotateTokens() const
|
||||||
{
|
{
|
||||||
return annotateTokens;
|
return annotateTokens;
|
||||||
}
|
}
|
||||||
QByteArray getTabGameSplitterSizes() const
|
[[nodiscard]] QByteArray getTabGameSplitterSizes() const
|
||||||
{
|
{
|
||||||
return tabGameSplitterSizes;
|
return tabGameSplitterSizes;
|
||||||
}
|
}
|
||||||
bool getShowShortcuts() const
|
[[nodiscard]] bool getShowShortcuts() const
|
||||||
{
|
{
|
||||||
return showShortcuts;
|
return showShortcuts;
|
||||||
}
|
}
|
||||||
bool getDisplayCardNames() const
|
[[nodiscard]] bool getDisplayCardNames() const
|
||||||
{
|
{
|
||||||
return displayCardNames;
|
return displayCardNames;
|
||||||
}
|
}
|
||||||
bool getOverrideAllCardArtWithPersonalPreference() const
|
[[nodiscard]] bool getOverrideAllCardArtWithPersonalPreference() const
|
||||||
{
|
{
|
||||||
return overrideAllCardArtWithPersonalPreference;
|
return overrideAllCardArtWithPersonalPreference;
|
||||||
}
|
}
|
||||||
bool getBumpSetsWithCardsInDeckToTop() const
|
[[nodiscard]] bool getBumpSetsWithCardsInDeckToTop() const
|
||||||
{
|
{
|
||||||
return bumpSetsWithCardsInDeckToTop;
|
return bumpSetsWithCardsInDeckToTop;
|
||||||
}
|
}
|
||||||
int getPrintingSelectorSortOrder() const
|
[[nodiscard]] int getPrintingSelectorSortOrder() const
|
||||||
{
|
{
|
||||||
return printingSelectorSortOrder;
|
return printingSelectorSortOrder;
|
||||||
}
|
}
|
||||||
int getPrintingSelectorCardSize() const
|
[[nodiscard]] int getPrintingSelectorCardSize() const
|
||||||
{
|
{
|
||||||
return printingSelectorCardSize;
|
return printingSelectorCardSize;
|
||||||
}
|
}
|
||||||
bool getIncludeRebalancedCards() const
|
[[nodiscard]] bool getIncludeRebalancedCards() const
|
||||||
{
|
{
|
||||||
return includeRebalancedCards;
|
return includeRebalancedCards;
|
||||||
}
|
}
|
||||||
bool getPrintingSelectorNavigationButtonsVisible() const
|
[[nodiscard]] bool getPrintingSelectorNavigationButtonsVisible() const
|
||||||
{
|
{
|
||||||
return printingSelectorNavigationButtonsVisible;
|
return printingSelectorNavigationButtonsVisible;
|
||||||
}
|
}
|
||||||
bool getDeckEditorBannerCardComboBoxVisible() const
|
[[nodiscard]] bool getDeckEditorBannerCardComboBoxVisible() const
|
||||||
{
|
{
|
||||||
return deckEditorBannerCardComboBoxVisible;
|
return deckEditorBannerCardComboBoxVisible;
|
||||||
}
|
}
|
||||||
bool getDeckEditorTagsWidgetVisible() const
|
[[nodiscard]] bool getDeckEditorTagsWidgetVisible() const
|
||||||
{
|
{
|
||||||
return deckEditorTagsWidgetVisible;
|
return deckEditorTagsWidgetVisible;
|
||||||
}
|
}
|
||||||
int getVisualDeckStorageSortingOrder() const
|
[[nodiscard]] int getVisualDeckStorageSortingOrder() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageSortingOrder;
|
return visualDeckStorageSortingOrder;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageShowFolders() const
|
[[nodiscard]] bool getVisualDeckStorageShowFolders() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowFolders;
|
return visualDeckStorageShowFolders;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageShowTagFilter() const
|
[[nodiscard]] bool getVisualDeckStorageShowTagFilter() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowTagFilter;
|
return visualDeckStorageShowTagFilter;
|
||||||
}
|
}
|
||||||
QStringList getVisualDeckStorageDefaultTagsList() const
|
[[nodiscard]] QStringList getVisualDeckStorageDefaultTagsList() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageDefaultTagsList;
|
return visualDeckStorageDefaultTagsList;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageSearchFolderNames() const
|
[[nodiscard]] bool getVisualDeckStorageSearchFolderNames() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageSearchFolderNames;
|
return visualDeckStorageSearchFolderNames;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageShowBannerCardComboBox() const
|
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowBannerCardComboBox;
|
return visualDeckStorageShowBannerCardComboBox;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageShowTagsOnDeckPreviews() const
|
[[nodiscard]] bool getVisualDeckStorageShowTagsOnDeckPreviews() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowTagsOnDeckPreviews;
|
return visualDeckStorageShowTagsOnDeckPreviews;
|
||||||
}
|
}
|
||||||
int getVisualDeckStorageCardSize() const
|
[[nodiscard]] int getVisualDeckStorageCardSize() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageCardSize;
|
return visualDeckStorageCardSize;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageDrawUnusedColorIdentities() const
|
[[nodiscard]] bool getVisualDeckStorageDrawUnusedColorIdentities() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageDrawUnusedColorIdentities;
|
return visualDeckStorageDrawUnusedColorIdentities;
|
||||||
}
|
}
|
||||||
int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
|
[[nodiscard]] int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
}
|
}
|
||||||
int getVisualDeckStorageTooltipType() const
|
[[nodiscard]] int getVisualDeckStorageTooltipType() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageTooltipType;
|
return visualDeckStorageTooltipType;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStoragePromptForConversion() const
|
[[nodiscard]] bool getVisualDeckStoragePromptForConversion() const
|
||||||
{
|
{
|
||||||
return visualDeckStoragePromptForConversion;
|
return visualDeckStoragePromptForConversion;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageAlwaysConvert() const
|
[[nodiscard]] bool getVisualDeckStorageAlwaysConvert() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageAlwaysConvert;
|
return visualDeckStorageAlwaysConvert;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageInGame() const
|
[[nodiscard]] bool getVisualDeckStorageInGame() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageInGame;
|
return visualDeckStorageInGame;
|
||||||
}
|
}
|
||||||
bool getVisualDeckStorageSelectionAnimation() const
|
[[nodiscard]] bool getVisualDeckStorageSelectionAnimation() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageSelectionAnimation;
|
return visualDeckStorageSelectionAnimation;
|
||||||
}
|
}
|
||||||
int getDefaultDeckEditorType() const
|
[[nodiscard]] int getVisualDeckEditorCardSize() const
|
||||||
|
{
|
||||||
|
return visualDeckEditorCardSize;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getVisualDatabaseDisplayCardSize() const
|
||||||
|
{
|
||||||
|
return visualDatabaseDisplayCardSize;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getEDHRecCardSize() const
|
||||||
|
{
|
||||||
|
return edhrecCardSize;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getArchidektPreviewSize() const
|
||||||
|
{
|
||||||
|
return archidektPreviewSize;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getDefaultDeckEditorType() const
|
||||||
{
|
{
|
||||||
return defaultDeckEditorType;
|
return defaultDeckEditorType;
|
||||||
}
|
}
|
||||||
bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
|
[[nodiscard]] bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
|
||||||
{
|
{
|
||||||
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
|
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
|
||||||
}
|
}
|
||||||
int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
|
[[nodiscard]] int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
|
||||||
{
|
{
|
||||||
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
|
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
|
||||||
}
|
}
|
||||||
int getVisualDeckEditorSampleHandSize() const
|
[[nodiscard]] int getVisualDeckEditorSampleHandSize() const
|
||||||
{
|
{
|
||||||
return visualDeckEditorSampleHandSize;
|
return visualDeckEditorSampleHandSize;
|
||||||
}
|
}
|
||||||
bool getHorizontalHand() const
|
[[nodiscard]] bool getHorizontalHand() const
|
||||||
{
|
{
|
||||||
return horizontalHand;
|
return horizontalHand;
|
||||||
}
|
}
|
||||||
bool getInvertVerticalCoordinate() const
|
[[nodiscard]] bool getInvertVerticalCoordinate() const
|
||||||
{
|
{
|
||||||
return invertVerticalCoordinate;
|
return invertVerticalCoordinate;
|
||||||
}
|
}
|
||||||
int getMinPlayersForMultiColumnLayout() const
|
[[nodiscard]] int getMinPlayersForMultiColumnLayout() const
|
||||||
{
|
{
|
||||||
return minPlayersForMultiColumnLayout;
|
return minPlayersForMultiColumnLayout;
|
||||||
}
|
}
|
||||||
bool getTapAnimation() const
|
[[nodiscard]] bool getTapAnimation() const
|
||||||
{
|
{
|
||||||
return tapAnimation;
|
return tapAnimation;
|
||||||
}
|
}
|
||||||
bool getAutoRotateSidewaysLayoutCards() const
|
[[nodiscard]] bool getAutoRotateSidewaysLayoutCards() const
|
||||||
{
|
{
|
||||||
return autoRotateSidewaysLayoutCards;
|
return autoRotateSidewaysLayoutCards;
|
||||||
}
|
}
|
||||||
bool getOpenDeckInNewTab() const
|
[[nodiscard]] bool getOpenDeckInNewTab() const
|
||||||
{
|
{
|
||||||
return openDeckInNewTab;
|
return openDeckInNewTab;
|
||||||
}
|
}
|
||||||
int getRewindBufferingMs() const
|
[[nodiscard]] int getRewindBufferingMs() const
|
||||||
{
|
{
|
||||||
return rewindBufferingMs;
|
return rewindBufferingMs;
|
||||||
}
|
}
|
||||||
bool getChatMention() const
|
[[nodiscard]] bool getChatMention() const
|
||||||
{
|
{
|
||||||
return chatMention;
|
return chatMention;
|
||||||
}
|
}
|
||||||
bool getChatMentionCompleter() const
|
[[nodiscard]] bool getChatMentionCompleter() const
|
||||||
{
|
{
|
||||||
return chatMentionCompleter;
|
return chatMentionCompleter;
|
||||||
}
|
}
|
||||||
bool getChatMentionForeground() const
|
[[nodiscard]] bool getChatMentionForeground() const
|
||||||
{
|
{
|
||||||
return chatMentionForeground;
|
return chatMentionForeground;
|
||||||
}
|
}
|
||||||
bool getChatHighlightForeground() const
|
[[nodiscard]] bool getChatHighlightForeground() const
|
||||||
{
|
{
|
||||||
return chatHighlightForeground;
|
return chatHighlightForeground;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Currently selected index for the `Group by X` QComboBox
|
* Currently selected index for the `Group by X` QComboBox
|
||||||
*/
|
*/
|
||||||
int getZoneViewGroupByIndex() const
|
[[nodiscard]] int getZoneViewGroupByIndex() const
|
||||||
{
|
{
|
||||||
return zoneViewGroupByIndex;
|
return zoneViewGroupByIndex;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Currently selected index for the `Sort by X` QComboBox
|
* Currently selected index for the `Sort by X` QComboBox
|
||||||
*/
|
*/
|
||||||
int getZoneViewSortByIndex() const
|
[[nodiscard]] int getZoneViewSortByIndex() const
|
||||||
{
|
{
|
||||||
return zoneViewSortByIndex;
|
return zoneViewSortByIndex;
|
||||||
}
|
}
|
||||||
@@ -669,144 +743,148 @@ public:
|
|||||||
Returns if the view should be sorted into pile view.
|
Returns if the view should be sorted into pile view.
|
||||||
@return zoneViewPileView if the view should be sorted into pile view.
|
@return zoneViewPileView if the view should be sorted into pile view.
|
||||||
*/
|
*/
|
||||||
bool getZoneViewPileView() const
|
[[nodiscard]] bool getZoneViewPileView() const
|
||||||
{
|
{
|
||||||
return zoneViewPileView;
|
return zoneViewPileView;
|
||||||
}
|
}
|
||||||
bool getSoundEnabled() const
|
[[nodiscard]] bool getSoundEnabled() const
|
||||||
{
|
{
|
||||||
return soundEnabled;
|
return soundEnabled;
|
||||||
}
|
}
|
||||||
QString getSoundThemeName() const
|
[[nodiscard]] QString getSoundThemeName() const
|
||||||
{
|
{
|
||||||
return soundThemeName;
|
return soundThemeName;
|
||||||
}
|
}
|
||||||
bool getIgnoreUnregisteredUsers() const
|
[[nodiscard]] bool getIgnoreUnregisteredUsers() const
|
||||||
{
|
{
|
||||||
return ignoreUnregisteredUsers;
|
return ignoreUnregisteredUsers;
|
||||||
}
|
}
|
||||||
bool getIgnoreUnregisteredUserMessages() const
|
[[nodiscard]] bool getIgnoreUnregisteredUserMessages() const
|
||||||
{
|
{
|
||||||
return ignoreUnregisteredUserMessages;
|
return ignoreUnregisteredUserMessages;
|
||||||
}
|
}
|
||||||
int getPixmapCacheSize() const
|
[[nodiscard]] int getPixmapCacheSize() const
|
||||||
{
|
{
|
||||||
return pixmapCacheSize;
|
return pixmapCacheSize;
|
||||||
}
|
}
|
||||||
int getNetworkCacheSizeInMB() const
|
[[nodiscard]] int getNetworkCacheSizeInMB() const
|
||||||
{
|
{
|
||||||
return networkCacheSize;
|
return networkCacheSize;
|
||||||
}
|
}
|
||||||
int getRedirectCacheTtl() const
|
[[nodiscard]] int getRedirectCacheTtl() const
|
||||||
{
|
{
|
||||||
return redirectCacheTtl;
|
return redirectCacheTtl;
|
||||||
}
|
}
|
||||||
bool getScaleCards() const
|
[[nodiscard]] bool getScaleCards() const
|
||||||
{
|
{
|
||||||
return scaleCards;
|
return scaleCards;
|
||||||
}
|
}
|
||||||
int getStackCardOverlapPercent() const
|
[[nodiscard]] int getStackCardOverlapPercent() const
|
||||||
{
|
{
|
||||||
return verticalCardOverlapPercent;
|
return verticalCardOverlapPercent;
|
||||||
}
|
}
|
||||||
bool getShowMessagePopup() const
|
[[nodiscard]] bool getShowMessagePopup() const
|
||||||
{
|
{
|
||||||
return showMessagePopups;
|
return showMessagePopups;
|
||||||
}
|
}
|
||||||
bool getShowMentionPopup() const
|
[[nodiscard]] bool getShowMentionPopup() const
|
||||||
{
|
{
|
||||||
return showMentionPopups;
|
return showMentionPopups;
|
||||||
}
|
}
|
||||||
bool getRoomHistory() const
|
[[nodiscard]] bool getRoomHistory() const
|
||||||
{
|
{
|
||||||
return roomHistory;
|
return roomHistory;
|
||||||
}
|
}
|
||||||
bool getLeftJustified() const
|
[[nodiscard]] bool getLeftJustified() const
|
||||||
{
|
{
|
||||||
return leftJustified;
|
return leftJustified;
|
||||||
}
|
}
|
||||||
int getMasterVolume() const
|
[[nodiscard]] int getMasterVolume() const
|
||||||
{
|
{
|
||||||
return masterVolume;
|
return masterVolume;
|
||||||
}
|
}
|
||||||
int getCardInfoViewMode() const
|
[[nodiscard]] int getCardInfoViewMode() const
|
||||||
{
|
{
|
||||||
return cardInfoViewMode;
|
return cardInfoViewMode;
|
||||||
}
|
}
|
||||||
QStringList getCountries() const;
|
[[nodiscard]] QStringList getCountries() const;
|
||||||
QString getHighlightWords() const
|
[[nodiscard]] QString getHighlightWords() const
|
||||||
{
|
{
|
||||||
return highlightWords;
|
return highlightWords;
|
||||||
}
|
}
|
||||||
QString getGameDescription() const
|
[[nodiscard]] QString getGameDescription() const
|
||||||
{
|
{
|
||||||
return gameDescription;
|
return gameDescription;
|
||||||
}
|
}
|
||||||
int getMaxPlayers() const
|
[[nodiscard]] int getMaxPlayers() const
|
||||||
{
|
{
|
||||||
return maxPlayers;
|
return maxPlayers;
|
||||||
}
|
}
|
||||||
QString getGameTypes() const
|
[[nodiscard]] QString getGameTypes() const
|
||||||
{
|
{
|
||||||
return gameTypes;
|
return gameTypes;
|
||||||
}
|
}
|
||||||
bool getOnlyBuddies() const
|
[[nodiscard]] bool getOnlyBuddies() const
|
||||||
{
|
{
|
||||||
return onlyBuddies;
|
return onlyBuddies;
|
||||||
}
|
}
|
||||||
bool getOnlyRegistered() const
|
[[nodiscard]] bool getOnlyRegistered() const
|
||||||
{
|
{
|
||||||
return onlyRegistered;
|
return onlyRegistered;
|
||||||
}
|
}
|
||||||
bool getSpectatorsAllowed() const
|
[[nodiscard]] bool getSpectatorsAllowed() const
|
||||||
{
|
{
|
||||||
return spectatorsAllowed;
|
return spectatorsAllowed;
|
||||||
}
|
}
|
||||||
bool getSpectatorsNeedPassword() const
|
[[nodiscard]] bool getSpectatorsNeedPassword() const
|
||||||
{
|
{
|
||||||
return spectatorsNeedPassword;
|
return spectatorsNeedPassword;
|
||||||
}
|
}
|
||||||
bool getSpectatorsCanTalk() const
|
[[nodiscard]] bool getSpectatorsCanTalk() const
|
||||||
{
|
{
|
||||||
return spectatorsCanTalk;
|
return spectatorsCanTalk;
|
||||||
}
|
}
|
||||||
bool getSpectatorsCanSeeEverything() const
|
[[nodiscard]] bool getSpectatorsCanSeeEverything() const
|
||||||
{
|
{
|
||||||
return spectatorsCanSeeEverything;
|
return spectatorsCanSeeEverything;
|
||||||
}
|
}
|
||||||
int getDefaultStartingLifeTotal() const
|
[[nodiscard]] int getDefaultStartingLifeTotal() const
|
||||||
{
|
{
|
||||||
return defaultStartingLifeTotal;
|
return defaultStartingLifeTotal;
|
||||||
}
|
}
|
||||||
bool getCreateGameAsSpectator() const
|
[[nodiscard]] bool getShareDecklistsOnLoad() const
|
||||||
|
{
|
||||||
|
return shareDecklistsOnLoad;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getCreateGameAsSpectator() const
|
||||||
{
|
{
|
||||||
return createGameAsSpectator;
|
return createGameAsSpectator;
|
||||||
}
|
}
|
||||||
bool getRememberGameSettings() const
|
[[nodiscard]] bool getRememberGameSettings() const
|
||||||
{
|
{
|
||||||
return rememberGameSettings;
|
return rememberGameSettings;
|
||||||
}
|
}
|
||||||
int getKeepAlive() const
|
[[nodiscard]] int getKeepAlive() const override
|
||||||
{
|
{
|
||||||
return keepalive;
|
return keepalive;
|
||||||
}
|
}
|
||||||
int getTimeOut() const
|
[[nodiscard]] int getTimeOut() const override
|
||||||
{
|
{
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
int getMaxFontSize() const
|
[[nodiscard]] int getMaxFontSize() const
|
||||||
{
|
{
|
||||||
return maxFontSize;
|
return maxFontSize;
|
||||||
}
|
}
|
||||||
void setClientID(const QString &clientID);
|
void setClientID(const QString &clientID);
|
||||||
void setClientVersion(const QString &clientVersion);
|
void setClientVersion(const QString &clientVersion);
|
||||||
void setKnownMissingFeatures(const QString &_knownMissingFeatures);
|
void setKnownMissingFeatures(const QString &_knownMissingFeatures) override;
|
||||||
void setUseTearOffMenus(bool _useTearOffMenus);
|
void setUseTearOffMenus(bool _useTearOffMenus);
|
||||||
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
|
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
|
||||||
void setCardViewExpandedRowsMax(int value);
|
void setCardViewExpandedRowsMax(int value);
|
||||||
void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
|
void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
|
||||||
void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
|
void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
|
||||||
QString getClientID()
|
QString getClientID() override
|
||||||
{
|
{
|
||||||
return clientID;
|
return clientID;
|
||||||
}
|
}
|
||||||
@@ -814,7 +892,7 @@ public:
|
|||||||
{
|
{
|
||||||
return clientVersion;
|
return clientVersion;
|
||||||
}
|
}
|
||||||
QString getKnownMissingFeatures()
|
QString getKnownMissingFeatures() override
|
||||||
{
|
{
|
||||||
return knownMissingFeatures;
|
return knownMissingFeatures;
|
||||||
}
|
}
|
||||||
@@ -822,73 +900,73 @@ public:
|
|||||||
{
|
{
|
||||||
return useTearOffMenus;
|
return useTearOffMenus;
|
||||||
}
|
}
|
||||||
int getCardViewInitialRowsMax() const
|
[[nodiscard]] int getCardViewInitialRowsMax() const
|
||||||
{
|
{
|
||||||
return cardViewInitialRowsMax;
|
return cardViewInitialRowsMax;
|
||||||
}
|
}
|
||||||
int getCardViewExpandedRowsMax() const
|
[[nodiscard]] int getCardViewExpandedRowsMax() const
|
||||||
{
|
{
|
||||||
return cardViewExpandedRowsMax;
|
return cardViewExpandedRowsMax;
|
||||||
}
|
}
|
||||||
bool getCloseEmptyCardView() const
|
[[nodiscard]] bool getCloseEmptyCardView() const
|
||||||
{
|
{
|
||||||
return closeEmptyCardView;
|
return closeEmptyCardView;
|
||||||
}
|
}
|
||||||
bool getFocusCardViewSearchBar() const
|
[[nodiscard]] bool getFocusCardViewSearchBar() const
|
||||||
{
|
{
|
||||||
return focusCardViewSearchBar;
|
return focusCardViewSearchBar;
|
||||||
}
|
}
|
||||||
ShortcutsSettings &shortcuts() const
|
[[nodiscard]] ShortcutsSettings &shortcuts() const
|
||||||
{
|
{
|
||||||
return *shortcutsSettings;
|
return *shortcutsSettings;
|
||||||
}
|
}
|
||||||
CardDatabaseSettings &cardDatabase() const
|
[[nodiscard]] CardDatabaseSettings *cardDatabase() const
|
||||||
{
|
{
|
||||||
return *cardDatabaseSettings;
|
return cardDatabaseSettings;
|
||||||
}
|
}
|
||||||
ServersSettings &servers() const
|
[[nodiscard]] ServersSettings &servers() const
|
||||||
{
|
{
|
||||||
return *serversSettings;
|
return *serversSettings;
|
||||||
}
|
}
|
||||||
MessageSettings &messages() const
|
[[nodiscard]] MessageSettings &messages() const
|
||||||
{
|
{
|
||||||
return *messageSettings;
|
return *messageSettings;
|
||||||
}
|
}
|
||||||
GameFiltersSettings &gameFilters() const
|
[[nodiscard]] GameFiltersSettings &gameFilters() const
|
||||||
{
|
{
|
||||||
return *gameFiltersSettings;
|
return *gameFiltersSettings;
|
||||||
}
|
}
|
||||||
LayoutsSettings &layouts() const
|
[[nodiscard]] LayoutsSettings &layouts() const
|
||||||
{
|
{
|
||||||
return *layoutsSettings;
|
return *layoutsSettings;
|
||||||
}
|
}
|
||||||
DownloadSettings &downloads() const
|
[[nodiscard]] DownloadSettings &downloads() const
|
||||||
{
|
{
|
||||||
return *downloadSettings;
|
return *downloadSettings;
|
||||||
}
|
}
|
||||||
RecentsSettings &recents() const
|
[[nodiscard]] RecentsSettings &recents() const
|
||||||
{
|
{
|
||||||
return *recentsSettings;
|
return *recentsSettings;
|
||||||
}
|
}
|
||||||
CardOverrideSettings &cardOverrides() const
|
[[nodiscard]] CardOverrideSettings &cardOverrides() const
|
||||||
{
|
{
|
||||||
return *cardOverrideSettings;
|
return *cardOverrideSettings;
|
||||||
}
|
}
|
||||||
DebugSettings &debug() const
|
[[nodiscard]] DebugSettings &debug() const
|
||||||
{
|
{
|
||||||
return *debugSettings;
|
return *debugSettings;
|
||||||
}
|
}
|
||||||
CardCounterSettings &cardCounters() const;
|
[[nodiscard]] CardCounterSettings &cardCounters() const;
|
||||||
|
|
||||||
bool getIsPortableBuild() const
|
[[nodiscard]] bool getIsPortableBuild() const
|
||||||
{
|
{
|
||||||
return isPortableBuild;
|
return isPortableBuild;
|
||||||
}
|
}
|
||||||
bool getDownloadSpoilersStatus() const
|
[[nodiscard]] bool getDownloadSpoilersStatus() const
|
||||||
{
|
{
|
||||||
return mbDownloadSpoilers;
|
return mbDownloadSpoilers;
|
||||||
}
|
}
|
||||||
bool getRoundCardCorners() const
|
[[nodiscard]] bool getRoundCardCorners() const
|
||||||
{
|
{
|
||||||
return roundCardCorners;
|
return roundCardCorners;
|
||||||
}
|
}
|
||||||
@@ -915,6 +993,8 @@ public slots:
|
|||||||
void setSpoilerDatabasePath(const QString &_spoilerDatabasePath);
|
void setSpoilerDatabasePath(const QString &_spoilerDatabasePath);
|
||||||
void setTokenDatabasePath(const QString &_tokenDatabasePath);
|
void setTokenDatabasePath(const QString &_tokenDatabasePath);
|
||||||
void setThemeName(const QString &_themeName);
|
void setThemeName(const QString &_themeName);
|
||||||
|
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
||||||
|
void setHomeTabBackgroundShuffleFrequency(int _frequency);
|
||||||
void setTabVisualDeckStorageOpen(bool value);
|
void setTabVisualDeckStorageOpen(bool value);
|
||||||
void setTabServerOpen(bool value);
|
void setTabServerOpen(bool value);
|
||||||
void setTabAccountOpen(bool value);
|
void setTabAccountOpen(bool value);
|
||||||
@@ -932,6 +1012,7 @@ public slots:
|
|||||||
void setDoubleClickToPlay(QT_STATE_CHANGED_T _doubleClickToPlay);
|
void setDoubleClickToPlay(QT_STATE_CHANGED_T _doubleClickToPlay);
|
||||||
void setClickPlaysAllSelected(QT_STATE_CHANGED_T _clickPlaysAllSelected);
|
void setClickPlaysAllSelected(QT_STATE_CHANGED_T _clickPlaysAllSelected);
|
||||||
void setPlayToStack(QT_STATE_CHANGED_T _playToStack);
|
void setPlayToStack(QT_STATE_CHANGED_T _playToStack);
|
||||||
|
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 setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
|
||||||
@@ -960,6 +1041,10 @@ public slots:
|
|||||||
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
|
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
|
||||||
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
|
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
|
||||||
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
|
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
|
||||||
|
void setVisualDeckEditorCardSize(int _visualDeckEditorCardSize);
|
||||||
|
void setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize);
|
||||||
|
void setEDHRecCardSize(int _EDHRecCardSize);
|
||||||
|
void setArchidektPreviewCardSize(int _archidektPreviewCardSize);
|
||||||
void setDefaultDeckEditorType(int value);
|
void setDefaultDeckEditorType(int value);
|
||||||
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
|
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
|
||||||
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
|
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
|
||||||
@@ -1005,8 +1090,13 @@ public slots:
|
|||||||
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
|
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
|
||||||
void setCreateGameAsSpectator(const bool _createGameAsSpectator);
|
void setCreateGameAsSpectator(const bool _createGameAsSpectator);
|
||||||
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
||||||
|
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
|
||||||
void setRememberGameSettings(const bool _rememberGameSettings);
|
void setRememberGameSettings(const bool _rememberGameSettings);
|
||||||
void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
|
void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
|
||||||
|
void setStartupCardUpdateCheckPromptForUpdate(bool value);
|
||||||
|
void setStartupCardUpdateCheckAlwaysUpdate(bool value);
|
||||||
|
void setCardUpdateCheckInterval(int value);
|
||||||
|
void setLastCardUpdateCheck(QDate value);
|
||||||
void setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate);
|
void setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate);
|
||||||
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
||||||
void setUpdateReleaseChannelIndex(int value);
|
void setUpdateReleaseChannelIndex(int value);
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
|
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
|
||||||
: SettingsManager(settingsPath + "global.ini", parent)
|
: SettingsManager(settingsPath + "global.ini", "cards", "counters", parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @file card_counter_settings.h
|
||||||
|
* @ingroup GameSettings
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef CARD_COUNTER_SETTINGS_H
|
#ifndef CARD_COUNTER_SETTINGS_H
|
||||||
#define CARD_COUNTER_SETTINGS_H
|
#define CARD_COUNTER_SETTINGS_H
|
||||||
|
|
||||||
#include "settings_manager.h"
|
#include <libcockatrice/settings/settings_manager.h>
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
class QColor;
|
class QColor;
|
||||||
@@ -15,9 +19,9 @@ class CardCounterSettings : public SettingsManager
|
|||||||
public:
|
public:
|
||||||
CardCounterSettings(const QString &settingsPath, QObject *parent = nullptr);
|
CardCounterSettings(const QString &settingsPath, QObject *parent = nullptr);
|
||||||
|
|
||||||
QColor color(int counterId) const;
|
[[nodiscard]] QColor color(int counterId) const;
|
||||||
|
|
||||||
QString displayName(int counterId) const;
|
[[nodiscard]] QString displayName(int counterId) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setColor(int counterId, const QColor &color);
|
void setColor(int counterId, const QColor &color);
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @file shortcut_treeview.h
|
||||||
|
* @ingroup CoreSettings
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef SHORTCUT_TREEVIEW_H
|
#ifndef SHORTCUT_TREEVIEW_H
|
||||||
#define SHORTCUT_TREEVIEW_H
|
#define SHORTCUT_TREEVIEW_H
|
||||||
|
|
||||||
#include <QModelIndex>
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
@@ -16,7 +21,7 @@ public:
|
|||||||
explicit ShortcutFilterProxyModel(QObject *parent = nullptr);
|
explicit ShortcutFilterProxyModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
[[nodiscard]] bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShortcutTreeView : public QTreeView
|
class ShortcutTreeView : public QTreeView
|
||||||
@@ -115,6 +115,13 @@ ShortcutKey ShortcutsSettings::getShortcut(const QString &name) const
|
|||||||
return getDefaultShortcut(name);
|
return getDefaultShortcut(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the first shortcut for the given action.
|
||||||
|
*
|
||||||
|
* NOTE: In most cases you should be using ShortcutsSettings::getShortcut instead,
|
||||||
|
* as that will return all shortcuts if there are multiple shortcuts.
|
||||||
|
* The only reason to use this method is if an object does not accept multiple shortcuts, such as with QButtons.
|
||||||
|
*/
|
||||||
QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const
|
QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const
|
||||||
{
|
{
|
||||||
return getShortcut(name).at(0);
|
return getShortcut(name).at(0);
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @file shortcuts_settings.h
|
||||||
|
* @ingroup CoreSettings
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef SHORTCUTSSETTINGS_H
|
#ifndef SHORTCUTSSETTINGS_H
|
||||||
#define SHORTCUTSSETTINGS_H
|
#define SHORTCUTSSETTINGS_H
|
||||||
|
|
||||||
@@ -27,6 +33,7 @@ public:
|
|||||||
Move_bottom,
|
Move_bottom,
|
||||||
Gameplay,
|
Gameplay,
|
||||||
Drawing,
|
Drawing,
|
||||||
|
Hand,
|
||||||
Chat_room,
|
Chat_room,
|
||||||
Game_window,
|
Game_window,
|
||||||
Load_deck,
|
Load_deck,
|
||||||
@@ -65,6 +72,8 @@ public:
|
|||||||
return QApplication::translate("shortcutsTab", "Gameplay");
|
return QApplication::translate("shortcutsTab", "Gameplay");
|
||||||
case Drawing:
|
case Drawing:
|
||||||
return QApplication::translate("shortcutsTab", "Drawing");
|
return QApplication::translate("shortcutsTab", "Drawing");
|
||||||
|
case Hand:
|
||||||
|
return QApplication::translate("shortcutsTab", "Hand");
|
||||||
case Chat_room:
|
case Chat_room:
|
||||||
return QApplication::translate("shortcutsTab", "Chat Room");
|
return QApplication::translate("shortcutsTab", "Chat Room");
|
||||||
case Game_window:
|
case Game_window:
|
||||||
@@ -90,15 +99,15 @@ public:
|
|||||||
void setSequence(const QList &_sequence)
|
void setSequence(const QList &_sequence)
|
||||||
{
|
{
|
||||||
QList::operator=(_sequence);
|
QList::operator=(_sequence);
|
||||||
};
|
}
|
||||||
QString getName() const
|
[[nodiscard]] QString getName() const
|
||||||
{
|
{
|
||||||
return QApplication::translate("shortcutsTab", name.toUtf8().data());
|
return QApplication::translate("shortcutsTab", name.toUtf8().data());
|
||||||
};
|
}
|
||||||
QString getGroupName() const
|
[[nodiscard]] QString getGroupName() const
|
||||||
{
|
{
|
||||||
return ShortcutGroup::getGroupName(group);
|
return ShortcutGroup::getGroupName(group);
|
||||||
};
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString name;
|
QString name;
|
||||||
@@ -111,24 +120,24 @@ class ShortcutsSettings : public QObject
|
|||||||
public:
|
public:
|
||||||
explicit ShortcutsSettings(const QString &settingsFilePath, QObject *parent = nullptr);
|
explicit ShortcutsSettings(const QString &settingsFilePath, QObject *parent = nullptr);
|
||||||
|
|
||||||
ShortcutKey getDefaultShortcut(const QString &name) const;
|
[[nodiscard]] ShortcutKey getDefaultShortcut(const QString &name) const;
|
||||||
ShortcutKey getShortcut(const QString &name) const;
|
[[nodiscard]] ShortcutKey getShortcut(const QString &name) const;
|
||||||
QKeySequence getSingleShortcut(const QString &name) const;
|
[[nodiscard]] QKeySequence getSingleShortcut(const QString &name) const;
|
||||||
QString getDefaultShortcutString(const QString &name) const;
|
[[nodiscard]] QString getDefaultShortcutString(const QString &name) const;
|
||||||
QString getShortcutString(const QString &name) const;
|
[[nodiscard]] QString getShortcutString(const QString &name) const;
|
||||||
QString getShortcutFriendlyName(const QString &shortcutName) const;
|
[[nodiscard]] QString getShortcutFriendlyName(const QString &shortcutName) const;
|
||||||
QList<QString> getAllShortcutKeys() const
|
[[nodiscard]] QList<QString> getAllShortcutKeys() const
|
||||||
{
|
{
|
||||||
return shortCuts.keys();
|
return shortCuts.keys();
|
||||||
};
|
}
|
||||||
|
|
||||||
void setShortcuts(const QString &name, const QList<QKeySequence> &Sequence);
|
void setShortcuts(const QString &name, const QList<QKeySequence> &Sequence);
|
||||||
void setShortcuts(const QString &name, const QKeySequence &Sequence);
|
void setShortcuts(const QString &name, const QKeySequence &Sequence);
|
||||||
void setShortcuts(const QString &name, const QString &sequences);
|
void setShortcuts(const QString &name, const QString &sequences);
|
||||||
|
|
||||||
bool isKeyAllowed(const QString &name, const QString &sequences) const;
|
[[nodiscard]] bool isKeyAllowed(const QString &name, const QString &sequences) const;
|
||||||
bool isValid(const QString &name, const QString &sequences) const;
|
[[nodiscard]] bool isValid(const QString &name, const QString &sequences) const;
|
||||||
QStringList findOverlaps(const QString &name, const QString &sequences) const;
|
[[nodiscard]] QStringList findOverlaps(const QString &name, const QString &sequences) const;
|
||||||
|
|
||||||
void resetAllShortcuts();
|
void resetAllShortcuts();
|
||||||
void clearAllShortcuts();
|
void clearAllShortcuts();
|
||||||
@@ -143,8 +152,8 @@ private:
|
|||||||
QString settingsFilePath;
|
QString settingsFilePath;
|
||||||
QHash<QString, ShortcutKey> shortCuts;
|
QHash<QString, ShortcutKey> shortCuts;
|
||||||
|
|
||||||
QString stringifySequence(const QList<QKeySequence> &Sequence) const;
|
[[nodiscard]] QString stringifySequence(const QList<QKeySequence> &Sequence) const;
|
||||||
QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
|
[[nodiscard]] QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
|
||||||
|
|
||||||
const QHash<QString, ShortcutKey> defaultShortCuts = {
|
const QHash<QString, ShortcutKey> defaultShortCuts = {
|
||||||
{"MainWindow/aCheckCardUpdates", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Check for Card Updates..."),
|
{"MainWindow/aCheckCardUpdates", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Check for Card Updates..."),
|
||||||
@@ -413,6 +422,10 @@ private:
|
|||||||
{"Player/aSetCounter_storm", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Other Counters..."),
|
{"Player/aSetCounter_storm", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Other Counters..."),
|
||||||
parseSequenceString("Ctrl+\\"),
|
parseSequenceString("Ctrl+\\"),
|
||||||
ShortcutGroup::Player_Counters)},
|
ShortcutGroup::Player_Counters)},
|
||||||
|
{"Player/aIncrementAllCardCounters",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increment all card counters"),
|
||||||
|
parseSequenceString("Ctrl+Shift+A"),
|
||||||
|
ShortcutGroup::Playing_Area)},
|
||||||
{"Player/aIncP", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Power (+1/+0)"),
|
{"Player/aIncP", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Power (+1/+0)"),
|
||||||
parseSequenceString("Ctrl++;Ctrl+="),
|
parseSequenceString("Ctrl++;Ctrl+="),
|
||||||
ShortcutGroup::Power_Toughness)},
|
ShortcutGroup::Power_Toughness)},
|
||||||
@@ -530,6 +543,9 @@ private:
|
|||||||
{"Player/aSelectColumn", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Column"),
|
{"Player/aSelectColumn", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Column"),
|
||||||
parseSequenceString("Ctrl+Shift+C"),
|
parseSequenceString("Ctrl+Shift+C"),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
|
{"Player/aRevealToAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Reveal Selected Cards to All Players"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Playing_Area)},
|
||||||
{"Player/aMoveToBottomLibrary", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Bottom of Library"),
|
{"Player/aMoveToBottomLibrary", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Bottom of Library"),
|
||||||
parseSequenceString("Ctrl+B"),
|
parseSequenceString("Ctrl+B"),
|
||||||
ShortcutGroup::Move_selected)},
|
ShortcutGroup::Move_selected)},
|
||||||
@@ -659,6 +675,22 @@ private:
|
|||||||
{"Player/aAlwaysLookAtTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Look At Top Card"),
|
{"Player/aAlwaysLookAtTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Look At Top Card"),
|
||||||
parseSequenceString("Ctrl+Shift+N"),
|
parseSequenceString("Ctrl+Shift+N"),
|
||||||
ShortcutGroup::Drawing)},
|
ShortcutGroup::Drawing)},
|
||||||
|
{"Player/aSortHandByName", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Sort Hand by Name"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Hand)},
|
||||||
|
{"Player/aSortHandByType", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Sort Hand by Type"),
|
||||||
|
parseSequenceString("Ctrl+Shift+H"),
|
||||||
|
ShortcutGroup::Hand)},
|
||||||
|
{"Player/aSortHandByManaValue", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Sort Hand by Mana Value"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Hand)},
|
||||||
|
{"Player/aRevealHandToAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Reveal Hand to All Players"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Hand)},
|
||||||
|
{"Player/aRevealRandomHandCardToAll",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Reveal Random Card to All Players"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Hand)},
|
||||||
{"Player/aRotateViewCW", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Rotate View Clockwise"),
|
{"Player/aRotateViewCW", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Rotate View Clockwise"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Gameplay)},
|
ShortcutGroup::Gameplay)},
|
||||||
@@ -700,6 +732,8 @@ private:
|
|||||||
ShortcutGroup::Replays)},
|
ShortcutGroup::Replays)},
|
||||||
{"Tabs/aTabDeckEditor",
|
{"Tabs/aTabDeckEditor",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Deck Editor"), parseSequenceString(""), ShortcutGroup::Tabs)},
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Deck Editor"), parseSequenceString(""), ShortcutGroup::Tabs)},
|
||||||
|
{"Tabs/aTabHome",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Home"), parseSequenceString(""), ShortcutGroup::Tabs)},
|
||||||
{"Tabs/aTabVisualDeckStorage", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Visual Deck Storage"),
|
{"Tabs/aTabVisualDeckStorage", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Visual Deck Storage"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Tabs)},
|
ShortcutGroup::Tabs)},
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "sound_engine.h"
|
#include "sound_engine.h"
|
||||||
|
|
||||||
#include "../settings/cache_settings.h"
|
#include "settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMediaPlayer>
|
#include <QMediaPlayer>
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @file sound_engine.h
|
||||||
|
* @ingroup Core
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef SOUNDENGINE_H
|
#ifndef SOUNDENGINE_H
|
||||||
#define SOUNDENGINE_H
|
#define SOUNDENGINE_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,158 +0,0 @@
|
|||||||
#ifndef TAB_GENERIC_DECK_EDITOR_H
|
|
||||||
#define TAB_GENERIC_DECK_EDITOR_H
|
|
||||||
|
|
||||||
#include "../../game/cards/card_info.h"
|
|
||||||
#include "../menus/deck_editor/deck_editor_menu.h"
|
|
||||||
#include "../ui/widgets/deck_editor/deck_editor_card_info_dock_widget.h"
|
|
||||||
#include "../ui/widgets/deck_editor/deck_editor_database_display_widget.h"
|
|
||||||
#include "../ui/widgets/deck_editor/deck_editor_deck_dock_widget.h"
|
|
||||||
#include "../ui/widgets/deck_editor/deck_editor_filter_dock_widget.h"
|
|
||||||
#include "../ui/widgets/deck_editor/deck_editor_printing_selector_dock_widget.h"
|
|
||||||
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
|
|
||||||
#include "tab.h"
|
|
||||||
|
|
||||||
class CardDatabaseModel;
|
|
||||||
class CardDatabaseDisplayModel;
|
|
||||||
|
|
||||||
class CardInfoFrameWidget;
|
|
||||||
class DeckLoader;
|
|
||||||
class DeckEditorMenu;
|
|
||||||
class DeckEditorCardInfoDockWidget;
|
|
||||||
class DeckEditorDatabaseDisplayWidget;
|
|
||||||
class DeckEditorDeckDockWidget;
|
|
||||||
class DeckEditorFilterDockWidget;
|
|
||||||
class DeckEditorPrintingSelectorDockWidget;
|
|
||||||
class DeckPreviewDeckTagsDisplayWidget;
|
|
||||||
class Response;
|
|
||||||
class FilterTreeModel;
|
|
||||||
class FilterBuilder;
|
|
||||||
|
|
||||||
class QTreeView;
|
|
||||||
class QTextEdit;
|
|
||||||
class QLabel;
|
|
||||||
class QComboBox;
|
|
||||||
class QGroupBox;
|
|
||||||
class QMessageBox;
|
|
||||||
class QHBoxLayout;
|
|
||||||
class QVBoxLayout;
|
|
||||||
class QPushButton;
|
|
||||||
class QDockWidget;
|
|
||||||
class QMenu;
|
|
||||||
class QAction;
|
|
||||||
|
|
||||||
class AbstractTabDeckEditor : public Tab
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
friend class DeckEditorMenu;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AbstractTabDeckEditor(TabSupervisor *_tabSupervisor);
|
|
||||||
|
|
||||||
// UI and Navigation
|
|
||||||
virtual void createMenus() = 0;
|
|
||||||
[[nodiscard]] virtual QString getTabText() const override = 0;
|
|
||||||
bool confirmClose();
|
|
||||||
virtual void retranslateUi() override = 0;
|
|
||||||
|
|
||||||
// Deck Management
|
|
||||||
void openDeck(DeckLoader *deck);
|
|
||||||
DeckLoader *getDeckList() const;
|
|
||||||
void setModified(bool _windowModified);
|
|
||||||
|
|
||||||
// UI Elements
|
|
||||||
DeckEditorMenu *deckMenu;
|
|
||||||
DeckEditorDatabaseDisplayWidget *databaseDisplayDockWidget;
|
|
||||||
DeckEditorCardInfoDockWidget *cardInfoDockWidget;
|
|
||||||
DeckEditorDeckDockWidget *deckDockWidget;
|
|
||||||
DeckEditorFilterDockWidget *filterDockWidget;
|
|
||||||
DeckEditorPrintingSelectorDockWidget *printingSelectorDockWidget;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
virtual void onDeckChanged();
|
|
||||||
virtual void onDeckModified();
|
|
||||||
void updateCard(CardInfoPtr _card);
|
|
||||||
void actAddCard(CardInfoPtr info);
|
|
||||||
void actAddCardToSideboard(CardInfoPtr info);
|
|
||||||
void actDecrementCard(CardInfoPtr info);
|
|
||||||
void actDecrementCardFromSideboard(CardInfoPtr info);
|
|
||||||
void actOpenRecent(const QString &fileName);
|
|
||||||
void filterTreeChanged(FilterTree *filterTree);
|
|
||||||
void closeRequest(bool forced = false) override;
|
|
||||||
virtual void showPrintingSelector() = 0;
|
|
||||||
virtual void dockTopLevelChanged(bool topLevel) = 0;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void openDeckEditor(const DeckLoader *deckLoader);
|
|
||||||
void deckEditorClosing(AbstractTabDeckEditor *tab);
|
|
||||||
void decrementCard(CardInfoPtr card, QString zoneName);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
// Deck Operations
|
|
||||||
virtual void actNewDeck();
|
|
||||||
void cleanDeckAndResetModified();
|
|
||||||
virtual void actLoadDeck();
|
|
||||||
bool actSaveDeck();
|
|
||||||
virtual bool actSaveDeckAs();
|
|
||||||
virtual void actLoadDeckFromClipboard();
|
|
||||||
void actEditDeckInClipboard();
|
|
||||||
void actEditDeckInClipboardRaw();
|
|
||||||
void actSaveDeckToClipboard();
|
|
||||||
void actSaveDeckToClipboardNoSetInfo();
|
|
||||||
void actSaveDeckToClipboardRaw();
|
|
||||||
void actSaveDeckToClipboardRawNoSetInfo();
|
|
||||||
void actPrintDeck();
|
|
||||||
void actExportDeckDecklist();
|
|
||||||
void actExportDeckDecklistXyz();
|
|
||||||
void actAnalyzeDeckDeckstats();
|
|
||||||
void actAnalyzeDeckTappedout();
|
|
||||||
|
|
||||||
// Remote Save
|
|
||||||
void saveDeckRemoteFinished(const Response &r);
|
|
||||||
|
|
||||||
// UI Layout Management
|
|
||||||
virtual void loadLayout() = 0;
|
|
||||||
virtual void restartLayout() = 0;
|
|
||||||
virtual void freeDocksSize() = 0;
|
|
||||||
virtual void refreshShortcuts() = 0;
|
|
||||||
|
|
||||||
bool eventFilter(QObject *o, QEvent *e) override;
|
|
||||||
virtual void dockVisibleTriggered() = 0;
|
|
||||||
virtual void dockFloatingTriggered() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual void setDeck(DeckLoader *_deck);
|
|
||||||
void editDeckInClipboard(bool annotated);
|
|
||||||
void exportToDecklistWebsite(DeckLoader::DecklistWebsite website);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* @brief Enum for selecting deck open location
|
|
||||||
*/
|
|
||||||
enum DeckOpenLocation
|
|
||||||
{
|
|
||||||
CANCELLED,
|
|
||||||
SAME_TAB,
|
|
||||||
NEW_TAB
|
|
||||||
};
|
|
||||||
|
|
||||||
DeckOpenLocation confirmOpen(bool openInSameTabIfBlank = true);
|
|
||||||
QMessageBox *createSaveConfirmationWindow();
|
|
||||||
bool isBlankNewDeck() const;
|
|
||||||
|
|
||||||
// Helper functions for card actions
|
|
||||||
void addCardHelper(CardInfoPtr info, QString zoneName);
|
|
||||||
void actSwapCard(CardInfoPtr info, QString zoneName);
|
|
||||||
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
|
|
||||||
|
|
||||||
// UI Menu Elements
|
|
||||||
QMenu *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu, *printingSelectorDockMenu;
|
|
||||||
|
|
||||||
QAction *aResetLayout;
|
|
||||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
|
||||||
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
|
||||||
|
|
||||||
bool modified = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // TAB_GENERIC_DECK_EDITOR_H
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#ifndef WINDOW_DECKEDITOR_H
|
|
||||||
#define WINDOW_DECKEDITOR_H
|
|
||||||
|
|
||||||
#include "../../game/cards/card_info.h"
|
|
||||||
#include "../game_logic/key_signals.h"
|
|
||||||
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
|
|
||||||
#include "abstract_tab_deck_editor.h"
|
|
||||||
|
|
||||||
class CardDatabaseModel;
|
|
||||||
class CardDatabaseDisplayModel;
|
|
||||||
class DeckListModel;
|
|
||||||
|
|
||||||
class QLabel;
|
|
||||||
class DeckLoader;
|
|
||||||
|
|
||||||
class TabDeckEditor : public AbstractTabDeckEditor
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void loadLayout() override;
|
|
||||||
void restartLayout() override;
|
|
||||||
void freeDocksSize() override;
|
|
||||||
void refreshShortcuts() override;
|
|
||||||
|
|
||||||
bool eventFilter(QObject *o, QEvent *e) override;
|
|
||||||
void dockVisibleTriggered() override;
|
|
||||||
void dockFloatingTriggered() override;
|
|
||||||
void dockTopLevelChanged(bool topLevel) override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TabDeckEditor(TabSupervisor *_tabSupervisor);
|
|
||||||
void retranslateUi() override;
|
|
||||||
QString getTabText() const override;
|
|
||||||
void createMenus() override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void showPrintingSelector() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
#ifndef TAB_GAME_H
|
|
||||||
#define TAB_GAME_H
|
|
||||||
|
|
||||||
#include "../../client/tearoff_menu.h"
|
|
||||||
#include "../../game/player/player.h"
|
|
||||||
#include "../ui/widgets/visual_deck_storage/visual_deck_storage_widget.h"
|
|
||||||
#include "pb/event_leave.pb.h"
|
|
||||||
#include "pb/serverinfo_game.pb.h"
|
|
||||||
#include "tab.h"
|
|
||||||
|
|
||||||
#include <QCompleter>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game");
|
|
||||||
|
|
||||||
class UserListProxy;
|
|
||||||
class DeckViewContainer;
|
|
||||||
class AbstractClient;
|
|
||||||
class CardDatabase;
|
|
||||||
class GameView;
|
|
||||||
class GameScene;
|
|
||||||
class CardInfoFrameWidget;
|
|
||||||
class MessageLogWidget;
|
|
||||||
class QTimer;
|
|
||||||
class QSplitter;
|
|
||||||
class QLabel;
|
|
||||||
class QToolButton;
|
|
||||||
class QMenu;
|
|
||||||
class ZoneViewLayout;
|
|
||||||
class ZoneViewWidget;
|
|
||||||
class PhasesToolbar;
|
|
||||||
class PlayerListWidget;
|
|
||||||
class ReplayTimelineWidget;
|
|
||||||
class Response;
|
|
||||||
class GameEventContainer;
|
|
||||||
class GameEventContext;
|
|
||||||
class GameCommand;
|
|
||||||
class CommandContainer;
|
|
||||||
class Event_GameJoined;
|
|
||||||
class Event_GameStateChanged;
|
|
||||||
class Event_PlayerPropertiesChanged;
|
|
||||||
class Event_Join;
|
|
||||||
class Event_Leave;
|
|
||||||
class Event_GameHostChanged;
|
|
||||||
class Event_GameClosed;
|
|
||||||
class Event_GameStart;
|
|
||||||
class Event_SetActivePlayer;
|
|
||||||
class Event_SetActivePhase;
|
|
||||||
class Event_Ping;
|
|
||||||
class Event_GameSay;
|
|
||||||
class Event_Kicked;
|
|
||||||
class Event_ReverseTurn;
|
|
||||||
class CardZone;
|
|
||||||
class AbstractCardItem;
|
|
||||||
class CardItem;
|
|
||||||
class DeckLoader;
|
|
||||||
class QVBoxLayout;
|
|
||||||
class QHBoxLayout;
|
|
||||||
class GameReplay;
|
|
||||||
class ServerInfo_User;
|
|
||||||
class PendingCommand;
|
|
||||||
class LineEditCompleter;
|
|
||||||
class QDockWidget;
|
|
||||||
class QStackedWidget;
|
|
||||||
|
|
||||||
class TabGame : public Tab
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private:
|
|
||||||
QTimer *gameTimer;
|
|
||||||
int secondsElapsed;
|
|
||||||
const UserListProxy *userListProxy;
|
|
||||||
QList<AbstractClient *> clients;
|
|
||||||
ServerInfo_Game gameInfo;
|
|
||||||
QMap<int, QString> roomGameTypes;
|
|
||||||
int hostId;
|
|
||||||
int localPlayerId;
|
|
||||||
const bool isLocalGame;
|
|
||||||
bool spectator;
|
|
||||||
bool judge;
|
|
||||||
QMap<int, Player *> players;
|
|
||||||
QMap<int, ServerInfo_User> spectators;
|
|
||||||
bool gameStateKnown;
|
|
||||||
bool resuming;
|
|
||||||
QStringList phasesList;
|
|
||||||
int currentPhase;
|
|
||||||
int activePlayer;
|
|
||||||
CardItem *activeCard;
|
|
||||||
bool gameClosed;
|
|
||||||
QStringList gameTypes;
|
|
||||||
QCompleter *completer;
|
|
||||||
QStringList autocompleteUserList;
|
|
||||||
QStackedWidget *mainWidget;
|
|
||||||
|
|
||||||
// Replay related members
|
|
||||||
GameReplay *replay;
|
|
||||||
int currentReplayStep;
|
|
||||||
QList<int> replayTimeline;
|
|
||||||
ReplayTimelineWidget *timelineWidget;
|
|
||||||
QToolButton *replayPlayButton, *replayFastForwardButton;
|
|
||||||
QAction *aReplaySkipForward, *aReplaySkipBackward, *aReplaySkipForwardBig, *aReplaySkipBackwardBig;
|
|
||||||
|
|
||||||
CardInfoFrameWidget *cardInfoFrameWidget;
|
|
||||||
PlayerListWidget *playerListWidget;
|
|
||||||
QLabel *timeElapsedLabel;
|
|
||||||
MessageLogWidget *messageLog;
|
|
||||||
QLabel *sayLabel;
|
|
||||||
LineEditCompleter *sayEdit;
|
|
||||||
PhasesToolbar *phasesToolbar;
|
|
||||||
GameScene *scene;
|
|
||||||
GameView *gameView;
|
|
||||||
QMap<int, DeckViewContainer *> deckViewContainers;
|
|
||||||
QVBoxLayout *deckViewContainerLayout;
|
|
||||||
QWidget *gamePlayAreaWidget, *deckViewContainerWidget;
|
|
||||||
QDockWidget *cardInfoDock, *messageLayoutDock, *playerListDock, *replayDock;
|
|
||||||
QAction *playersSeparator;
|
|
||||||
QMenu *gameMenu, *viewMenu, *cardInfoDockMenu, *messageLayoutDockMenu, *playerListDockMenu, *replayDockMenu;
|
|
||||||
TearOffMenu *phasesMenu;
|
|
||||||
QAction *aGameInfo, *aConcede, *aLeaveGame, *aCloseReplay, *aNextPhase, *aNextPhaseAction, *aNextTurn,
|
|
||||||
*aReverseTurn, *aRemoveLocalArrows, *aRotateViewCW, *aRotateViewCCW, *aResetLayout, *aResetReplayLayout;
|
|
||||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aMessageLayoutDockVisible, *aMessageLayoutDockFloating,
|
|
||||||
*aPlayerListDockVisible, *aPlayerListDockFloating, *aReplayDockVisible, *aReplayDockFloating;
|
|
||||||
QAction *aFocusChat;
|
|
||||||
QList<QAction *> phaseActions;
|
|
||||||
|
|
||||||
Player *addPlayer(int playerId, const ServerInfo_User &info);
|
|
||||||
|
|
||||||
bool isMainPlayerConceded() const;
|
|
||||||
|
|
||||||
void startGame(bool resuming);
|
|
||||||
void stopGame();
|
|
||||||
void closeGame();
|
|
||||||
bool leaveGame();
|
|
||||||
|
|
||||||
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
|
|
||||||
void eventGameStateChanged(const Event_GameStateChanged &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &event,
|
|
||||||
int eventPlayerId,
|
|
||||||
const GameEventContext &context);
|
|
||||||
void eventJoin(const Event_Join &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventKicked(const Event_Kicked &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventGameHostChanged(const Event_GameHostChanged &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventGameClosed(const Event_GameClosed &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
Player *setActivePlayer(int id);
|
|
||||||
void eventSetActivePlayer(const Event_SetActivePlayer &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void setActivePhase(int phase);
|
|
||||||
void eventSetActivePhase(const Event_SetActivePhase &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
|
|
||||||
void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext & /*context*/);
|
|
||||||
void emitUserEvent();
|
|
||||||
void createMenuItems();
|
|
||||||
void createReplayMenuItems();
|
|
||||||
void createViewMenuItems();
|
|
||||||
void createCardInfoDock(bool bReplay = false);
|
|
||||||
void createPlayerListDock(bool bReplay = false);
|
|
||||||
void createMessageDock(bool bReplay = false);
|
|
||||||
void createPlayAreaWidget(bool bReplay = false);
|
|
||||||
void createDeckViewContainerWidget(bool bReplay = false);
|
|
||||||
void createReplayDock();
|
|
||||||
QString getLeaveReason(Event_Leave::LeaveReason reason);
|
|
||||||
signals:
|
|
||||||
void gameClosing(TabGame *tab);
|
|
||||||
void playerAdded(Player *player);
|
|
||||||
void playerRemoved(Player *player);
|
|
||||||
void containerProcessingStarted(const GameEventContext &context);
|
|
||||||
void containerProcessingDone();
|
|
||||||
void openMessageDialog(const QString &userName, bool focus);
|
|
||||||
void openDeckEditor(const DeckLoader *deck);
|
|
||||||
void notIdle();
|
|
||||||
private slots:
|
|
||||||
void replayNextEvent(Player::EventProcessingOptions options);
|
|
||||||
void replayFinished();
|
|
||||||
void replayPlayButtonToggled(bool checked);
|
|
||||||
void replayFastForwardButtonToggled(bool checked);
|
|
||||||
void replayRewind();
|
|
||||||
|
|
||||||
void incrementGameTime();
|
|
||||||
void adminLockChanged(bool lock);
|
|
||||||
void newCardAdded(AbstractCardItem *card);
|
|
||||||
void updateCardMenu(AbstractCardItem *card);
|
|
||||||
|
|
||||||
void actGameInfo();
|
|
||||||
void actConcede();
|
|
||||||
void actRemoveLocalArrows();
|
|
||||||
void actRotateViewCW();
|
|
||||||
void actRotateViewCCW();
|
|
||||||
void actSay();
|
|
||||||
void actPhaseAction();
|
|
||||||
void actNextPhase();
|
|
||||||
void actNextPhaseAction();
|
|
||||||
void actNextTurn();
|
|
||||||
void actReverseTurn();
|
|
||||||
|
|
||||||
void addMentionTag(const QString &value);
|
|
||||||
void linkCardToChat(const QString &cardName);
|
|
||||||
void commandFinished(const Response &response);
|
|
||||||
|
|
||||||
void refreshShortcuts();
|
|
||||||
|
|
||||||
void loadLayout();
|
|
||||||
void actCompleterChanged();
|
|
||||||
void actResetLayout();
|
|
||||||
void freeDocksSize();
|
|
||||||
|
|
||||||
void hideEvent(QHideEvent *event) override;
|
|
||||||
bool eventFilter(QObject *o, QEvent *e) override;
|
|
||||||
void dockVisibleTriggered();
|
|
||||||
void dockFloatingTriggered();
|
|
||||||
void dockTopLevelChanged(bool topLevel);
|
|
||||||
|
|
||||||
public:
|
|
||||||
TabGame(TabSupervisor *_tabSupervisor,
|
|
||||||
QList<AbstractClient *> &_clients,
|
|
||||||
const Event_GameJoined &event,
|
|
||||||
const QMap<int, QString> &_roomGameTypes);
|
|
||||||
TabGame(TabSupervisor *_tabSupervisor, GameReplay *replay);
|
|
||||||
~TabGame() override;
|
|
||||||
void retranslateUi() override;
|
|
||||||
void updatePlayerListDockTitle();
|
|
||||||
void closeRequest(bool forced = false) override;
|
|
||||||
const QMap<int, Player *> &getPlayers() const
|
|
||||||
{
|
|
||||||
return players;
|
|
||||||
}
|
|
||||||
CardItem *getCard(int playerId, const QString &zoneName, int cardId) const;
|
|
||||||
bool isHost() const
|
|
||||||
{
|
|
||||||
return hostId == localPlayerId;
|
|
||||||
}
|
|
||||||
bool getIsLocalGame() const
|
|
||||||
{
|
|
||||||
return isLocalGame;
|
|
||||||
}
|
|
||||||
int getGameId() const
|
|
||||||
{
|
|
||||||
return gameInfo.game_id();
|
|
||||||
}
|
|
||||||
QString getTabText() const override;
|
|
||||||
bool getSpectator() const
|
|
||||||
{
|
|
||||||
return spectator;
|
|
||||||
}
|
|
||||||
bool getSpectatorsSeeEverything() const
|
|
||||||
{
|
|
||||||
return gameInfo.spectators_omniscient();
|
|
||||||
}
|
|
||||||
bool isSpectator();
|
|
||||||
Player *getActiveLocalPlayer() const;
|
|
||||||
AbstractClient *getClientForPlayer(int playerId) const;
|
|
||||||
|
|
||||||
void setActiveCard(CardItem *card);
|
|
||||||
CardItem *getActiveCard() const
|
|
||||||
{
|
|
||||||
return activeCard;
|
|
||||||
}
|
|
||||||
|
|
||||||
void processGameEventContainer(const GameEventContainer &cont,
|
|
||||||
AbstractClient *client,
|
|
||||||
Player::EventProcessingOptions options);
|
|
||||||
PendingCommand *prepareGameCommand(const ::google::protobuf::Message &cmd);
|
|
||||||
PendingCommand *prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList);
|
|
||||||
public slots:
|
|
||||||
void sendGameCommand(PendingCommand *pend, int playerId = -1);
|
|
||||||
void sendGameCommand(const ::google::protobuf::Message &command, int playerId = -1);
|
|
||||||
void viewCardInfo(const QString &cardName, const QString &providerId = "") const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#ifndef TAB_VISUAL_DATABASE_DISPLAY_H
|
|
||||||
#define TAB_VISUAL_DATABASE_DISPLAY_H
|
|
||||||
|
|
||||||
#include "../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
|
||||||
#include "tab.h"
|
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
class TabVisualDatabaseDisplay : public Tab
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private:
|
|
||||||
TabDeckEditor *deckEditor;
|
|
||||||
VisualDatabaseDisplayWidget *visualDatabaseDisplayWidget;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor);
|
|
||||||
void retranslateUi() override;
|
|
||||||
QString getTabText() const override
|
|
||||||
{
|
|
||||||
return tr("Visual Database Display");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // TAB_VISUAL_DATABASE_DISPLAY_H
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef WINDOW_DECKEDITORVISUAL_H
|
|
||||||
#define WINDOW_DECKEDITORVISUAL_H
|
|
||||||
|
|
||||||
#include "../tab.h"
|
|
||||||
#include "tab_deck_editor_visual_tab_widget.h"
|
|
||||||
|
|
||||||
class TabDeckEditorVisual : public AbstractTabDeckEditor
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
protected slots:
|
|
||||||
void loadLayout() override;
|
|
||||||
void restartLayout() override;
|
|
||||||
void freeDocksSize() override;
|
|
||||||
void refreshShortcuts() override;
|
|
||||||
|
|
||||||
bool eventFilter(QObject *o, QEvent *e) override;
|
|
||||||
void dockVisibleTriggered() override;
|
|
||||||
void dockFloatingTriggered() override;
|
|
||||||
void dockTopLevelChanged(bool topLevel) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
TabDeckEditorVisualTabWidget *tabContainer;
|
|
||||||
|
|
||||||
QVBoxLayout *centralFrame;
|
|
||||||
QVBoxLayout *searchAndDatabaseFrame;
|
|
||||||
QHBoxLayout *searchLayout;
|
|
||||||
QDockWidget *searchAndDatabaseDock;
|
|
||||||
QDockWidget *deckAnalyticsDock;
|
|
||||||
QWidget *centralWidget;
|
|
||||||
QMenu *deckAnalyticsMenu;
|
|
||||||
QAction *aDeckAnalyticsDockVisible, *aDeckAnalyticsDockFloating;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TabDeckEditorVisual(TabSupervisor *_tabSupervisor);
|
|
||||||
void retranslateUi() override;
|
|
||||||
QString getTabText() const override;
|
|
||||||
void changeModelIndexAndCardInfo(const CardInfoPtr &activeCard);
|
|
||||||
void changeModelIndexToCard(const CardInfoPtr &activeCard);
|
|
||||||
void createDeckAnalyticsDock();
|
|
||||||
void createMenus() override;
|
|
||||||
void createSearchAndDatabaseFrame();
|
|
||||||
void createCentralFrame();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void onDeckChanged() override;
|
|
||||||
void showPrintingSelector() override;
|
|
||||||
void
|
|
||||||
processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
|
||||||
void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
|
||||||
bool actSaveDeckAs() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
#ifndef TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
|
||||||
#define TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
|
||||||
|
|
||||||
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
|
|
||||||
#include "../../ui/widgets/printing_selector/printing_selector.h"
|
|
||||||
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
|
||||||
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h"
|
|
||||||
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
|
||||||
#include "../abstract_tab_deck_editor.h"
|
|
||||||
|
|
||||||
#include <QTabWidget>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class TabDeckEditorVisualTabWidget : public QTabWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TabDeckEditorVisualTabWidget(QWidget *parent,
|
|
||||||
AbstractTabDeckEditor *_deckEditor,
|
|
||||||
DeckListModel *_deckModel,
|
|
||||||
CardDatabaseModel *_cardDatabaseModel,
|
|
||||||
CardDatabaseDisplayModel *_cardDatabaseDisplayModel);
|
|
||||||
|
|
||||||
// Utility functions
|
|
||||||
void addNewTab(QWidget *widget, const QString &title);
|
|
||||||
void removeCurrentTab();
|
|
||||||
void setTabTitle(int index, const QString &title);
|
|
||||||
QWidget *getCurrentTab() const;
|
|
||||||
int getTabCount() const;
|
|
||||||
|
|
||||||
VisualDeckEditorWidget *visualDeckView;
|
|
||||||
DeckAnalyticsWidget *deckAnalytics;
|
|
||||||
VisualDatabaseDisplayWidget *visualDatabaseDisplay;
|
|
||||||
PrintingSelector *printingSelector;
|
|
||||||
VisualDeckEditorSampleHandWidget *sampleHandWidget;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void onCardChanged(CardInfoPtr activeCard);
|
|
||||||
void onCardChangedDatabaseDisplay(CardInfoPtr activeCard);
|
|
||||||
void onCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
|
||||||
void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void cardChanged(CardInfoPtr activeCard);
|
|
||||||
void cardChangedDatabaseDisplay(CardInfoPtr activeCard);
|
|
||||||
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
|
||||||
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVBoxLayout *layout; // Layout for the tab widget and other controls
|
|
||||||
AbstractTabDeckEditor *deckEditor;
|
|
||||||
DeckListModel *deckModel;
|
|
||||||
CardDatabaseModel *cardDatabaseModel;
|
|
||||||
CardDatabaseDisplayModel *cardDatabaseDisplayModel;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void handleTabClose(int index); // Slot for closing a tab
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef PICTURELOADER_H
|
|
||||||
#define PICTURELOADER_H
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_info.h"
|
|
||||||
#include "picture_loader_status_bar.h"
|
|
||||||
#include "picture_loader_worker.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PictureLoaderLog, "picture_loader");
|
|
||||||
inline Q_LOGGING_CATEGORY(PictureLoaderCardBackCacheFailLog, "picture_loader.card_back_cache_fail");
|
|
||||||
|
|
||||||
class PictureLoader : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
static PictureLoader &getInstance()
|
|
||||||
{
|
|
||||||
static PictureLoader instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit PictureLoader();
|
|
||||||
~PictureLoader() override;
|
|
||||||
// Singleton - Don't implement copy constructor and assign operator
|
|
||||||
PictureLoader(PictureLoader const &);
|
|
||||||
void operator=(PictureLoader const &);
|
|
||||||
|
|
||||||
PictureLoaderWorker *worker;
|
|
||||||
PictureLoaderStatusBar *statusBar;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size);
|
|
||||||
static void getCardBackPixmap(QPixmap &pixmap, QSize size);
|
|
||||||
static void getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSize size);
|
|
||||||
static void getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize size);
|
|
||||||
static void clearPixmapCache(CardInfoPtr card);
|
|
||||||
static void clearPixmapCache();
|
|
||||||
static void cacheCardPixmaps(QList<CardInfoPtr> cards);
|
|
||||||
static bool hasCustomArt();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
static void clearNetworkCache();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void picDownloadChanged();
|
|
||||||
void picsPathChanged();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void imageLoaded(CardInfoPtr card, const QImage &image);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
#include "picture_loader_local.h"
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../settings/cache_settings.h"
|
|
||||||
#include "picture_to_load.h"
|
|
||||||
|
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QMovie>
|
|
||||||
|
|
||||||
static constexpr int REFRESH_INTERVAL_MS = 10 * 1000;
|
|
||||||
|
|
||||||
PictureLoaderLocal::PictureLoaderLocal(QObject *parent)
|
|
||||||
: QObject(parent), picsPath(SettingsCache::instance().getPicsPath()),
|
|
||||||
customPicsPath(SettingsCache::instance().getCustomPicsPath()),
|
|
||||||
overrideAllCardArtWithPersonalPreference(SettingsCache::instance().getOverrideAllCardArtWithPersonalPreference())
|
|
||||||
{
|
|
||||||
// Hook up signals to settings
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::picsPathChanged, this, &PictureLoaderLocal::picsPathChanged);
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::overrideAllCardArtWithPersonalPreferenceChanged, this,
|
|
||||||
&PictureLoaderLocal::setOverrideAllCardArtWithPersonalPreference);
|
|
||||||
|
|
||||||
refreshIndex();
|
|
||||||
|
|
||||||
refreshTimer = new QTimer(this);
|
|
||||||
connect(refreshTimer, &QTimer::timeout, this, &PictureLoaderLocal::refreshIndex);
|
|
||||||
refreshTimer->start(REFRESH_INTERVAL_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderLocal::refreshIndex()
|
|
||||||
{
|
|
||||||
customFolderIndex.clear();
|
|
||||||
|
|
||||||
QDirIterator it(customPicsPath, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
|
||||||
|
|
||||||
// Recursively check all subdirectories of the CUSTOM folder
|
|
||||||
while (it.hasNext()) {
|
|
||||||
QString thisPath(it.next());
|
|
||||||
QFileInfo thisFileInfo(thisPath);
|
|
||||||
|
|
||||||
if (thisFileInfo.isFile()) {
|
|
||||||
// We don't know which name is the correctedName because there might be '.'s in the cardName.
|
|
||||||
// Just add all possibilities to be sure.
|
|
||||||
customFolderIndex.insert(thisFileInfo.baseName(), thisFileInfo.absoluteFilePath());
|
|
||||||
customFolderIndex.insert(thisFileInfo.completeBaseName(), thisFileInfo.absoluteFilePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(PictureLoaderLocalLog) << "Finished indexing local image folder CUSTOM; map now has"
|
|
||||||
<< customFolderIndex.size() << "entries.";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to load the card image from the local images.
|
|
||||||
*
|
|
||||||
* @param toLoad The card to load
|
|
||||||
* @return The loaded image, or an empty QImage if loading failed.
|
|
||||||
*/
|
|
||||||
QImage PictureLoaderLocal::tryLoad(const CardInfoPtr &toLoad) const
|
|
||||||
{
|
|
||||||
CardSetPtr set = PictureToLoad::extractSetsSorted(toLoad).first();
|
|
||||||
|
|
||||||
QString setName = set ? set->getCorrectedShortName() : QString();
|
|
||||||
QString cardName = toLoad->getName();
|
|
||||||
QString correctedCardName = toLoad->getCorrectedName();
|
|
||||||
|
|
||||||
// FIXME: This is a hack so that to keep old Cockatrice behavior
|
|
||||||
// (ignoring provider ID) when the "override all card art with personal
|
|
||||||
// preference" is set.
|
|
||||||
//
|
|
||||||
// Figure out a proper way to integrate the two systems at some point.
|
|
||||||
//
|
|
||||||
// Note: need to go through a member for
|
|
||||||
// overrideAllCardArtWithPersonalPreference as reading from the
|
|
||||||
// SettingsCache instance from the PictureLoaderWorker thread could
|
|
||||||
// cause race conditions.
|
|
||||||
//
|
|
||||||
// XXX: Reading from the CardDatabaseManager instance from the
|
|
||||||
// PictureLoaderWorker thread might not be safe either
|
|
||||||
bool searchCustomPics =
|
|
||||||
overrideAllCardArtWithPersonalPreference ||
|
|
||||||
CardDatabaseManager::getInstance()->isProviderIdForPreferredPrinting(cardName, toLoad->getPixmapCacheKey());
|
|
||||||
if (searchCustomPics) {
|
|
||||||
qCDebug(PictureLoaderLocalLog).nospace()
|
|
||||||
<< "[card: " << cardName << " set: " << setName << "]: Attempting to load picture from local";
|
|
||||||
return tryLoadCardImageFromDisk(setName, correctedCardName, searchCustomPics);
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(PictureLoaderLocalLog).nospace()
|
|
||||||
<< "[card: " << cardName << " set: " << setName << "]: Skipping load picture from local";
|
|
||||||
|
|
||||||
return QImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage PictureLoaderLocal::tryLoadCardImageFromDisk(const QString &setName,
|
|
||||||
const QString &correctedCardName,
|
|
||||||
const bool searchCustomPics) const
|
|
||||||
{
|
|
||||||
QImage image;
|
|
||||||
QImageReader imgReader;
|
|
||||||
imgReader.setDecideFormatFromContent(true);
|
|
||||||
QList<QString> picsPaths = QList<QString>();
|
|
||||||
|
|
||||||
if (searchCustomPics) {
|
|
||||||
picsPaths << customFolderIndex.values(correctedCardName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!setName.isEmpty()) {
|
|
||||||
picsPaths << picsPath + "/" + setName + "/" + correctedCardName
|
|
||||||
// We no longer store downloaded images there, but don't just ignore
|
|
||||||
// stuff that old versions have put there.
|
|
||||||
<< picsPath + "/downloadedPics/" + setName + "/" + correctedCardName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterates through the list of paths, searching for images with the desired
|
|
||||||
// name with any QImageReader-supported extension
|
|
||||||
for (const auto &_picsPath : picsPaths) {
|
|
||||||
if (!QFileInfo(_picsPath).isFile()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
imgReader.setFileName(_picsPath);
|
|
||||||
if (imgReader.read(&image)) {
|
|
||||||
qCDebug(PictureLoaderLocalLog).nospace()
|
|
||||||
<< "[card: " << correctedCardName << " set: " << setName << "]: Picture found on disk.";
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
imgReader.setFileName(_picsPath + ".full");
|
|
||||||
if (imgReader.read(&image)) {
|
|
||||||
qCDebug(PictureLoaderLocalLog).nospace()
|
|
||||||
<< "[card: " << correctedCardName << " set: " << setName << "]: Picture.full found on disk.";
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
imgReader.setFileName(_picsPath + ".xlhq");
|
|
||||||
if (imgReader.read(&image)) {
|
|
||||||
qCDebug(PictureLoaderLocalLog).nospace()
|
|
||||||
<< "[card: " << correctedCardName << " set: " << setName << "]: Picture.xlhq found on disk.";
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qCDebug(PictureLoaderLocalLog).nospace()
|
|
||||||
<< "[card: " << correctedCardName << " set: " << setName << "]: Picture NOT found on disk.";
|
|
||||||
return QImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderLocal::picsPathChanged()
|
|
||||||
{
|
|
||||||
picsPath = SettingsCache::instance().getPicsPath();
|
|
||||||
customPicsPath = SettingsCache::instance().getCustomPicsPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderLocal::setOverrideAllCardArtWithPersonalPreference(bool _overrideAllCardArtWithPersonalPreference)
|
|
||||||
{
|
|
||||||
overrideAllCardArtWithPersonalPreference = _overrideAllCardArtWithPersonalPreference;
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#ifndef PICTURE_LOADER_LOCAL_H
|
|
||||||
#define PICTURE_LOADER_LOCAL_H
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_info.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PictureLoaderLocalLog, "picture_loader.local");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles searching for and loading card images from the local pics and custom image folders.
|
|
||||||
* This class maintains an index of the CUSTOM folder, to avoid repeatedly searching the entire directory.
|
|
||||||
*/
|
|
||||||
class PictureLoaderLocal : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit PictureLoaderLocal(QObject *parent);
|
|
||||||
|
|
||||||
QImage tryLoad(const CardInfoPtr &toLoad) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString picsPath, customPicsPath;
|
|
||||||
bool overrideAllCardArtWithPersonalPreference;
|
|
||||||
|
|
||||||
QMultiHash<QString, QString> customFolderIndex; // multimap of cardName to picPaths
|
|
||||||
QTimer *refreshTimer;
|
|
||||||
|
|
||||||
void refreshIndex();
|
|
||||||
|
|
||||||
QImage
|
|
||||||
tryLoadCardImageFromDisk(const QString &setName, const QString &correctedCardName, bool searchCustomPics) const;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void picsPathChanged();
|
|
||||||
void setOverrideAllCardArtWithPersonalPreference(bool _overrideAllCardArtWithPersonalPreference);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_LOCAL_H
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#include "picture_loader_request_status_display_widget.h"
|
|
||||||
|
|
||||||
PictureLoaderRequestStatusDisplayWidget::PictureLoaderRequestStatusDisplayWidget(QWidget *parent,
|
|
||||||
const QUrl &_url,
|
|
||||||
PictureLoaderWorkerWork *worker)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
layout = new QHBoxLayout(this);
|
|
||||||
|
|
||||||
if (worker->cardToDownload.getCard()) {
|
|
||||||
name = new QLabel(this);
|
|
||||||
name->setText(worker->cardToDownload.getCard()->getName());
|
|
||||||
setShortname = new QLabel(this);
|
|
||||||
setShortname->setText(worker->cardToDownload.getSetName());
|
|
||||||
providerId = new QLabel(this);
|
|
||||||
providerId->setText(worker->cardToDownload.getCard()->getProperty("uuid"));
|
|
||||||
|
|
||||||
layout->addWidget(name);
|
|
||||||
layout->addWidget(setShortname);
|
|
||||||
layout->addWidget(providerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
startTime = new QLabel(QDateTime::currentDateTime().toString(), this);
|
|
||||||
elapsedTime = new QLabel("0", this);
|
|
||||||
finished = new QLabel("False", this);
|
|
||||||
url = new QLabel(_url.toString(), this);
|
|
||||||
|
|
||||||
layout->addWidget(startTime);
|
|
||||||
layout->addWidget(elapsedTime);
|
|
||||||
layout->addWidget(finished);
|
|
||||||
layout->addWidget(url);
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
#ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
|
||||||
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
|
||||||
#include "picture_loader_worker_work.h"
|
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class PictureLoaderRequestStatusDisplayWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
PictureLoaderRequestStatusDisplayWidget(QWidget *parent, const QUrl &url, PictureLoaderWorkerWork *worker);
|
|
||||||
PictureLoaderWorkerWork *worker;
|
|
||||||
|
|
||||||
void setFinished()
|
|
||||||
{
|
|
||||||
finished->setText("True");
|
|
||||||
update();
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getFinished() const
|
|
||||||
{
|
|
||||||
return finished->text() == "True";
|
|
||||||
}
|
|
||||||
|
|
||||||
void setElapsedTime(const QString &_elapsedTime) const
|
|
||||||
{
|
|
||||||
elapsedTime->setText(_elapsedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
int queryElapsedSeconds()
|
|
||||||
{
|
|
||||||
if (!finished) {
|
|
||||||
int elapsedSeconds = QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime());
|
|
||||||
elapsedTime->setText(QString::number(elapsedSeconds));
|
|
||||||
update();
|
|
||||||
repaint();
|
|
||||||
return elapsedSeconds;
|
|
||||||
}
|
|
||||||
return elapsedTime->text().toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString getStartTime() const
|
|
||||||
{
|
|
||||||
return startTime->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString getUrl() const
|
|
||||||
{
|
|
||||||
return url->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QHBoxLayout *layout;
|
|
||||||
QLabel *name;
|
|
||||||
QLabel *setShortname;
|
|
||||||
QLabel *providerId;
|
|
||||||
QLabel *startTime;
|
|
||||||
QLabel *elapsedTime;
|
|
||||||
QLabel *finished;
|
|
||||||
QLabel *url;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef PICTURE_LOADER_STATUS_BAR_H
|
|
||||||
#define PICTURE_LOADER_STATUS_BAR_H
|
|
||||||
|
|
||||||
#include "../widgets/quick_settings/settings_button_widget.h"
|
|
||||||
#include "picture_loader_worker_work.h"
|
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class PictureLoaderStatusBar : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit PictureLoaderStatusBar(QWidget *parent);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void addQueuedImageLoad(const QUrl &url, PictureLoaderWorkerWork *worker);
|
|
||||||
void addSuccessfulImageLoad(const QUrl &url, PictureLoaderWorkerWork *worker);
|
|
||||||
void cleanOldEntries();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QHBoxLayout *layout;
|
|
||||||
QProgressBar *progressBar;
|
|
||||||
SettingsButtonWidget *loadLog;
|
|
||||||
QTimer *cleaner;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_STATUS_BAR_H
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#ifndef PICTURE_LOADER_WORKER_H
|
|
||||||
#define PICTURE_LOADER_WORKER_H
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_database.h"
|
|
||||||
#include "../../../game/cards/card_info.h"
|
|
||||||
#include "picture_loader_local.h"
|
|
||||||
#include "picture_loader_worker_work.h"
|
|
||||||
#include "picture_to_load.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkDiskCache>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QQueue>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#define REDIRECT_HEADER_NAME "redirects"
|
|
||||||
#define REDIRECT_ORIGINAL_URL "original"
|
|
||||||
#define REDIRECT_URL "redirect"
|
|
||||||
#define REDIRECT_TIMESTAMP "timestamp"
|
|
||||||
#define REDIRECT_CACHE_FILENAME "cache.ini"
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PictureLoaderWorkerLog, "picture_loader.worker");
|
|
||||||
|
|
||||||
class PictureLoaderWorkerWork;
|
|
||||||
class PictureLoaderWorker : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit PictureLoaderWorker();
|
|
||||||
~PictureLoaderWorker() override;
|
|
||||||
|
|
||||||
void enqueueImageLoad(const CardInfoPtr &card); // Starts a thread for the image to be loaded
|
|
||||||
void queueRequest(const QUrl &url, PictureLoaderWorkerWork *worker); // Queues network requests for load threads
|
|
||||||
void clearNetworkCache();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
QNetworkReply *makeRequest(const QUrl &url, PictureLoaderWorkerWork *workThread);
|
|
||||||
void processQueuedRequests();
|
|
||||||
void imageLoadedSuccessfully(const CardInfoPtr &card, const QImage &image);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static QStringList md5Blacklist;
|
|
||||||
|
|
||||||
QThread *pictureLoaderThread;
|
|
||||||
QNetworkAccessManager *networkManager;
|
|
||||||
QNetworkDiskCache *cache;
|
|
||||||
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; // Stores redirect and timestamp
|
|
||||||
QString cacheFilePath; // Path to persistent storage
|
|
||||||
static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable
|
|
||||||
bool picDownload;
|
|
||||||
QQueue<QPair<QUrl, PictureLoaderWorkerWork *>> requestLoadQueue;
|
|
||||||
QTimer requestTimer; // Timer for processing delayed requests
|
|
||||||
|
|
||||||
PictureLoaderLocal *localLoader;
|
|
||||||
QSet<CardInfoPtr> currentlyLoading; // for deduplication purposes
|
|
||||||
|
|
||||||
void cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl);
|
|
||||||
QUrl getCachedRedirect(const QUrl &originalUrl) const;
|
|
||||||
void loadRedirectCache();
|
|
||||||
void saveRedirectCache() const;
|
|
||||||
void cleanStaleEntries();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void handleImageLoadEnqueued(const CardInfoPtr &card);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void imageLoadEnqueued(const CardInfoPtr &card);
|
|
||||||
void imageLoaded(CardInfoPtr card, const QImage &image);
|
|
||||||
void imageLoadQueued(const QUrl &url, PictureLoaderWorkerWork *worker);
|
|
||||||
void imageLoadSuccessful(const QUrl &url, PictureLoaderWorkerWork *worker);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_WORKER_H
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
#include "picture_loader_worker_work.h"
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../settings/cache_settings.h"
|
|
||||||
#include "picture_loader_worker.h"
|
|
||||||
|
|
||||||
#include <QBuffer>
|
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QMovie>
|
|
||||||
#include <QNetworkDiskCache>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
// Card back returned by gatherer when card is not found
|
|
||||||
QStringList PictureLoaderWorkerWork::md5Blacklist = QStringList() << "db0c48db407a907c16ade38de048a441";
|
|
||||||
|
|
||||||
PictureLoaderWorkerWork::PictureLoaderWorkerWork(const PictureLoaderWorker *worker, const CardInfoPtr &toLoad)
|
|
||||||
: QObject(nullptr), cardToDownload(toLoad), picDownload(SettingsCache::instance().getPicDownload())
|
|
||||||
{
|
|
||||||
// Hook up signals to the orchestrator
|
|
||||||
connect(this, &PictureLoaderWorkerWork::requestImageDownload, worker, &PictureLoaderWorker::queueRequest,
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
connect(this, &PictureLoaderWorkerWork::imageLoaded, worker, &PictureLoaderWorker::imageLoadedSuccessfully,
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
|
|
||||||
// Hook up signals to settings
|
|
||||||
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
|
|
||||||
|
|
||||||
pictureLoaderThread = new QThread;
|
|
||||||
moveToThread(pictureLoaderThread);
|
|
||||||
|
|
||||||
connect(pictureLoaderThread, &QThread::started, this, &PictureLoaderWorkerWork::startNextPicDownload);
|
|
||||||
|
|
||||||
// clean up worker once loading finishes
|
|
||||||
connect(this, &PictureLoaderWorkerWork::imageLoaded, this, &QObject::deleteLater);
|
|
||||||
connect(this, &QObject::destroyed, pictureLoaderThread, &QThread::quit);
|
|
||||||
connect(pictureLoaderThread, &QThread::finished, pictureLoaderThread, &QObject::deleteLater);
|
|
||||||
|
|
||||||
pictureLoaderThread->start(QThread::LowPriority);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderWorkerWork::startNextPicDownload()
|
|
||||||
{
|
|
||||||
QString picUrl = cardToDownload.getCurrentUrl();
|
|
||||||
|
|
||||||
if (picUrl.isEmpty()) {
|
|
||||||
downloadRunning = false;
|
|
||||||
picDownloadFailed();
|
|
||||||
} else {
|
|
||||||
QUrl url(picUrl);
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getCorrectedName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: Trying to fetch picture from url "
|
|
||||||
<< url.toDisplayString();
|
|
||||||
emit requestImageDownload(url, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts another pic download using the next possible url combination for the card.
|
|
||||||
* If all possibilities are exhausted, then concludes the image loading with an empty QImage.
|
|
||||||
*/
|
|
||||||
void PictureLoaderWorkerWork::picDownloadFailed()
|
|
||||||
{
|
|
||||||
/* Take advantage of short-circuiting here to call the nextUrl until one
|
|
||||||
is not available. Only once nextUrl evaluates to false will this move
|
|
||||||
on to nextSet. If the Urls for a particular card are empty, this will
|
|
||||||
effectively go through the sets for that card. */
|
|
||||||
if (cardToDownload.nextUrl() || cardToDownload.nextSet()) {
|
|
||||||
startNextPicDownload();
|
|
||||||
} else {
|
|
||||||
qCWarning(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getCorrectedName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: Picture NOT found, "
|
|
||||||
<< (picDownload ? "download failed" : "downloads disabled")
|
|
||||||
<< ", no more url combinations to try: BAILING OUT";
|
|
||||||
emit imageLoaded(cardToDownload.getCard(), QImage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderWorkerWork::picDownloadFinished(QNetworkReply *reply)
|
|
||||||
{
|
|
||||||
bool isFromCache = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
|
|
||||||
|
|
||||||
if (reply->error()) {
|
|
||||||
if (isFromCache) {
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: Removing corrupted cache file for url "
|
|
||||||
<< reply->url().toDisplayString() << " and retrying (" << reply->errorString() << ")";
|
|
||||||
|
|
||||||
networkManager->cache()->remove(reply->url());
|
|
||||||
|
|
||||||
emit requestImageDownload(reply->url(), this);
|
|
||||||
} else {
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: " << (picDownload ? "Download" : "Cache search")
|
|
||||||
<< " failed for url " << reply->url().toDisplayString() << " (" << reply->errorString() << ")";
|
|
||||||
|
|
||||||
picDownloadFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
reply->deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// List of status codes from https://doc.qt.io/qt-6/qnetworkreply.html#redirected
|
|
||||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
||||||
if (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 ||
|
|
||||||
statusCode == 308) {
|
|
||||||
QUrl redirectUrl = reply->header(QNetworkRequest::LocationHeader).toUrl();
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: following "
|
|
||||||
<< (isFromCache ? "cached redirect" : "redirect") << " to " << redirectUrl.toDisplayString();
|
|
||||||
reply->deleteLater();
|
|
||||||
emit requestImageDownload(redirectUrl, this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// peek is used to keep the data in the buffer for use by QImageReader
|
|
||||||
const QByteArray &picData = reply->peek(reply->size());
|
|
||||||
|
|
||||||
if (imageIsBlackListed(picData)) {
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getName()
|
|
||||||
<< " set: " << cardToDownload.getSetName()
|
|
||||||
<< "]: Picture found, but blacklisted, will consider it as not found";
|
|
||||||
|
|
||||||
reply->deleteLater();
|
|
||||||
picDownloadFailed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage testImage;
|
|
||||||
|
|
||||||
QImageReader imgReader;
|
|
||||||
imgReader.setDecideFormatFromContent(true);
|
|
||||||
imgReader.setDevice(reply);
|
|
||||||
|
|
||||||
bool logSuccessMessage = false;
|
|
||||||
|
|
||||||
static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h
|
|
||||||
auto replyHeader = reply->peek(riffHeaderSize);
|
|
||||||
|
|
||||||
if (replyHeader.startsWith("RIFF") && replyHeader.endsWith("WEBP")) {
|
|
||||||
auto imgBuf = QBuffer(this);
|
|
||||||
imgBuf.setData(reply->readAll());
|
|
||||||
|
|
||||||
auto movie = QMovie(&imgBuf);
|
|
||||||
movie.start();
|
|
||||||
movie.stop();
|
|
||||||
|
|
||||||
emit imageLoaded(cardToDownload.getCard(), movie.currentImage());
|
|
||||||
logSuccessMessage = true;
|
|
||||||
} else if (imgReader.read(&testImage)) {
|
|
||||||
emit imageLoaded(cardToDownload.getCard(), testImage);
|
|
||||||
logSuccessMessage = true;
|
|
||||||
} else {
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: Possible " << (isFromCache ? "cached" : "downloaded")
|
|
||||||
<< " picture at " << reply->url().toDisplayString() << " could not be loaded: " << reply->errorString();
|
|
||||||
|
|
||||||
picDownloadFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logSuccessMessage) {
|
|
||||||
qCDebug(PictureLoaderWorkerWorkLog).nospace()
|
|
||||||
<< "PictureLoader: [card: " << cardToDownload.getCard()->getName()
|
|
||||||
<< " set: " << cardToDownload.getSetName() << "]: Image successfully "
|
|
||||||
<< (isFromCache ? "loaded from cached" : "downloaded from") << " url " << reply->url().toDisplayString();
|
|
||||||
}
|
|
||||||
|
|
||||||
reply->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PictureLoaderWorkerWork::picDownloadChanged()
|
|
||||||
{
|
|
||||||
picDownload = SettingsCache::instance().getPicDownload();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PictureLoaderWorkerWork::imageIsBlackListed(const QByteArray &picData)
|
|
||||||
{
|
|
||||||
QString md5sum = QCryptographicHash::hash(picData, QCryptographicHash::Md5).toHex();
|
|
||||||
return md5Blacklist.contains(md5sum);
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#ifndef PICTURE_LOADER_WORKER_WORK_H
|
|
||||||
#define PICTURE_LOADER_WORKER_WORK_H
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_database.h"
|
|
||||||
#include "picture_loader_worker.h"
|
|
||||||
#include "picture_to_load.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#define REDIRECT_HEADER_NAME "redirects"
|
|
||||||
#define REDIRECT_ORIGINAL_URL "original"
|
|
||||||
#define REDIRECT_URL "redirect"
|
|
||||||
#define REDIRECT_TIMESTAMP "timestamp"
|
|
||||||
#define REDIRECT_CACHE_FILENAME "cache.ini"
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PictureLoaderWorkerWorkLog, "picture_loader.worker");
|
|
||||||
|
|
||||||
class PictureLoaderWorker;
|
|
||||||
|
|
||||||
class PictureLoaderWorkerWork : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit PictureLoaderWorkerWork(const PictureLoaderWorker *worker, const CardInfoPtr &toLoad);
|
|
||||||
|
|
||||||
PictureToLoad cardToDownload;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void picDownloadFinished(QNetworkReply *reply);
|
|
||||||
void picDownloadFailed();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static QStringList md5Blacklist;
|
|
||||||
QThread *pictureLoaderThread;
|
|
||||||
QNetworkAccessManager *networkManager;
|
|
||||||
bool picDownload, downloadRunning, loadQueueRunning;
|
|
||||||
|
|
||||||
void startNextPicDownload();
|
|
||||||
bool imageIsBlackListed(const QByteArray &);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void picDownloadChanged();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
/**
|
|
||||||
* Emitted when this worker has successfully loaded the image or has exhausted all attempts at loading the image.
|
|
||||||
* Failures are represented by an empty QImage.
|
|
||||||
* Note that this object will delete itself as this signal is emitted.
|
|
||||||
*/
|
|
||||||
void imageLoaded(CardInfoPtr card, const QImage &image);
|
|
||||||
void requestImageDownload(const QUrl &url, PictureLoaderWorkerWork *instance);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_WORKER_WORK_H
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#ifndef PICTURE_TO_LOAD_H
|
|
||||||
#define PICTURE_TO_LOAD_H
|
|
||||||
|
|
||||||
#include "../../../game/cards/card_info.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PictureToLoadLog, "picture_loader.picture_to_load");
|
|
||||||
|
|
||||||
class PictureToLoad
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
CardInfoPtr card;
|
|
||||||
QList<CardSetPtr> sortedSets;
|
|
||||||
QList<QString> urlTemplates;
|
|
||||||
QList<QString> currentSetUrls;
|
|
||||||
QString currentUrl;
|
|
||||||
CardSetPtr currentSet;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit PictureToLoad(CardInfoPtr _card = CardInfoPtr());
|
|
||||||
|
|
||||||
CardInfoPtr getCard() const
|
|
||||||
{
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
card.clear();
|
|
||||||
}
|
|
||||||
QString getCurrentUrl() const
|
|
||||||
{
|
|
||||||
return currentUrl;
|
|
||||||
}
|
|
||||||
CardSetPtr getCurrentSet() const
|
|
||||||
{
|
|
||||||
return currentSet;
|
|
||||||
}
|
|
||||||
QString getSetName() const;
|
|
||||||
QString transformUrl(const QString &urlTemplate) const;
|
|
||||||
bool nextSet();
|
|
||||||
bool nextUrl();
|
|
||||||
void populateSetUrls();
|
|
||||||
|
|
||||||
static QList<CardSetPtr> extractSetsSorted(const CardInfoPtr &card);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PICTURE_TO_LOAD_H
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
#include "card_group_display_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../../deck/deck_list_model.h"
|
|
||||||
#include "../../../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../../../utility/card_info_comparator.h"
|
|
||||||
#include "../card_info_picture_with_text_overlay_widget.h"
|
|
||||||
|
|
||||||
#include <QResizeEvent>
|
|
||||||
|
|
||||||
CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
|
|
||||||
DeckListModel *_deckListModel,
|
|
||||||
QPersistentModelIndex _trackedIndex,
|
|
||||||
QString _zoneName,
|
|
||||||
QString _cardGroupCategory,
|
|
||||||
QString _activeGroupCriteria,
|
|
||||||
QStringList _activeSortCriteria,
|
|
||||||
int bannerOpacity,
|
|
||||||
CardSizeWidget *_cardSizeWidget)
|
|
||||||
: QWidget(parent), deckListModel(_deckListModel), trackedIndex(_trackedIndex), zoneName(_zoneName),
|
|
||||||
cardGroupCategory(_cardGroupCategory), activeGroupCriteria(_activeGroupCriteria),
|
|
||||||
activeSortCriteria(_activeSortCriteria), cardSizeWidget(_cardSizeWidget)
|
|
||||||
{
|
|
||||||
layout = new QVBoxLayout(this);
|
|
||||||
setLayout(layout);
|
|
||||||
setMinimumSize(QSize(0, 0));
|
|
||||||
|
|
||||||
banner = new BannerWidget(this, cardGroupCategory, Qt::Orientation::Vertical, bannerOpacity);
|
|
||||||
|
|
||||||
layout->addWidget(banner);
|
|
||||||
|
|
||||||
CardGroupDisplayWidget::updateCardDisplays();
|
|
||||||
|
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *CardGroupDisplayWidget::constructWidgetForIndex(int rowIndex)
|
|
||||||
{
|
|
||||||
QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(rowIndex, 0, trackedIndex));
|
|
||||||
|
|
||||||
if (indexToWidgetMap.contains(index)) {
|
|
||||||
return indexToWidgetMap[index];
|
|
||||||
}
|
|
||||||
auto cardName = deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString();
|
|
||||||
auto cardProviderId = deckListModel->data(index.sibling(index.row(), 4), Qt::EditRole).toString();
|
|
||||||
|
|
||||||
auto widget = new CardInfoPictureWithTextOverlayWidget(getLayoutParent(), true);
|
|
||||||
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
|
||||||
widget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId(cardName, cardProviderId));
|
|
||||||
|
|
||||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &CardGroupDisplayWidget::onClick);
|
|
||||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &CardGroupDisplayWidget::onHover);
|
|
||||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget, &CardInfoPictureWidget::setScaleFactor);
|
|
||||||
|
|
||||||
indexToWidgetMap.insert(index, widget);
|
|
||||||
return widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::updateCardDisplays()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < deckListModel->rowCount(trackedIndex); ++i) {
|
|
||||||
addToLayout(constructWidgetForIndex(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onCardAddition(const QModelIndex &parent, int first, int last)
|
|
||||||
{
|
|
||||||
if (!trackedIndex.isValid()) {
|
|
||||||
emit cleanupRequested(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (parent == trackedIndex) {
|
|
||||||
for (int i = first; i <= last; i++) {
|
|
||||||
insertIntoLayout(constructWidgetForIndex(i), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onCardRemoval(const QModelIndex &parent, int first, int last)
|
|
||||||
{
|
|
||||||
Q_UNUSED(first);
|
|
||||||
Q_UNUSED(last);
|
|
||||||
if (parent == trackedIndex) {
|
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
|
||||||
if (!idx.isValid()) {
|
|
||||||
removeFromLayout(indexToWidgetMap.value(idx));
|
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!trackedIndex.isValid()) {
|
|
||||||
emit cleanupRequested(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
|
||||||
{
|
|
||||||
emit cardClicked(event, card);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::onHover(CardInfoPtr card)
|
|
||||||
{
|
|
||||||
emit cardHovered(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
#include "flat_card_group_display_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../../deck/deck_list_model.h"
|
|
||||||
#include "../../../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../../../utility/card_info_comparator.h"
|
|
||||||
#include "../card_info_picture_with_text_overlay_widget.h"
|
|
||||||
|
|
||||||
#include <QResizeEvent>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
FlatCardGroupDisplayWidget::FlatCardGroupDisplayWidget(QWidget *parent,
|
|
||||||
DeckListModel *_deckListModel,
|
|
||||||
QPersistentModelIndex _trackedIndex,
|
|
||||||
QString _zoneName,
|
|
||||||
QString _cardGroupCategory,
|
|
||||||
QString _activeGroupCriteria,
|
|
||||||
QStringList _activeSortCriteria,
|
|
||||||
int bannerOpacity,
|
|
||||||
CardSizeWidget *_cardSizeWidget)
|
|
||||||
: CardGroupDisplayWidget(parent,
|
|
||||||
_deckListModel,
|
|
||||||
std::move(_trackedIndex),
|
|
||||||
_zoneName,
|
|
||||||
_cardGroupCategory,
|
|
||||||
_activeGroupCriteria,
|
|
||||||
_activeSortCriteria,
|
|
||||||
bannerOpacity,
|
|
||||||
_cardSizeWidget)
|
|
||||||
{
|
|
||||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
|
||||||
banner->setBuddy(flowWidget);
|
|
||||||
|
|
||||||
layout->addWidget(flowWidget);
|
|
||||||
|
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
|
||||||
FlatCardGroupDisplayWidget::removeFromLayout(indexToWidgetMap.value(idx));
|
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlatCardGroupDisplayWidget::updateCardDisplays();
|
|
||||||
disconnect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
|
||||||
disconnect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
|
||||||
|
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &FlatCardGroupDisplayWidget::onCardAddition);
|
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &FlatCardGroupDisplayWidget::onCardRemoval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatCardGroupDisplayWidget::onCardAddition(const QModelIndex &parent, int first, int last)
|
|
||||||
{
|
|
||||||
if (!trackedIndex.isValid()) {
|
|
||||||
emit cleanupRequested(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (parent == trackedIndex) {
|
|
||||||
for (int i = first; i <= last; i++) {
|
|
||||||
insertIntoLayout(constructWidgetForIndex(i), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatCardGroupDisplayWidget::onCardRemoval(const QModelIndex &parent, int first, int last)
|
|
||||||
{
|
|
||||||
Q_UNUSED(first);
|
|
||||||
Q_UNUSED(last);
|
|
||||||
if (parent == trackedIndex) {
|
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
|
||||||
if (!idx.isValid()) {
|
|
||||||
removeFromLayout(indexToWidgetMap.value(idx));
|
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!trackedIndex.isValid()) {
|
|
||||||
emit cleanupRequested(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *FlatCardGroupDisplayWidget::constructWidgetForIndex(int row)
|
|
||||||
{
|
|
||||||
QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(row, 0, trackedIndex));
|
|
||||||
|
|
||||||
if (indexToWidgetMap.contains(index)) {
|
|
||||||
return indexToWidgetMap[index];
|
|
||||||
}
|
|
||||||
auto cardName = deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString();
|
|
||||||
auto cardProviderId = deckListModel->data(index.sibling(index.row(), 4), Qt::EditRole).toString();
|
|
||||||
|
|
||||||
auto widget = new CardInfoPictureWithTextOverlayWidget(flowWidget, true);
|
|
||||||
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
|
||||||
widget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId(cardName, cardProviderId));
|
|
||||||
|
|
||||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &FlatCardGroupDisplayWidget::onClick);
|
|
||||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &FlatCardGroupDisplayWidget::onHover);
|
|
||||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget, &CardInfoPictureWidget::setScaleFactor);
|
|
||||||
|
|
||||||
indexToWidgetMap.insert(index, widget);
|
|
||||||
return widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
#include "card_info_text_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../game/board/card_item.h"
|
|
||||||
#include "../../../../game/game_specific_terms.h"
|
|
||||||
|
|
||||||
#include <QGridLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QTextEdit>
|
|
||||||
|
|
||||||
CardInfoTextWidget::CardInfoTextWidget(QWidget *parent) : QFrame(parent), info(nullptr)
|
|
||||||
{
|
|
||||||
nameLabel = new QLabel;
|
|
||||||
nameLabel->setOpenExternalLinks(false);
|
|
||||||
nameLabel->setWordWrap(true);
|
|
||||||
connect(nameLabel, SIGNAL(linkActivated(const QString &)), this, SIGNAL(linkActivated(const QString &)));
|
|
||||||
|
|
||||||
textLabel = new QTextEdit();
|
|
||||||
textLabel->setReadOnly(true);
|
|
||||||
|
|
||||||
auto *grid = new QGridLayout(this);
|
|
||||||
grid->addWidget(nameLabel, 0, 0);
|
|
||||||
grid->addWidget(textLabel, 1, 0, -1, 2);
|
|
||||||
grid->setRowStretch(1, 1);
|
|
||||||
grid->setColumnStretch(1, 1);
|
|
||||||
|
|
||||||
retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfoTextWidget::setCard(CardInfoPtr card)
|
|
||||||
{
|
|
||||||
if (card == nullptr) {
|
|
||||||
nameLabel->setText("");
|
|
||||||
textLabel->setText("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString text = "<table width=\"100%\" border=0 cellspacing=0 cellpadding=0>";
|
|
||||||
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>%2</td></tr>")
|
|
||||||
.arg(tr("Name:"), card->getName().toHtmlEscaped());
|
|
||||||
|
|
||||||
QStringList cardProps = card->getProperties();
|
|
||||||
for (const QString &key : cardProps) {
|
|
||||||
if (key.contains("-"))
|
|
||||||
continue;
|
|
||||||
QString keyText = Mtg::getNicePropertyName(key).toHtmlEscaped() + ":";
|
|
||||||
text +=
|
|
||||||
QString("<tr><td>%1</td><td></td><td>%2</td></tr>").arg(keyText, card->getProperty(key).toHtmlEscaped());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto relatedCards = card->getAllRelatedCards();
|
|
||||||
if (!relatedCards.empty()) {
|
|
||||||
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>").arg(tr("Related cards:"));
|
|
||||||
|
|
||||||
for (auto *relatedCard : relatedCards) {
|
|
||||||
QString tmp = relatedCard->getName().toHtmlEscaped();
|
|
||||||
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
|
|
||||||
}
|
|
||||||
|
|
||||||
text += "</td></tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
text += "</table>";
|
|
||||||
nameLabel->setText(text);
|
|
||||||
textLabel->setText(card->getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfoTextWidget::setInvalidCardName(const QString &cardName)
|
|
||||||
{
|
|
||||||
nameLabel->setText(tr("Unknown card:") + " " + cardName);
|
|
||||||
textLabel->setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfoTextWidget::retranslateUi()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* There's no way we can really translate the text currently being rendered.
|
|
||||||
* The best we can do is invalidate the current text.
|
|
||||||
*/
|
|
||||||
setInvalidCardName("");
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
#include "mana_base_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../deck/deck_loader.h"
|
|
||||||
#include "../../../../game/cards/card_database.h"
|
|
||||||
#include "../../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../general/display/banner_widget.h"
|
|
||||||
#include "../general/display/bar_widget.h"
|
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <decklist.h>
|
|
||||||
|
|
||||||
ManaBaseWidget::ManaBaseWidget(QWidget *parent, DeckListModel *_deckListModel)
|
|
||||||
: QWidget(parent), deckListModel(_deckListModel)
|
|
||||||
{
|
|
||||||
layout = new QVBoxLayout(this);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
bannerWidget = new BannerWidget(this, tr("Mana Base"), Qt::Vertical, 100);
|
|
||||||
bannerWidget->setMaximumHeight(100);
|
|
||||||
layout->addWidget(bannerWidget);
|
|
||||||
|
|
||||||
barContainer = new QWidget(this);
|
|
||||||
barLayout = new QHBoxLayout(barContainer);
|
|
||||||
layout->addWidget(barContainer);
|
|
||||||
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaBaseWidget::analyzeManaBase);
|
|
||||||
|
|
||||||
retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaBaseWidget::retranslateUi()
|
|
||||||
{
|
|
||||||
bannerWidget->setText(tr("Mana Base"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaBaseWidget::setDeckModel(DeckListModel *deckModel)
|
|
||||||
{
|
|
||||||
deckListModel = deckModel;
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaBaseWidget::analyzeManaBase);
|
|
||||||
analyzeManaBase();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaBaseWidget::updateDisplay()
|
|
||||||
{
|
|
||||||
// Clear the layout first
|
|
||||||
QLayoutItem *item;
|
|
||||||
while ((item = barLayout->takeAt(0)) != nullptr) {
|
|
||||||
item->widget()->deleteLater();
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
int highestEntry = 0;
|
|
||||||
for (auto entry : manaBaseMap) {
|
|
||||||
if (entry > highestEntry) {
|
|
||||||
highestEntry = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define color mapping for mana types
|
|
||||||
QHash<QString, QColor> manaColors;
|
|
||||||
manaColors.insert("W", QColor(248, 231, 185));
|
|
||||||
manaColors.insert("U", QColor(14, 104, 171));
|
|
||||||
manaColors.insert("B", QColor(21, 11, 0));
|
|
||||||
manaColors.insert("R", QColor(211, 32, 42));
|
|
||||||
manaColors.insert("G", QColor(0, 115, 62));
|
|
||||||
manaColors.insert("C", QColor(150, 150, 150));
|
|
||||||
|
|
||||||
for (auto manaColor : manaBaseMap.keys()) {
|
|
||||||
QColor barColor = manaColors.value(manaColor, Qt::gray);
|
|
||||||
BarWidget *barWidget = new BarWidget(QString(manaColor), manaBaseMap[manaColor], highestEntry, barColor, this);
|
|
||||||
barLayout->addWidget(barWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QString, int> ManaBaseWidget::analyzeManaBase()
|
|
||||||
{
|
|
||||||
manaBaseMap.clear();
|
|
||||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
|
||||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
|
||||||
if (info) {
|
|
||||||
auto devotion = determineManaProduction(info->getText());
|
|
||||||
mergeManaCounts(manaBaseMap, devotion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplay();
|
|
||||||
return manaBaseMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QString, int> ManaBaseWidget::determineManaProduction(const QString &rulesText)
|
|
||||||
{
|
|
||||||
QHash<QString, int> manaCounts = {{"W", 0}, {"U", 0}, {"B", 0}, {"R", 0}, {"G", 0}, {"C", 0}};
|
|
||||||
|
|
||||||
QString text = rulesText.toLower(); // Normalize case for matching
|
|
||||||
|
|
||||||
// Quick keyword-based checks for any color and colorless mana
|
|
||||||
if (text.contains("{t}: add one mana of any color") || text.contains("add one mana of any color")) {
|
|
||||||
for (const auto &color : {QStringLiteral("W"), QStringLiteral("U"), QStringLiteral("B"), QStringLiteral("R"),
|
|
||||||
QStringLiteral("G")}) {
|
|
||||||
manaCounts[color]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (text.contains("{t}: add {c}") || text.contains("add one colorless mana")) {
|
|
||||||
manaCounts["C"]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimized regex for specific mana symbols
|
|
||||||
static const QRegularExpression specificColorRegex(R"(\{T\}:\s*Add\s*\{([WUBRG])\})");
|
|
||||||
QRegularExpressionMatch match = specificColorRegex.match(rulesText);
|
|
||||||
if (match.hasMatch()) {
|
|
||||||
manaCounts[match.captured(1)]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return manaCounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaBaseWidget::mergeManaCounts(QHash<QString, int> &manaCounts1, const QHash<QString, int> &manaCounts2)
|
|
||||||
{
|
|
||||||
for (auto it = manaCounts2.constBegin(); it != manaCounts2.constEnd(); ++it) {
|
|
||||||
manaCounts1[it.key()] += it.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#ifndef MANA_BASE_WIDGET_H
|
|
||||||
#define MANA_BASE_WIDGET_H
|
|
||||||
|
|
||||||
#include "../../../../deck/deck_list_model.h"
|
|
||||||
#include "../general/display/banner_widget.h"
|
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QWidget>
|
|
||||||
#include <decklist.h>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class ManaBaseWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ManaBaseWidget(QWidget *parent, DeckListModel *deckListModel);
|
|
||||||
QHash<QString, int> analyzeManaBase();
|
|
||||||
void updateDisplay();
|
|
||||||
|
|
||||||
QHash<QString, int> determineManaProduction(const QString &manaString);
|
|
||||||
void mergeManaCounts(QHash<QString, int> &manaCounts1, const QHash<QString, int> &manaCounts2);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setDeckModel(DeckListModel *deckModel);
|
|
||||||
void retranslateUi();
|
|
||||||
|
|
||||||
private:
|
|
||||||
DeckListModel *deckListModel;
|
|
||||||
BannerWidget *bannerWidget;
|
|
||||||
QHash<QString, int> manaBaseMap;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QWidget *barContainer;
|
|
||||||
QHBoxLayout *barLayout;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MANA_BASE_WIDGET_H
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#include "mana_curve_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../deck/deck_loader.h"
|
|
||||||
#include "../../../../game/cards/card_database.h"
|
|
||||||
#include "../../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../../main.h"
|
|
||||||
#include "../general/display/banner_widget.h"
|
|
||||||
#include "../general/display/bar_widget.h"
|
|
||||||
|
|
||||||
#include <decklist.h>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
ManaCurveWidget::ManaCurveWidget(QWidget *parent, DeckListModel *_deckListModel)
|
|
||||||
: QWidget(parent), deckListModel(_deckListModel)
|
|
||||||
{
|
|
||||||
layout = new QVBoxLayout(this);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
bannerWidget = new BannerWidget(this, tr("Mana Curve"), Qt::Vertical, 100);
|
|
||||||
bannerWidget->setMaximumHeight(100);
|
|
||||||
layout->addWidget(bannerWidget);
|
|
||||||
|
|
||||||
barContainer = new QWidget(this);
|
|
||||||
barLayout = new QHBoxLayout(barContainer);
|
|
||||||
layout->addWidget(barContainer);
|
|
||||||
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaCurveWidget::analyzeManaCurve);
|
|
||||||
|
|
||||||
retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaCurveWidget::retranslateUi()
|
|
||||||
{
|
|
||||||
bannerWidget->setText(tr("Mana Curve"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaCurveWidget::setDeckModel(DeckListModel *deckModel)
|
|
||||||
{
|
|
||||||
deckListModel = deckModel;
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaCurveWidget::analyzeManaCurve);
|
|
||||||
analyzeManaCurve();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<int, int> ManaCurveWidget::analyzeManaCurve()
|
|
||||||
{
|
|
||||||
manaCurveMap.clear();
|
|
||||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
|
||||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
|
||||||
if (info) {
|
|
||||||
int cmc = info->getCmc().toInt();
|
|
||||||
manaCurveMap[cmc]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplay();
|
|
||||||
|
|
||||||
return manaCurveMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaCurveWidget::updateDisplay()
|
|
||||||
{
|
|
||||||
// Clear the layout first
|
|
||||||
if (barLayout != nullptr) {
|
|
||||||
QLayoutItem *item;
|
|
||||||
while ((item = barLayout->takeAt(0)) != nullptr) {
|
|
||||||
item->widget()->deleteLater();
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int highestEntry = 0;
|
|
||||||
for (const auto &entry : manaCurveMap) {
|
|
||||||
if (entry.second > highestEntry) {
|
|
||||||
highestEntry = entry.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert unordered_map to ordered map to ensure sorting by CMC
|
|
||||||
std::map<int, int> sortedManaCurve(manaCurveMap.begin(), manaCurveMap.end());
|
|
||||||
|
|
||||||
// Add new widgets to the layout in sorted order
|
|
||||||
for (const auto &entry : sortedManaCurve) {
|
|
||||||
BarWidget *barWidget =
|
|
||||||
new BarWidget(QString::number(entry.first), entry.second, highestEntry, QColor(122, 122, 122), this);
|
|
||||||
barLayout->addWidget(barWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(); // Update the widget display
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
#include "mana_devotion_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../deck/deck_loader.h"
|
|
||||||
#include "../../../../game/cards/card_database.h"
|
|
||||||
#include "../../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../../main.h"
|
|
||||||
#include "../general/display/banner_widget.h"
|
|
||||||
#include "../general/display/bar_widget.h"
|
|
||||||
|
|
||||||
#include <decklist.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <regex>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
ManaDevotionWidget::ManaDevotionWidget(QWidget *parent, DeckListModel *_deckListModel)
|
|
||||||
: QWidget(parent), deckListModel(_deckListModel)
|
|
||||||
{
|
|
||||||
layout = new QVBoxLayout(this);
|
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
bannerWidget = new BannerWidget(this, tr("Mana Devotion"), Qt::Vertical, 100);
|
|
||||||
bannerWidget->setMaximumHeight(100);
|
|
||||||
layout->addWidget(bannerWidget);
|
|
||||||
|
|
||||||
barLayout = new QHBoxLayout();
|
|
||||||
layout->addLayout(barLayout);
|
|
||||||
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaDevotionWidget::analyzeManaDevotion);
|
|
||||||
|
|
||||||
retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaDevotionWidget::retranslateUi()
|
|
||||||
{
|
|
||||||
bannerWidget->setText(tr("Mana Devotion"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaDevotionWidget::setDeckModel(DeckListModel *deckModel)
|
|
||||||
{
|
|
||||||
deckListModel = deckModel;
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaDevotionWidget::analyzeManaDevotion);
|
|
||||||
analyzeManaDevotion();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
|
|
||||||
{
|
|
||||||
manaDevotionMap.clear();
|
|
||||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
|
||||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
|
||||||
if (info) {
|
|
||||||
auto devotion = countManaSymbols(info->getManaCost());
|
|
||||||
mergeManaCounts(manaDevotionMap, devotion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplay();
|
|
||||||
return manaDevotionMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaDevotionWidget::updateDisplay()
|
|
||||||
{
|
|
||||||
// Clear the layout first
|
|
||||||
QLayoutItem *item;
|
|
||||||
while ((item = barLayout->takeAt(0)) != nullptr) {
|
|
||||||
item->widget()->deleteLater();
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
int highestEntry = 0;
|
|
||||||
for (auto entry : manaDevotionMap) {
|
|
||||||
if (highestEntry < entry.second) {
|
|
||||||
highestEntry = entry.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define color mapping for devotion bars
|
|
||||||
std::unordered_map<char, QColor> manaColors = {{'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 entry : manaDevotionMap) {
|
|
||||||
QColor barColor = manaColors.count(entry.first) ? manaColors[entry.first] : Qt::gray;
|
|
||||||
BarWidget *barWidget = new BarWidget(QString(entry.first), entry.second, highestEntry, barColor, this);
|
|
||||||
barLayout->addWidget(barWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(); // Update the widget display
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<char, int> ManaDevotionWidget::countManaSymbols(const QString &manaString)
|
|
||||||
{
|
|
||||||
std::unordered_map<char, int> manaCounts = {{'W', 0}, {'U', 0}, {'B', 0}, {'R', 0}, {'G', 0}};
|
|
||||||
|
|
||||||
int len = manaString.length();
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
if (manaString[i] == '{') {
|
|
||||||
++i; // Move past '{'
|
|
||||||
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
|
||||||
char mana1 = manaString[i].toLatin1();
|
|
||||||
++i; // Move to next character
|
|
||||||
if (i < len && manaString[i] == '/') {
|
|
||||||
++i; // Move past '/'
|
|
||||||
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
|
||||||
char mana2 = manaString[i].toLatin1();
|
|
||||||
manaCounts[mana1]++;
|
|
||||||
manaCounts[mana2]++;
|
|
||||||
} else {
|
|
||||||
// Handle cases like "{W/}" where second part is invalid
|
|
||||||
manaCounts[mana1]++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
manaCounts[mana1]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ensure we always skip to the closing '}'
|
|
||||||
while (i < len && manaString[i] != '}') {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if the character is a standalone mana symbol (not inside {})
|
|
||||||
else if (manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
|
||||||
manaCounts[manaString[i].toLatin1()]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return manaCounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ManaDevotionWidget::mergeManaCounts(std::unordered_map<char, int> &manaCounts1,
|
|
||||||
const std::unordered_map<char, int> &manaCounts2)
|
|
||||||
{
|
|
||||||
for (const auto &pair : manaCounts2) {
|
|
||||||
manaCounts1[pair.first] += pair.second; // Add values for matching keys
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#ifndef MANA_DEVOTION_WIDGET_H
|
|
||||||
#define MANA_DEVOTION_WIDGET_H
|
|
||||||
|
|
||||||
#include "../../../../deck/deck_list_model.h"
|
|
||||||
#include "../general/display/banner_widget.h"
|
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QWidget>
|
|
||||||
#include <decklist.h>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class ManaDevotionWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ManaDevotionWidget(QWidget *parent, DeckListModel *deckListModel);
|
|
||||||
void updateDisplay();
|
|
||||||
|
|
||||||
std::unordered_map<char, int> countManaSymbols(const QString &manaString);
|
|
||||||
void mergeManaCounts(std::unordered_map<char, int> &manaCounts1, const std::unordered_map<char, int> &manaCounts2);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setDeckModel(DeckListModel *deckModel);
|
|
||||||
std::unordered_map<char, int> analyzeManaDevotion();
|
|
||||||
void retranslateUi();
|
|
||||||
|
|
||||||
private:
|
|
||||||
DeckListModel *deckListModel;
|
|
||||||
BannerWidget *bannerWidget;
|
|
||||||
std::unordered_map<char, int> manaDevotionMap;
|
|
||||||
QVBoxLayout *layout;
|
|
||||||
QHBoxLayout *barLayout;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MANA_DEVOTION_WIDGET_H
|
|
||||||
@@ -1,355 +0,0 @@
|
|||||||
#include "visual_deck_editor_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../deck/deck_list_model.h"
|
|
||||||
#include "../../../../deck/deck_loader.h"
|
|
||||||
#include "../../../../game/cards/card_completer_proxy_model.h"
|
|
||||||
#include "../../../../game/cards/card_database.h"
|
|
||||||
#include "../../../../game/cards/card_database_manager.h"
|
|
||||||
#include "../../../../game/cards/card_database_model.h"
|
|
||||||
#include "../../../../game/cards/card_search_model.h"
|
|
||||||
#include "../../../../main.h"
|
|
||||||
#include "../../../../utility/card_info_comparator.h"
|
|
||||||
#include "../../layouts/overlap_layout.h"
|
|
||||||
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
|
||||||
#include "../cards/deck_card_zone_display_widget.h"
|
|
||||||
#include "../general/layout_containers/flow_widget.h"
|
|
||||||
#include "../general/layout_containers/overlap_control_widget.h"
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QCompleter>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QResizeEvent>
|
|
||||||
#include <qscrollarea.h>
|
|
||||||
|
|
||||||
VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_deckListModel)
|
|
||||||
: QWidget(parent), deckListModel(_deckListModel)
|
|
||||||
{
|
|
||||||
// The Main Widget and Main Layout, which contain a single Widget: The Scroll Area
|
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
||||||
mainLayout = new QVBoxLayout(this);
|
|
||||||
setLayout(mainLayout);
|
|
||||||
mainLayout->setContentsMargins(9, 0, 9, 5);
|
|
||||||
mainLayout->setSpacing(0);
|
|
||||||
|
|
||||||
searchContainer = new QWidget(this);
|
|
||||||
searchLayout = new QHBoxLayout(searchContainer);
|
|
||||||
searchContainer->setLayout(searchLayout);
|
|
||||||
|
|
||||||
searchBar = new QLineEdit(this);
|
|
||||||
connect(searchBar, &QLineEdit::returnPressed, this, [=, this]() {
|
|
||||||
if (!searchBar->hasFocus())
|
|
||||||
return;
|
|
||||||
|
|
||||||
CardInfoPtr card = CardDatabaseManager::getInstance()->getCard(searchBar->text());
|
|
||||||
if (card) {
|
|
||||||
emit cardAdditionRequested(card);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setFocusProxy(searchBar);
|
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
|
||||||
|
|
||||||
cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
|
||||||
cardDatabaseDisplayModel = new CardDatabaseDisplayModel(this);
|
|
||||||
cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel);
|
|
||||||
CardSearchModel *searchModel = new CardSearchModel(cardDatabaseDisplayModel, this);
|
|
||||||
|
|
||||||
proxyModel = new CardCompleterProxyModel(this);
|
|
||||||
proxyModel->setSourceModel(searchModel);
|
|
||||||
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
||||||
proxyModel->setFilterRole(Qt::DisplayRole);
|
|
||||||
|
|
||||||
completer = new QCompleter(proxyModel, this);
|
|
||||||
completer->setCompletionRole(Qt::DisplayRole);
|
|
||||||
completer->setCompletionMode(QCompleter::PopupCompletion);
|
|
||||||
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
|
||||||
completer->setFilterMode(Qt::MatchContains);
|
|
||||||
completer->setMaxVisibleItems(15);
|
|
||||||
searchBar->setCompleter(completer);
|
|
||||||
|
|
||||||
// Update suggestions dynamically
|
|
||||||
connect(searchBar, &QLineEdit::textEdited, searchModel, &CardSearchModel::updateSearchResults);
|
|
||||||
connect(searchBar, &QLineEdit::textEdited, this, [=, this](const QString &text) {
|
|
||||||
// Ensure substring matching
|
|
||||||
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
|
|
||||||
proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
|
|
||||||
|
|
||||||
if (!text.isEmpty()) {
|
|
||||||
completer->complete(); // Force the dropdown to appear
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(completer, static_cast<void (QCompleter::*)(const QString &)>(&QCompleter::activated), this,
|
|
||||||
[=, this](const QString &completion) {
|
|
||||||
// Prevent the text from changing automatically when navigating with arrow keys
|
|
||||||
if (searchBar->text() != completion) {
|
|
||||||
searchBar->setText(completion); // Set the completion explicitly
|
|
||||||
searchBar->setCursorPosition(searchBar->text().length()); // Move cursor to the end
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure that the text stays consistent during selection
|
|
||||||
connect(searchBar, &QLineEdit::textEdited, this, [=, this](const QString &text) {
|
|
||||||
if (searchBar->hasFocus() && !searchBar->completer()->popup()->isVisible()) {
|
|
||||||
// Allow text to change when typing, but not when navigating the completer
|
|
||||||
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
|
|
||||||
proxyModel->setFilterRegularExpression(
|
|
||||||
QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Search button functionality
|
|
||||||
searchPushButton = new QPushButton(this);
|
|
||||||
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() {
|
|
||||||
CardInfoPtr card = CardDatabaseManager::getInstance()->getCard(searchBar->text());
|
|
||||||
if (card) {
|
|
||||||
emit cardAdditionRequested(card);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
searchLayout->addWidget(searchBar);
|
|
||||||
searchLayout->addWidget(searchPushButton);
|
|
||||||
|
|
||||||
mainLayout->addWidget(searchContainer);
|
|
||||||
|
|
||||||
groupAndSortContainer = new QWidget(this);
|
|
||||||
groupAndSortLayout = new QHBoxLayout(groupAndSortContainer);
|
|
||||||
groupAndSortLayout->setAlignment(Qt::AlignLeft);
|
|
||||||
groupAndSortContainer->setLayout(groupAndSortLayout);
|
|
||||||
|
|
||||||
groupByComboBox = new QComboBox();
|
|
||||||
QStringList groupProperties = {"maintype", "colors", "cmc", "name"};
|
|
||||||
groupByComboBox->addItems(groupProperties);
|
|
||||||
groupByComboBox->setMinimumWidth(300);
|
|
||||||
connect(groupByComboBox, QOverload<const QString &>::of(&QComboBox::currentTextChanged), this,
|
|
||||||
&VisualDeckEditorWidget::actChangeActiveGroupCriteria);
|
|
||||||
actChangeActiveGroupCriteria();
|
|
||||||
|
|
||||||
sortCriteriaButton = new SettingsButtonWidget(this);
|
|
||||||
|
|
||||||
sortLabel = new QLabel(sortCriteriaButton);
|
|
||||||
sortLabel->setWordWrap(true);
|
|
||||||
|
|
||||||
QStringList sortProperties = {"colors", "cmc", "name", "maintype"};
|
|
||||||
sortByListWidget = new QListWidget();
|
|
||||||
sortByListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
||||||
sortByListWidget->setDragDropMode(QAbstractItemView::InternalMove);
|
|
||||||
sortByListWidget->setDefaultDropAction(Qt::MoveAction);
|
|
||||||
|
|
||||||
for (const QString &property : sortProperties) {
|
|
||||||
QListWidgetItem *item = new QListWidgetItem(property, sortByListWidget);
|
|
||||||
item->setFlags(item->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(sortByListWidget->model(), &QAbstractItemModel::rowsMoved, this,
|
|
||||||
&VisualDeckEditorWidget::actChangeActiveSortCriteria);
|
|
||||||
actChangeActiveSortCriteria();
|
|
||||||
|
|
||||||
sortByListWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
|
|
||||||
sortCriteriaButton->addSettingsWidget(sortLabel);
|
|
||||||
sortCriteriaButton->addSettingsWidget(sortByListWidget);
|
|
||||||
|
|
||||||
displayTypeButton = new QPushButton(this);
|
|
||||||
connect(displayTypeButton, &QPushButton::clicked, this, &VisualDeckEditorWidget::updateDisplayType);
|
|
||||||
|
|
||||||
groupAndSortLayout->addWidget(groupByComboBox);
|
|
||||||
groupAndSortLayout->addWidget(sortCriteriaButton);
|
|
||||||
groupAndSortLayout->addWidget(displayTypeButton);
|
|
||||||
|
|
||||||
scrollArea = new QScrollArea(this);
|
|
||||||
scrollArea->setWidgetResizable(true);
|
|
||||||
scrollArea->setMinimumSize(0, 0);
|
|
||||||
|
|
||||||
// Set scrollbar policies
|
|
||||||
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|
||||||
|
|
||||||
zoneContainer = new QWidget(scrollArea);
|
|
||||||
zoneContainerLayout = new QVBoxLayout(zoneContainer);
|
|
||||||
zoneContainer->setLayout(zoneContainerLayout);
|
|
||||||
scrollArea->addScrollBarWidget(zoneContainer, Qt::AlignHCenter);
|
|
||||||
scrollArea->setWidget(zoneContainer);
|
|
||||||
|
|
||||||
cardSizeWidget = new CardSizeWidget(this);
|
|
||||||
|
|
||||||
mainLayout->addWidget(groupAndSortContainer);
|
|
||||||
mainLayout->addWidget(scrollArea);
|
|
||||||
mainLayout->addWidget(cardSizeWidget);
|
|
||||||
|
|
||||||
connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorWidget::decklistDataChanged);
|
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &VisualDeckEditorWidget::onCardAddition);
|
|
||||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &VisualDeckEditorWidget::onCardRemoval);
|
|
||||||
constructZoneWidgetsFromDeckListModel();
|
|
||||||
|
|
||||||
retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::retranslateUi()
|
|
||||||
{
|
|
||||||
sortLabel->setText(tr("Click and drag to change the sort order within the groups"));
|
|
||||||
searchPushButton->setText(tr("Quick search and add card"));
|
|
||||||
searchPushButton->setToolTip(tr("Search for closest match in the database (with auto-suggestions) and add "
|
|
||||||
"preferred printing to the deck on pressing enter"));
|
|
||||||
sortCriteriaButton->setToolTip(tr("Configure how cards are sorted within their groups"));
|
|
||||||
displayTypeButton->setText(tr("Overlap Layout"));
|
|
||||||
displayTypeButton->setToolTip(
|
|
||||||
tr("Change how cards are displayed within zones (i.e. overlapped or fully visible.)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::cleanupInvalidZones(DeckCardZoneDisplayWidget *displayWidget)
|
|
||||||
{
|
|
||||||
zoneContainerLayout->removeWidget(displayWidget);
|
|
||||||
for (auto idx : indexToWidgetMap.keys()) {
|
|
||||||
if (!idx.isValid()) {
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete displayWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::onCardAddition(const QModelIndex &parent, int first, int last)
|
|
||||||
{
|
|
||||||
if (parent == deckListModel->getRoot()) {
|
|
||||||
for (int i = first; i <= last; i++) {
|
|
||||||
QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(i, 0, deckListModel->getRoot()));
|
|
||||||
|
|
||||||
if (indexToWidgetMap.contains(index)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckCardZoneDisplayWidget *zoneDisplayWidget = new DeckCardZoneDisplayWidget(
|
|
||||||
zoneContainer, deckListModel, index,
|
|
||||||
deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString(), activeGroupCriteria,
|
|
||||||
activeSortCriteria, currentDisplayType, 20, 10, cardSizeWidget);
|
|
||||||
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardHovered, this, &VisualDeckEditorWidget::onHover);
|
|
||||||
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardClicked, this,
|
|
||||||
&VisualDeckEditorWidget::onCardClick);
|
|
||||||
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::requestCleanup, this,
|
|
||||||
&VisualDeckEditorWidget::cleanupInvalidZones);
|
|
||||||
connect(this, &VisualDeckEditorWidget::activeSortCriteriaChanged, zoneDisplayWidget,
|
|
||||||
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
|
|
||||||
connect(this, &VisualDeckEditorWidget::activeGroupCriteriaChanged, zoneDisplayWidget,
|
|
||||||
&DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged);
|
|
||||||
connect(this, &VisualDeckEditorWidget::displayTypeChanged, zoneDisplayWidget,
|
|
||||||
&DeckCardZoneDisplayWidget::refreshDisplayType);
|
|
||||||
zoneDisplayWidget->refreshDisplayType(currentDisplayType);
|
|
||||||
zoneContainerLayout->addWidget(zoneDisplayWidget);
|
|
||||||
|
|
||||||
indexToWidgetMap.insert(index, zoneDisplayWidget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::onCardRemoval(const QModelIndex &parent, int first, int last)
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent);
|
|
||||||
Q_UNUSED(first);
|
|
||||||
Q_UNUSED(last);
|
|
||||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
|
||||||
if (!idx.isValid()) {
|
|
||||||
zoneContainerLayout->removeWidget(indexToWidgetMap.value(idx));
|
|
||||||
indexToWidgetMap.value(idx)->deleteLater();
|
|
||||||
indexToWidgetMap.remove(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::constructZoneWidgetsFromDeckListModel()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < deckListModel->rowCount(deckListModel->parent(QModelIndex())); i++) {
|
|
||||||
QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(i, 0, deckListModel->getRoot()));
|
|
||||||
|
|
||||||
if (indexToWidgetMap.contains(index)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckCardZoneDisplayWidget *zoneDisplayWidget = new DeckCardZoneDisplayWidget(
|
|
||||||
zoneContainer, deckListModel, index,
|
|
||||||
deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString(), activeGroupCriteria,
|
|
||||||
activeSortCriteria, currentDisplayType, 20, 10, cardSizeWidget);
|
|
||||||
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardHovered, this, &VisualDeckEditorWidget::onHover);
|
|
||||||
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardClicked, this, &VisualDeckEditorWidget::onCardClick);
|
|
||||||
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::requestCleanup, this,
|
|
||||||
&VisualDeckEditorWidget::cleanupInvalidZones);
|
|
||||||
connect(this, &VisualDeckEditorWidget::activeSortCriteriaChanged, zoneDisplayWidget,
|
|
||||||
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
|
|
||||||
connect(this, &VisualDeckEditorWidget::activeGroupCriteriaChanged, zoneDisplayWidget,
|
|
||||||
&DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged);
|
|
||||||
connect(this, &VisualDeckEditorWidget::displayTypeChanged, zoneDisplayWidget,
|
|
||||||
&DeckCardZoneDisplayWidget::refreshDisplayType);
|
|
||||||
zoneContainerLayout->addWidget(zoneDisplayWidget);
|
|
||||||
|
|
||||||
indexToWidgetMap.insert(index, zoneDisplayWidget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::updateZoneWidgets()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::updateDisplayType()
|
|
||||||
{
|
|
||||||
// Toggle the display type
|
|
||||||
currentDisplayType = (currentDisplayType == DisplayType::Overlap) ? DisplayType::Flat : DisplayType::Overlap;
|
|
||||||
|
|
||||||
// Update UI and emit signal
|
|
||||||
switch (currentDisplayType) {
|
|
||||||
case DisplayType::Flat:
|
|
||||||
displayTypeButton->setText(tr("Flat Layout"));
|
|
||||||
break;
|
|
||||||
case DisplayType::Overlap:
|
|
||||||
displayTypeButton->setText(tr("Overlap Layout"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
emit displayTypeChanged(currentDisplayType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
zoneContainer->setMaximumWidth(scrollArea->viewport()->width());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::actChangeActiveGroupCriteria()
|
|
||||||
{
|
|
||||||
activeGroupCriteria = groupByComboBox->currentText();
|
|
||||||
emit activeGroupCriteriaChanged(activeGroupCriteria);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::actChangeActiveSortCriteria()
|
|
||||||
{
|
|
||||||
QStringList selectedCriteria;
|
|
||||||
for (int i = 0; i < sortByListWidget->count(); ++i) {
|
|
||||||
QListWidgetItem *item = sortByListWidget->item(i);
|
|
||||||
selectedCriteria.append(item->text()); // Collect user-defined sort order
|
|
||||||
}
|
|
||||||
|
|
||||||
activeSortCriteria = selectedCriteria;
|
|
||||||
|
|
||||||
emit activeSortCriteriaChanged(selectedCriteria);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight)
|
|
||||||
{
|
|
||||||
// Might use these at some point.
|
|
||||||
Q_UNUSED(topLeft);
|
|
||||||
Q_UNUSED(bottomRight);
|
|
||||||
// Necessary to delay this in this manner else the updateDisplay will nuke widgets while their onClick event
|
|
||||||
// hasn't returned yet. Interval of 0 means QT will schedule this after the current event loop has finished.
|
|
||||||
updateZoneWidgets();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::onHover(CardInfoPtr hoveredCard)
|
|
||||||
{
|
|
||||||
emit activeCardChanged(hoveredCard);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualDeckEditorWidget::onCardClick(QMouseEvent *event,
|
|
||||||
CardInfoPictureWithTextOverlayWidget *instance,
|
|
||||||
QString zoneName)
|
|
||||||
{
|
|
||||||
emit cardClicked(event, instance, zoneName);
|
|
||||||
}
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
#include "deck_preview_deck_tags_display_widget.h"
|
|
||||||
|
|
||||||
#include "../../../../../dialogs/dlg_convert_deck_to_cod_format.h"
|
|
||||||
#include "../../../../../settings/cache_settings.h"
|
|
||||||
#include "../../../../tabs/tab_deck_editor.h"
|
|
||||||
#include "../../general/layout_containers/flow_widget.h"
|
|
||||||
#include "deck_preview_tag_addition_widget.h"
|
|
||||||
#include "deck_preview_tag_dialog.h"
|
|
||||||
#include "deck_preview_tag_display_widget.h"
|
|
||||||
#include "deck_preview_widget.h"
|
|
||||||
|
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
|
|
||||||
: QWidget(_parent), deckList(nullptr)
|
|
||||||
{
|
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
|
|
||||||
// Create layout
|
|
||||||
auto *layout = new QHBoxLayout(this);
|
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
|
|
||||||
setFixedHeight(100);
|
|
||||||
|
|
||||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
|
||||||
|
|
||||||
if (_deckList) {
|
|
||||||
connectDeckList(_deckList);
|
|
||||||
}
|
|
||||||
|
|
||||||
layout->addWidget(flowWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
|
|
||||||
{
|
|
||||||
if (deckList) {
|
|
||||||
disconnect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
|
||||||
}
|
|
||||||
|
|
||||||
deckList = _deckList;
|
|
||||||
connect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
|
||||||
|
|
||||||
refreshTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckPreviewDeckTagsDisplayWidget::refreshTags()
|
|
||||||
{
|
|
||||||
flowWidget->clearLayout();
|
|
||||||
|
|
||||||
for (const QString &tag : deckList->getTags()) {
|
|
||||||
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tagAdditionWidget = new DeckPreviewTagAdditionWidget(this, tr("Edit tags ..."));
|
|
||||||
connect(tagAdditionWidget, &DeckPreviewTagAdditionWidget::tagClicked, this,
|
|
||||||
&DeckPreviewDeckTagsDisplayWidget::openTagEditDlg);
|
|
||||||
flowWidget->addWidget(tagAdditionWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the filepath of all files (no directories) in target directory and all subdirectories
|
|
||||||
*/
|
|
||||||
static QStringList getAllFiles(const QString &filePath)
|
|
||||||
{
|
|
||||||
QStringList allFiles;
|
|
||||||
|
|
||||||
// QDirIterator with QDir::Files ensures only files are listed (no directories)
|
|
||||||
QDirIterator it(filePath, QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
allFiles << it.next(); // Add each file path to the list
|
|
||||||
}
|
|
||||||
|
|
||||||
return allFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath)
|
|
||||||
{
|
|
||||||
QFileInfo fileInfo(filePath);
|
|
||||||
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
|
|
||||||
|
|
||||||
if (QFile::exists(newFileName)) {
|
|
||||||
QMessageBox::StandardButton reply =
|
|
||||||
QMessageBox::question(parent, QObject::tr("Overwrite Existing File?"),
|
|
||||||
QObject::tr("A .cod version of this deck already exists. Overwrite it?"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
|
||||||
return reply == QMessageBox::Yes;
|
|
||||||
}
|
|
||||||
return true; // Safe to proceed
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
|
|
||||||
{
|
|
||||||
if (qobject_cast<DeckPreviewWidget *>(parentWidget())) {
|
|
||||||
auto *deckPreviewWidget = qobject_cast<DeckPreviewWidget *>(parentWidget());
|
|
||||||
QStringList knownTags = deckPreviewWidget->visualDeckStorageWidget->tagFilterWidget->getAllKnownTags();
|
|
||||||
QStringList activeTags = deckList->getTags();
|
|
||||||
|
|
||||||
bool canAddTags = true;
|
|
||||||
|
|
||||||
if (DeckLoader::getFormatFromName(deckPreviewWidget->filePath) != DeckLoader::CockatriceFormat) {
|
|
||||||
canAddTags = false;
|
|
||||||
// Retrieve saved preference if the prompt is disabled
|
|
||||||
if (!SettingsCache::instance().getVisualDeckStoragePromptForConversion()) {
|
|
||||||
if (SettingsCache::instance().getVisualDeckStorageAlwaysConvert()) {
|
|
||||||
|
|
||||||
if (!confirmOverwriteIfExists(this, deckPreviewWidget->filePath))
|
|
||||||
return;
|
|
||||||
|
|
||||||
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
|
||||||
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getLastFileName();
|
|
||||||
deckPreviewWidget->refreshBannerCardText();
|
|
||||||
canAddTags = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Show the dialog to the user
|
|
||||||
DialogConvertDeckToCodFormat conversionDialog(parentWidget());
|
|
||||||
if (conversionDialog.exec() == QDialog::Accepted) {
|
|
||||||
|
|
||||||
if (!confirmOverwriteIfExists(this, deckPreviewWidget->filePath))
|
|
||||||
return;
|
|
||||||
|
|
||||||
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
|
||||||
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getLastFileName();
|
|
||||||
deckPreviewWidget->refreshBannerCardText();
|
|
||||||
canAddTags = true;
|
|
||||||
|
|
||||||
if (conversionDialog.dontAskAgain()) {
|
|
||||||
SettingsCache::instance().setVisualDeckStoragePromptForConversion(false);
|
|
||||||
SettingsCache::instance().setVisualDeckStorageAlwaysConvert(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SettingsCache::instance().setVisualDeckStorageAlwaysConvert(false);
|
|
||||||
|
|
||||||
if (conversionDialog.dontAskAgain()) {
|
|
||||||
SettingsCache::instance().setVisualDeckStoragePromptForConversion(false);
|
|
||||||
} else {
|
|
||||||
SettingsCache::instance().setVisualDeckStoragePromptForConversion(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canAddTags) {
|
|
||||||
DeckPreviewTagDialog dialog(knownTags, activeTags);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
|
||||||
QStringList updatedTags = dialog.getActiveTags();
|
|
||||||
deckList->setTags(updatedTags);
|
|
||||||
deckPreviewWidget->deckLoader->saveToFile(deckPreviewWidget->filePath, DeckLoader::CockatriceFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (parentWidget()) {
|
|
||||||
// If we're the child of an AbstractTabDeckEditor, we are buried under a ton of childWidgets in the
|
|
||||||
// DeckInfoDock.
|
|
||||||
QWidget *currentParent = parentWidget();
|
|
||||||
while (currentParent) {
|
|
||||||
if (qobject_cast<AbstractTabDeckEditor *>(currentParent)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
currentParent = currentParent->parentWidget();
|
|
||||||
}
|
|
||||||
if (qobject_cast<AbstractTabDeckEditor *>(currentParent)) {
|
|
||||||
auto *deckEditor = qobject_cast<AbstractTabDeckEditor *>(currentParent);
|
|
||||||
QStringList knownTags;
|
|
||||||
QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath());
|
|
||||||
DeckLoader loader;
|
|
||||||
for (const QString &file : allFiles) {
|
|
||||||
loader.loadFromFile(file, DeckLoader::getFormatFromName(file), false);
|
|
||||||
QStringList tags = loader.getTags();
|
|
||||||
knownTags.append(tags);
|
|
||||||
knownTags.removeDuplicates();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList activeTags = deckList->getTags();
|
|
||||||
|
|
||||||
DeckPreviewTagDialog dialog(knownTags, activeTags);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
|
||||||
QStringList updatedTags = dialog.getActiveTags();
|
|
||||||
deckList->setTags(updatedTags);
|
|
||||||
deckEditor->setModified(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#ifndef DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H
|
|
||||||
#define DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H
|
|
||||||
|
|
||||||
#include "../../../../../deck/deck_loader.h"
|
|
||||||
#include "deck_preview_widget.h"
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
inline bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath);
|
|
||||||
|
|
||||||
class DeckPreviewWidget;
|
|
||||||
class DeckPreviewDeckTagsDisplayWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList);
|
|
||||||
void connectDeckList(DeckList *_deckList);
|
|
||||||
void refreshTags();
|
|
||||||
DeckList *deckList;
|
|
||||||
FlowWidget *flowWidget;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void openTagEditDlg();
|
|
||||||
};
|
|
||||||
#endif // DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef COCKATRICE_SETTINGS_CARD_PREFERENCE_PROVIDER_H
|
||||||
|
#define COCKATRICE_SETTINGS_CARD_PREFERENCE_PROVIDER_H
|
||||||
|
#include "../../client/settings/cache_settings.h"
|
||||||
|
|
||||||
|
#include <libcockatrice/interfaces/interface_card_preference_provider.h>
|
||||||
|
|
||||||
|
class SettingsCardPreferenceProvider : public ICardPreferenceProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]] QString getCardPreferenceOverride(const QString &cardName) const override
|
||||||
|
{
|
||||||
|
return SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool getIncludeRebalancedCards() const override
|
||||||
|
{
|
||||||
|
return SettingsCache::instance().getIncludeRebalancedCards();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_SETTINGS_CARD_PREFERENCE_PROVIDER_H
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
#ifndef DECKLISTMODEL_H
|
|
||||||
#define DECKLISTMODEL_H
|
|
||||||
|
|
||||||
#include "../game/cards/card_info.h"
|
|
||||||
#include "decklist.h"
|
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class DeckLoader;
|
|
||||||
class CardDatabase;
|
|
||||||
class QPrinter;
|
|
||||||
class QTextCursor;
|
|
||||||
|
|
||||||
enum DeckListModelGroupCriteria
|
|
||||||
{
|
|
||||||
MAIN_TYPE,
|
|
||||||
MANA_COST,
|
|
||||||
COLOR
|
|
||||||
};
|
|
||||||
|
|
||||||
class DecklistModelCardNode : public AbstractDecklistCardNode
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
DecklistCardNode *dataNode;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DecklistModelCardNode(DecklistCardNode *_dataNode, InnerDecklistNode *_parent, int position = -1)
|
|
||||||
: AbstractDecklistCardNode(_parent, position), dataNode(_dataNode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
int getNumber() const override
|
|
||||||
{
|
|
||||||
return dataNode->getNumber();
|
|
||||||
}
|
|
||||||
void setNumber(int _number) override
|
|
||||||
{
|
|
||||||
dataNode->setNumber(_number);
|
|
||||||
}
|
|
||||||
QString getName() const override
|
|
||||||
{
|
|
||||||
return dataNode->getName();
|
|
||||||
}
|
|
||||||
void setName(const QString &_name) override
|
|
||||||
{
|
|
||||||
dataNode->setName(_name);
|
|
||||||
}
|
|
||||||
QString getCardProviderId() const override
|
|
||||||
{
|
|
||||||
return dataNode->getCardProviderId();
|
|
||||||
}
|
|
||||||
void setCardProviderId(const QString &_cardProviderId) override
|
|
||||||
{
|
|
||||||
dataNode->setCardProviderId(_cardProviderId);
|
|
||||||
}
|
|
||||||
QString getCardSetShortName() const override
|
|
||||||
{
|
|
||||||
return dataNode->getCardSetShortName();
|
|
||||||
}
|
|
||||||
void setCardSetShortName(const QString &_cardSetShortName) override
|
|
||||||
{
|
|
||||||
dataNode->setCardSetShortName(_cardSetShortName);
|
|
||||||
}
|
|
||||||
QString getCardCollectorNumber() const override
|
|
||||||
{
|
|
||||||
return dataNode->getCardCollectorNumber();
|
|
||||||
}
|
|
||||||
void setCardCollectorNumber(const QString &_cardSetNumber) override
|
|
||||||
{
|
|
||||||
dataNode->setCardCollectorNumber(_cardSetNumber);
|
|
||||||
}
|
|
||||||
DecklistCardNode *getDataNode() const
|
|
||||||
{
|
|
||||||
return dataNode;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isDeckHeader() const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeckListModel : public QAbstractItemModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private slots:
|
|
||||||
void rebuildTree();
|
|
||||||
public slots:
|
|
||||||
void printDeckList(QPrinter *printer);
|
|
||||||
signals:
|
|
||||||
void deckHashChanged();
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit DeckListModel(QObject *parent = nullptr);
|
|
||||||
~DeckListModel() override;
|
|
||||||
QModelIndex getRoot() const
|
|
||||||
{
|
|
||||||
return nodeToIndex(root);
|
|
||||||
};
|
|
||||||
QString getGroupCriteriaForCard(CardInfoPtr info) const;
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
|
||||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
|
||||||
QModelIndex parent(const QModelIndex &index) const override;
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
|
||||||
bool removeRows(int row, int count, const QModelIndex &parent) override;
|
|
||||||
QModelIndex findCard(const QString &cardName,
|
|
||||||
const QString &zoneName,
|
|
||||||
const QString &providerId = "",
|
|
||||||
const QString &cardNumber = "") const;
|
|
||||||
QModelIndex addPreferredPrintingCard(const QString &cardName, const QString &zoneName, bool abAddAnyway);
|
|
||||||
QModelIndex addCard(const ::QString &cardName,
|
|
||||||
const CardInfoPerSet &cardInfoSet,
|
|
||||||
const QString &zoneName,
|
|
||||||
bool abAddAnyway = false);
|
|
||||||
int findSortedInsertRow(InnerDecklistNode *parent, CardInfoPtr cardInfo) const;
|
|
||||||
void sort(int column, Qt::SortOrder order) override;
|
|
||||||
void cleanList();
|
|
||||||
DeckLoader *getDeckList() const
|
|
||||||
{
|
|
||||||
return deckList;
|
|
||||||
}
|
|
||||||
void setDeckList(DeckLoader *_deck);
|
|
||||||
QList<CardInfoPtr> getCardsAsCardInfoPtrs() const;
|
|
||||||
QList<CardInfoPtr> getCardsAsCardInfoPtrsForZone(QString zoneName) const;
|
|
||||||
QList<QString> *getZones() const;
|
|
||||||
void setActiveGroupCriteria(DeckListModelGroupCriteria newCriteria);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DeckLoader *deckList;
|
|
||||||
InnerDecklistNode *root;
|
|
||||||
DeckListModelGroupCriteria activeGroupCriteria = DeckListModelGroupCriteria::MAIN_TYPE;
|
|
||||||
int lastKnownColumn;
|
|
||||||
Qt::SortOrder lastKnownOrder;
|
|
||||||
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
|
|
||||||
QModelIndex nodeToIndex(AbstractDecklistNode *node) const;
|
|
||||||
DecklistModelCardNode *findCardNode(const QString &cardName,
|
|
||||||
const QString &zoneName,
|
|
||||||
const QString &providerId = "",
|
|
||||||
const QString &cardNumber = "") const;
|
|
||||||
void emitRecursiveUpdates(const QModelIndex &index);
|
|
||||||
void sortHelper(InnerDecklistNode *node, Qt::SortOrder order);
|
|
||||||
|
|
||||||
void printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node);
|
|
||||||
|
|
||||||
template <typename T> T getNode(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return dynamic_cast<T>(root);
|
|
||||||
return dynamic_cast<T>(static_cast<AbstractDecklistNode *>(index.internalPointer()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
#ifndef DECK_LOADER_H
|
|
||||||
#define DECK_LOADER_H
|
|
||||||
|
|
||||||
#include "decklist.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(DeckLoaderLog, "deck_loader")
|
|
||||||
|
|
||||||
class DeckLoader : public DeckList
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
signals:
|
|
||||||
void deckLoaded();
|
|
||||||
void loadFinished(bool success);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum FileFormat
|
|
||||||
{
|
|
||||||
PlainTextFormat,
|
|
||||||
CockatriceFormat
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supported file extensions for decklist files
|
|
||||||
*/
|
|
||||||
static const QStringList ACCEPTED_FILE_EXTENSIONS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For use with `QFileDialog::setNameFilters`
|
|
||||||
*/
|
|
||||||
static const QStringList FILE_NAME_FILTERS;
|
|
||||||
|
|
||||||
enum DecklistWebsite
|
|
||||||
{
|
|
||||||
DecklistOrg,
|
|
||||||
DecklistXyz
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString lastFileName;
|
|
||||||
FileFormat lastFileFormat;
|
|
||||||
int lastRemoteDeckId;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DeckLoader();
|
|
||||||
explicit DeckLoader(const QString &nativeString);
|
|
||||||
explicit DeckLoader(const DeckList &other);
|
|
||||||
DeckLoader(const DeckLoader &other);
|
|
||||||
const QString &getLastFileName() const
|
|
||||||
{
|
|
||||||
return lastFileName;
|
|
||||||
}
|
|
||||||
void setLastFileName(const QString &_lastFileName)
|
|
||||||
{
|
|
||||||
lastFileName = _lastFileName;
|
|
||||||
}
|
|
||||||
FileFormat getLastFileFormat() const
|
|
||||||
{
|
|
||||||
return lastFileFormat;
|
|
||||||
}
|
|
||||||
int getLastRemoteDeckId() const
|
|
||||||
{
|
|
||||||
return lastRemoteDeckId;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasNotBeenLoaded() const
|
|
||||||
{
|
|
||||||
return getLastFileName().isEmpty() && getLastRemoteDeckId() == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearSetNamesAndNumbers();
|
|
||||||
static FileFormat getFormatFromName(const QString &fileName);
|
|
||||||
|
|
||||||
bool loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest = false);
|
|
||||||
bool loadFromFileAsync(const QString &fileName, FileFormat fmt, bool userRequest);
|
|
||||||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
|
||||||
bool saveToFile(const QString &fileName, FileFormat fmt);
|
|
||||||
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
|
||||||
QString exportDeckToDecklist(DecklistWebsite website);
|
|
||||||
void setProviderIdToPreferredPrinting();
|
|
||||||
|
|
||||||
void resolveSetNameAndNumberToProviderID();
|
|
||||||
|
|
||||||
void saveToClipboard(bool addComments = true, bool addSetNameAndNumber = true) const;
|
|
||||||
|
|
||||||
// overload
|
|
||||||
bool saveToStream_Plain(QTextStream &out, bool addComments = true, bool addSetNameAndNumber = true) const;
|
|
||||||
bool convertToCockatriceFormat(QString fileName);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void saveToStream_DeckHeader(QTextStream &out) const;
|
|
||||||
void saveToStream_DeckZone(QTextStream &out,
|
|
||||||
const InnerDecklistNode *zoneNode,
|
|
||||||
bool addComments = true,
|
|
||||||
bool addSetNameAndNumber = true) const;
|
|
||||||
void saveToStream_DeckZoneCards(QTextStream &out,
|
|
||||||
const InnerDecklistNode *zoneNode,
|
|
||||||
QList<DecklistCardNode *> cards,
|
|
||||||
bool addComments = true,
|
|
||||||
bool addSetNameAndNumber = true) const;
|
|
||||||
[[nodiscard]] QString getCardZoneFromName(QString cardName, QString currentZoneName) override;
|
|
||||||
[[nodiscard]] QString getCompleteCardName(const QString &cardName) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
#include "deck_filter_string.h"
|
#include "deck_filter_string.h"
|
||||||
|
|
||||||
#include "../cards/card_database_manager.h"
|
#include <QFileInfo>
|
||||||
#include "filter_string.h"
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include "lib/peglib.h"
|
#include <libcockatrice/filters/filter_string.h>
|
||||||
|
#include <libcockatrice/utility/peglib.h>
|
||||||
|
|
||||||
static peg::parser search(R"(
|
static peg::parser search(R"(
|
||||||
Start <- QueryPartList
|
Start <- QueryPartList
|
||||||
@@ -12,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 / GenericQuery
|
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / FormatQuery / GenericQuery
|
||||||
|
|
||||||
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
||||||
|
|
||||||
@@ -21,8 +22,9 @@ CardSearch <- '[[' CardFilterString ']]'
|
|||||||
CardFilterString <- (!']]'.)*
|
CardFilterString <- (!']]'.)*
|
||||||
|
|
||||||
DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String
|
DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String
|
||||||
FileNameQuery <- [Ff] ('ile' 'name'?)? [:] String
|
FileNameQuery <- [Ff] ([Nn] / 'ile' ([Nn] 'ame')?) [:] String
|
||||||
PathQuery <- [Pp] 'ath'? [:] String
|
PathQuery <- [Pp] 'ath'? [:] String
|
||||||
|
FormatQuery <- [Ff] 'ormat'? [:] String
|
||||||
|
|
||||||
GenericQuery <- String
|
GenericQuery <- String
|
||||||
|
|
||||||
@@ -117,12 +119,13 @@ static void setupParserRules()
|
|||||||
|
|
||||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
deck->deckLoader->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) {
|
auto cardNodes = deck->deckLoader->getDeck().deckList.getCardNodes();
|
||||||
auto cardInfoPtr = CardDatabaseManager::getInstance()->getCard(node->getName());
|
for (auto node : cardNodes) {
|
||||||
|
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||||
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
||||||
count += node->getNumber();
|
count += node->getNumber();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return numberMatcher(count);
|
return numberMatcher(count);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -136,7 +139,7 @@ static void setupParserRules()
|
|||||||
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
search["DeckNameQuery"] = [](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 &) {
|
||||||
return deck->deckLoader->getName().contains(name, Qt::CaseInsensitive);
|
return deck->deckLoader->getDeck().deckList.getName().contains(name, Qt::CaseInsensitive);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -155,6 +158,14 @@ static void setupParserRules()
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
search["FormatQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
auto format = std::any_cast<QString>(sv[0]);
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||||
|
auto gameFormat = deck->deckLoader->getDeck().deckList.getGameFormat();
|
||||||
|
return QString::compare(format, gameFormat, Qt::CaseInsensitive) == 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
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,13 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* @file deck_filter_string.h
|
||||||
|
* @ingroup DeckStorageWidgets
|
||||||
|
* @brief TODO: Document this.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef DECK_FILTER_STRING_H
|
#ifndef DECK_FILTER_STRING_H
|
||||||
#define DECK_FILTER_STRING_H
|
#define DECK_FILTER_STRING_H
|
||||||
|
|
||||||
#include "../../client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h"
|
#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h"
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QMap>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
|
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ public:
|
|||||||
return filter(deck, info);
|
return filter(deck, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid() const
|
[[nodiscard]] bool valid() const
|
||||||
{
|
{
|
||||||
return _error.isEmpty();
|
return _error.isEmpty();
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "filter_builder.h"
|
#include "filter_builder.h"
|
||||||
|
|
||||||
#include "../../deck/custom_line_edit.h"
|
#include "../interface/widgets/utility/custom_line_edit.h"
|
||||||
#include "filter_card.h"
|
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <libcockatrice/filters/filter_card.h>
|
||||||
|
|
||||||
FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||