Compare commits
271 Commits
2025-06-29
...
5c1bb27d5c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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 \
|
||||
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/*
|
||||
109
.ci/compile.sh
@@ -11,7 +11,8 @@
|
||||
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
||||
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
||||
# --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>)
|
||||
# exitcode: 1 for failure, 3 for invalid arguments
|
||||
|
||||
@@ -46,6 +47,10 @@ while [[ $# != 0 ]]; do
|
||||
MAKE_SERVER=1
|
||||
shift
|
||||
;;
|
||||
'--no-client')
|
||||
MAKE_NO_CLIENT=1
|
||||
shift
|
||||
;;
|
||||
'--test')
|
||||
MAKE_TEST=1
|
||||
shift
|
||||
@@ -66,6 +71,10 @@ while [[ $# != 0 ]]; do
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
'--vcpkg')
|
||||
USE_VCPKG=1
|
||||
shift
|
||||
;;
|
||||
'--dir')
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
@@ -75,6 +84,15 @@ while [[ $# != 0 ]]; do
|
||||
BUILD_DIR="$1"
|
||||
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"
|
||||
exit 3
|
||||
@@ -95,11 +113,17 @@ fi
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Set minimum CMake Version
|
||||
export CMAKE_POLICY_VERSION_MINIMUM=3.10
|
||||
|
||||
# Add cmake flags
|
||||
flags=("-DCMAKE_BUILD_TYPE=$BUILDTYPE")
|
||||
if [[ $MAKE_SERVER ]]; then
|
||||
flags+=("-DWITH_SERVER=1")
|
||||
fi
|
||||
if [[ $MAKE_NO_CLIENT ]]; then
|
||||
flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0" "-DWITH_DBCONVERTER=0")
|
||||
fi
|
||||
if [[ $MAKE_TEST ]]; then
|
||||
flags+=("-DTEST=1")
|
||||
fi
|
||||
@@ -113,6 +137,9 @@ fi
|
||||
if [[ $PACKAGE_TYPE ]]; then
|
||||
flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE")
|
||||
fi
|
||||
if [[ $USE_VCPKG ]]; then
|
||||
flags+=("-DUSE_VCPKG=1")
|
||||
fi
|
||||
|
||||
# Add cmake --build flags
|
||||
buildflags=(--config "$BUILDTYPE")
|
||||
@@ -129,9 +156,35 @@ function ccachestatsverbose() {
|
||||
|
||||
# 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
|
||||
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
|
||||
@@ -143,6 +196,29 @@ if [[ $RUNNER_OS == macOS ]]; then
|
||||
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
|
||||
@@ -153,17 +229,13 @@ fi
|
||||
|
||||
echo "::group::Configure cmake"
|
||||
cmake --version
|
||||
echo "Running cmake with flags: ${flags[*]}"
|
||||
cmake .. "${flags[@]}"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build project"
|
||||
if [[ $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
|
||||
cmake --build . "${buildflags[@]}" -- -p:UseMultiToolTask=true -p:EnableClServerMode=true
|
||||
else
|
||||
cmake --build . "${buildflags[@]}"
|
||||
fi
|
||||
echo "Running cmake --build with flags: ${buildflags[*]}"
|
||||
cmake --build . "${buildflags[@]}"
|
||||
echo "::endgroup::"
|
||||
|
||||
if [[ $USE_CCACHE ]]; then
|
||||
@@ -172,6 +244,19 @@ if [[ $USE_CCACHE ]]; then
|
||||
echo "::endgroup::"
|
||||
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
|
||||
echo "::group::Run tests"
|
||||
ctest -C "$BUILDTYPE" --output-on-failure
|
||||
@@ -186,12 +271,6 @@ fi
|
||||
|
||||
if [[ $MAKE_PACKAGE ]]; then
|
||||
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"
|
||||
echo "::endgroup::"
|
||||
|
||||
|
||||
@@ -137,10 +137,11 @@ if [[ $SAVE ]]; then
|
||||
fi
|
||||
|
||||
# Set compile function, runs the compile script on the image, passes arguments to the script
|
||||
# shellcheck disable=2120
|
||||
function RUN ()
|
||||
{
|
||||
echo "running image:"
|
||||
if [[ $(docker images) =~ "$IMAGE_NAME" ]]; then
|
||||
if [[ $(docker images) =~ $IMAGE_NAME ]]; then
|
||||
local args=(--mount "type=bind,source=$PWD,target=/src")
|
||||
args+=(--workdir "/src")
|
||||
args+=(--user "$(id -u):$(id -g)")
|
||||
@@ -151,6 +152,7 @@ function RUN ()
|
||||
if [[ -n "$CMAKE_GENERATOR" ]]; then
|
||||
args+=(--env "CMAKE_GENERATOR=$CMAKE_GENERATOR")
|
||||
fi
|
||||
# shellcheck disable=2086
|
||||
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
||||
return $?
|
||||
else
|
||||
@@ -164,5 +166,6 @@ function RUN ()
|
||||
if [[ $INTERACTIVE ]]; then
|
||||
export BUILD_SCRIPT="-i"
|
||||
export RUN_ARGS="$RUN_ARGS -it"
|
||||
# shellcheck disable=2119
|
||||
RUN
|
||||
fi
|
||||
|
||||
@@ -11,11 +11,19 @@ if ! git merge-base origin/master HEAD; then
|
||||
fi
|
||||
|
||||
# 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=$?
|
||||
|
||||
sep="
|
||||
----------
|
||||
"
|
||||
used_version="${diff%%"$sep"*}"
|
||||
diff="${diff#*"$sep"}"
|
||||
changes_to_make="${diff%%"$sep"*}"
|
||||
files_to_edit="${diff#*"$sep"}"
|
||||
|
||||
case $err in
|
||||
1)
|
||||
cat <<EOM
|
||||
@@ -33,14 +41,13 @@ case $err in
|
||||
***********************************************************
|
||||
|
||||
Used version:
|
||||
${diff%%
|
||||
----------
|
||||
*}
|
||||
$used_version
|
||||
|
||||
Affected files:
|
||||
$files_to_edit
|
||||
|
||||
The following changes should be made:
|
||||
${diff#*
|
||||
----------
|
||||
}
|
||||
$changes_to_make
|
||||
|
||||
Exiting...
|
||||
EOM
|
||||
@@ -58,6 +65,9 @@ EOM
|
||||
*** ***
|
||||
***********************************************************
|
||||
|
||||
Used version:
|
||||
$used_version
|
||||
|
||||
Exiting...
|
||||
EOM
|
||||
exit 0
|
||||
|
||||
@@ -20,10 +20,11 @@ Available pre-compiled binaries for installation:
|
||||
<b>Linux</b>
|
||||
• <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>Debian 13</kbd> <sub><i>Trixie</i></sub>
|
||||
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
||||
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
|
||||
• <kbd>Fedora 43</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>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>
|
||||
|
||||
@@ -25,6 +25,9 @@ IndentCaseLabels: true
|
||||
PointerAlignment: Right
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
StatementAttributeLikeMacros: [emit]
|
||||
# requires clang-format 16
|
||||
# RemoveSemicolon: true
|
||||
---
|
||||
Language: Proto
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
|
||||
2
.github/CONTRIBUTING.md
vendored
@@ -1,3 +1,5 @@
|
||||
<!--! @page contributing Contributing -->
|
||||
|
||||
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](
|
||||
#code-style-guide) | [Translations](#translations) | [Release Management](
|
||||
#release-management)
|
||||
|
||||
354
.github/workflows/desktop-build.yml
vendored
@@ -4,25 +4,39 @@ permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
actions: write # needed for ccache action to be able to delete gha caches
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'webclient/**'
|
||||
- '.github/workflows/web-*.yml'
|
||||
- '.github/workflows/translations-*.yml'
|
||||
- '.github/workflows/docker-release.yml'
|
||||
paths:
|
||||
- '*/**' # matches all files not in root
|
||||
- '!**.md'
|
||||
- '!.github/**'
|
||||
- '!.husky/**'
|
||||
- '!.tx/**'
|
||||
- '!doc/**'
|
||||
- '!webclient/**'
|
||||
- '.github/workflows/desktop-build.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'vcpkg.json'
|
||||
- 'vcpkg'
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'webclient/**'
|
||||
- '.github/workflows/web-*.yml'
|
||||
- '.github/workflows/translations-*.yml'
|
||||
paths:
|
||||
- '*/**' # matches all files not in root
|
||||
- '!**.md'
|
||||
- '!.github/**'
|
||||
- '!.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)
|
||||
concurrency:
|
||||
@@ -56,7 +70,7 @@ jobs:
|
||||
|
||||
- name: Checkout
|
||||
if: steps.configure.outputs.tag != null
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -100,19 +114,29 @@ jobs:
|
||||
- distro: Debian
|
||||
version: 11
|
||||
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
|
||||
version: 12
|
||||
package: DEB
|
||||
test: skip # Running tests on all distros is superfluous
|
||||
|
||||
- distro: Debian
|
||||
version: 13
|
||||
package: DEB
|
||||
|
||||
- distro: Fedora
|
||||
version: 41
|
||||
version: 42
|
||||
package: RPM
|
||||
test: skip # Running tests on all distros is superfluous
|
||||
|
||||
- distro: Fedora
|
||||
version: 42
|
||||
version: 43
|
||||
package: RPM
|
||||
|
||||
- distro: Ubuntu
|
||||
@@ -138,7 +162,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Restore compiler cache (ccache)
|
||||
id: ccache_restore
|
||||
@@ -172,10 +196,11 @@ jobs:
|
||||
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
||||
package: '${{matrix.package}}'
|
||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||
NO_CLIENT: ${{matrix.server_only == 'yes' && '--no-client' || '' }}
|
||||
run: |
|
||||
source .ci/docker.sh
|
||||
RUN --server --release --package "$package" --dir "$BUILD_DIR" \
|
||||
--ccache "$CCACHE_SIZE"
|
||||
--ccache "$CCACHE_SIZE" $NO_CLIENT
|
||||
.ci/name_build.sh
|
||||
|
||||
- name: Save compiler cache (ccache)
|
||||
@@ -188,7 +213,7 @@ jobs:
|
||||
- name: Upload artifact
|
||||
id: upload_artifact
|
||||
if: matrix.package != 'skip'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ${{matrix.distro}}${{matrix.version}}-package
|
||||
path: ${{steps.build.outputs.path}}
|
||||
@@ -208,7 +233,7 @@ jobs:
|
||||
- name: Attest binary provenance
|
||||
id: attestation
|
||||
if: steps.upload_release.outcome == 'success'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
uses: actions/attest-build-provenance@v3
|
||||
with:
|
||||
subject-name: ${{steps.build.outputs.name}}
|
||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
||||
@@ -220,96 +245,166 @@ jobs:
|
||||
GH_TOKEN: ${{github.token}}
|
||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
||||
|
||||
build-macos:
|
||||
build-vcpkg:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: 13
|
||||
- os: macOS
|
||||
target: 13
|
||||
runner: macos-15-intel
|
||||
soc: Intel
|
||||
os: macos-13
|
||||
xcode: "14.3.1"
|
||||
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_arch: clang_64
|
||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||
cache_qt: false # qt caches take too much space for macOS (1.1Gi)
|
||||
cmake_generator: Ninja
|
||||
use_ccache: 1
|
||||
|
||||
- target: 14
|
||||
- os: macOS
|
||||
target: 14
|
||||
runner: macos-14
|
||||
soc: Apple
|
||||
os: macos-14
|
||||
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
|
||||
|
||||
- target: 15
|
||||
- os: macOS
|
||||
target: 15
|
||||
runner: macos-15
|
||||
soc: Apple
|
||||
os: macos-15
|
||||
xcode: "16.2"
|
||||
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
|
||||
|
||||
- target: 15
|
||||
- os: macOS
|
||||
target: 15
|
||||
runner: macos-15
|
||||
soc: Apple
|
||||
os: macos-15
|
||||
xcode: "16.2"
|
||||
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
|
||||
|
||||
name: macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||
- 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
|
||||
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'
|
||||
runs-on: ${{matrix.runner}}
|
||||
|
||||
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 }}
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: ${{env.CCACHE_DIR}}
|
||||
key: ccache-${{matrix.os}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
||||
restore-keys: ccache-${{matrix.os}}-${{matrix.type}}-
|
||||
submodules: recursive
|
||||
|
||||
- name: Build on Xcode ${{matrix.xcode}}
|
||||
shell: bash
|
||||
- name: Add msbuild to PATH
|
||||
if: matrix.os == 'Windows'
|
||||
id: add-msbuild
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
msbuild-architecture: x64
|
||||
|
||||
# Using jianmingyong/ccache-action to setup ccache without using brew
|
||||
# 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:
|
||||
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}}
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{matrix.qt_version}}
|
||||
arch: ${{matrix.qt_arch}}
|
||||
modules: ${{matrix.qt_modules}}
|
||||
cache: ${{matrix.cache_qt}}
|
||||
|
||||
- name: Setup vcpkg cache
|
||||
id: vcpkg-cache
|
||||
uses: TAServers/vcpkg-cache@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# uses environment variables, see compile.sh for more details
|
||||
- name: Build Cockatrice
|
||||
id: build
|
||||
shell: bash
|
||||
env:
|
||||
BUILDTYPE: '${{matrix.type}}'
|
||||
MAKE_PACKAGE: '${{matrix.make_package}}'
|
||||
PACKAGE_SUFFIX: '-macOS${{matrix.target}}_${{matrix.soc}}'
|
||||
PACKAGE_SUFFIX: '${{matrix.package_suffix}}'
|
||||
CMAKE_GENERATOR: ${{matrix.cmake_generator}}
|
||||
CMAKE_GENERATOR_PLATFORM: ${{matrix.cmake_generator_platform}}
|
||||
USE_CCACHE: ${{matrix.use_ccache}}
|
||||
VCPKG_DISABLE_METRICS: 1
|
||||
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
|
||||
# macOS-specific environment variables, will be ignored on Windows
|
||||
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
||||
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 }}
|
||||
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 }}
|
||||
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.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||
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 }}
|
||||
@@ -321,7 +416,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Notarize app bundle
|
||||
if: matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||
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 }}
|
||||
@@ -332,20 +427,20 @@ jobs:
|
||||
# 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"
|
||||
@@ -355,110 +450,15 @@ jobs:
|
||||
- name: Upload artifact
|
||||
id: upload_artifact
|
||||
if: matrix.make_package
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
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:
|
||||
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
|
||||
env:
|
||||
GH_TOKEN: ${{github.token}}
|
||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
||||
|
||||
build-windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: 7
|
||||
qt_version: 5.15.*
|
||||
qt_arch: msvc2019_64
|
||||
|
||||
- target: 10
|
||||
qt_version: 6.6.*
|
||||
qt_arch: msvc2019_64
|
||||
qt_modules: "qtimageformats qtmultimedia qtwebsockets"
|
||||
|
||||
name: Windows ${{matrix.target}}
|
||||
needs: configure
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
CMAKE_GENERATOR: 'Visual Studio 17 2022'
|
||||
|
||||
steps:
|
||||
- name: Add msbuild to PATH
|
||||
id: add-msbuild
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
msbuild-architecture: x64
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Qt ${{matrix.qt_version}}
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
cache: true
|
||||
setup-python: true
|
||||
version: ${{matrix.qt_version}}
|
||||
arch: win64_${{matrix.qt_arch}}
|
||||
tools: ${{matrix.qt_tools}}
|
||||
modules: ${{matrix.qt_modules}}
|
||||
|
||||
- name: Setup vcpkg cache
|
||||
id: vcpkg-cache
|
||||
uses: TAServers/vcpkg-cache@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Cockatrice
|
||||
id: build
|
||||
shell: bash
|
||||
env:
|
||||
PACKAGE_SUFFIX: '-Win${{matrix.target}}'
|
||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||
CMAKE_GENERATOR_PLATFORM: 'x64'
|
||||
QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win64_${{matrix.qt_arch}}'
|
||||
VCPKG_DISABLE_METRICS: 1
|
||||
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,
|
||||
# project and process parallelism: https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
|
||||
run: .ci/compile.sh --server --release --test --package
|
||||
|
||||
- name: Upload artifact
|
||||
id: upload_artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows${{matrix.target}}-installer
|
||||
name: ${{matrix.artifact_name}}
|
||||
path: ${{steps.build.outputs.path}}
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload pdb database
|
||||
uses: actions/upload-artifact@v4
|
||||
if: matrix.os == 'Windows'
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Windows${{matrix.target}}-debug-pdbs
|
||||
path: |
|
||||
@@ -480,7 +480,7 @@ jobs:
|
||||
- name: Attest binary provenance
|
||||
id: attestation
|
||||
if: steps.upload_release.outcome == 'success'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
uses: actions/attest-build-provenance@v3
|
||||
with:
|
||||
subject-name: ${{steps.build.outputs.name}}
|
||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
||||
|
||||
25
.github/workflows/desktop-lint.yml
vendored
@@ -1,13 +1,22 @@
|
||||
name: Code Style (C++)
|
||||
|
||||
on:
|
||||
# push trigger not needed for linting, we do not allow direct pushes to master
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'webclient/**'
|
||||
- '.github/workflows/web-*.yml'
|
||||
- '.github/workflows/translations-*.yml'
|
||||
- '.github/workflows/docker-release.yml'
|
||||
paths:
|
||||
- '*/**' # matches all files not in root
|
||||
- '!**.md'
|
||||
- '!.ci/**'
|
||||
- '!.github/**'
|
||||
- '!.husky/**'
|
||||
- '!.tx/**'
|
||||
- '!doc/**'
|
||||
- '!webclient/**'
|
||||
- '.ci/lint_cpp.sh'
|
||||
- '.github/workflows/desktop-lint.yml'
|
||||
- '.clang-format'
|
||||
- '.cmake-format.json'
|
||||
- 'format.sh'
|
||||
|
||||
jobs:
|
||||
format:
|
||||
@@ -15,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 20 # should be enough to find merge base
|
||||
|
||||
@@ -23,7 +32,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
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
|
||||
shell: bash
|
||||
|
||||
7
.github/workflows/docker-release.yml
vendored
@@ -11,12 +11,7 @@ on:
|
||||
- master
|
||||
paths:
|
||||
- '.github/workflows/docker-release.yml'
|
||||
- 'CMakeLists.txt'
|
||||
- 'Dockerfile'
|
||||
- 'servatrice/**'
|
||||
- 'common/**'
|
||||
- 'cmake/**'
|
||||
- '!**.md'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@@ -28,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Docker 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/
|
||||
3
.github/workflows/translations-pull.yml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
- cron: '0 0 15 1,4,7,10 *'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.tx/**'
|
||||
- '.github/workflows/translations-pull.yml'
|
||||
|
||||
jobs:
|
||||
@@ -19,7 +20,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Pull translated strings from Transifex
|
||||
uses: transifex/cli-action@v2
|
||||
|
||||
11
.github/workflows/translations-push.yml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
- cron: '0 0 1 1,4,7,10 *'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.ci/update_translation_source_strings.sh'
|
||||
- '.github/workflows/translations-push.yml'
|
||||
|
||||
jobs:
|
||||
@@ -19,7 +20,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install lupdate
|
||||
shell: bash
|
||||
@@ -30,10 +31,10 @@ jobs:
|
||||
- name: Update Cockatrice translation source
|
||||
id: cockatrice
|
||||
shell: bash
|
||||
env:
|
||||
FILE: 'cockatrice/cockatrice_en@source.ts'
|
||||
DIRS: 'cockatrice/src common'
|
||||
run: .ci/update_translation_source_strings.sh
|
||||
run: |
|
||||
FILE="cockatrice/cockatrice_en@source.ts"
|
||||
export DIRS="cockatrice/src $(find . -maxdepth 1 -type d -name 'libcockatrice_*')"
|
||||
FILE="$FILE" DIRS="$DIRS" .ci/update_translation_source_strings.sh
|
||||
|
||||
- name: Update Oracle translation source
|
||||
id: oracle
|
||||
|
||||
10
.github/workflows/web-build.yml
vendored
@@ -5,14 +5,16 @@ on:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- '.github/workflows/web-*.yml'
|
||||
- '.husky/**'
|
||||
- 'webclient/**'
|
||||
- '!**.md'
|
||||
- '.github/workflows/web-build.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/web-*.yml'
|
||||
- '.husky/**'
|
||||
- 'webclient/**'
|
||||
- '!**.md'
|
||||
- '.github/workflows/web-build.yml'
|
||||
|
||||
jobs:
|
||||
build-web:
|
||||
@@ -33,10 +35,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{matrix.node_version}}
|
||||
cache: 'npm'
|
||||
|
||||
7
.github/workflows/web-lint.yml
vendored
@@ -1,11 +1,12 @@
|
||||
name: Code Style (TypeScript)
|
||||
|
||||
on:
|
||||
# push trigger not needed for linting, we do not allow direct pushes to master
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/web-*.yml'
|
||||
- 'webclient/**'
|
||||
- '!**.md'
|
||||
- '.github/workflows/web-lint.yml'
|
||||
|
||||
jobs:
|
||||
ESLint:
|
||||
@@ -17,10 +18,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'webclient/package-lock.json'
|
||||
|
||||
1
.gitignore
vendored
@@ -14,3 +14,4 @@ compile_commands.json
|
||||
.cache
|
||||
.gdb_history
|
||||
cockatrice/resources/config/qtlogging.ini
|
||||
docs/
|
||||
|
||||
@@ -24,6 +24,8 @@ option(WITH_ORACLE "build oracle" ON)
|
||||
option(WITH_DBCONVERTER "build dbconverter" ON)
|
||||
# Compile tests
|
||||
option(TEST "build tests" OFF)
|
||||
# Use vcpkg regardless of OS
|
||||
option(USE_VCPKG "Use vcpkg regardless of OS" OFF)
|
||||
|
||||
# Default to "Release" build type
|
||||
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
|
||||
@@ -48,8 +50,8 @@ if(USE_CCACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Use vcpkg toolchain on Windows
|
||||
if(WIN32 OR USE_VCPKG)
|
||||
# Use vcpkg toolchain on Windows (and on macOS in CI)
|
||||
set(CMAKE_TOOLCHAIN_FILE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||
CACHE STRING "Vcpkg toolchain file"
|
||||
@@ -301,6 +303,7 @@ if(UNIX)
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice")
|
||||
if(Qt6_FOUND)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins")
|
||||
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libqt6sql6-mysql") # for connecting servatrice to a mysql db
|
||||
elseif(Qt5_FOUND)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
|
||||
endif()
|
||||
@@ -325,7 +328,19 @@ endif()
|
||||
|
||||
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)
|
||||
add_subdirectory(servatrice)
|
||||
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
|
||||
|
||||
RUN apt-get update && apt-get install -y\
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
cmake \
|
||||
file \
|
||||
@@ -16,20 +17,28 @@ RUN apt-get update && apt-get install -y\
|
||||
qt6-tools-dev \
|
||||
qt6-tools-dev-tools
|
||||
|
||||
COPY ./CMakeLists.txt ./LICENSE ./README.md /home/servatrice/code/
|
||||
COPY ./cmake /home/servatrice/code/cmake
|
||||
COPY ./common /home/servatrice/code/common
|
||||
COPY ./servatrice /home/servatrice/code/servatrice
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN mkdir build && cd build && \
|
||||
cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 && \
|
||||
make -j$(nproc) && \
|
||||
make install
|
||||
|
||||
WORKDIR /home/servatrice/code
|
||||
|
||||
WORKDIR build
|
||||
RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 &&\
|
||||
make &&\
|
||||
make install
|
||||
# -------- Runtime Stage (clean) --------
|
||||
FROM ubuntu:24.04
|
||||
|
||||
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
|
||||
|
||||
EXPOSE 4748
|
||||
|
||||
ENTRYPOINT [ "servatrice", "--log-to-console" ]
|
||||
|
||||
9
LICENSE
@@ -2,7 +2,7 @@
|
||||
Version 2, June 1991
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
|
||||
@@ -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-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)
|
||||
@@ -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.
|
||||
- [Official Website](https://cockatrice.github.io)
|
||||
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
||||
- [Official Code Documentation](https://cockatrice.github.io/docs)
|
||||
- [Official Discord](https://discord.gg/3Z9yzmA)
|
||||
- [reddit r/Cockatrice](https://reddit.com/r/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" 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}")
|
||||
|
||||
@@ -7,254 +7,281 @@ project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${
|
||||
set(cockatrice_SOURCES
|
||||
${VERSION_STRING_CPP}
|
||||
# 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/game_logic/key_signals.cpp
|
||||
src/client/get_text_with_max.cpp
|
||||
src/client/menus/deck_editor/deck_editor_menu.cpp
|
||||
src/client/network/client_update_checker.cpp
|
||||
src/client/network/release_channel.cpp
|
||||
src/client/network/replay_timeline_widget.cpp
|
||||
src/client/network/sets_model.cpp
|
||||
src/client/network/spoiler_background_updater.cpp
|
||||
src/client/network/update/client/update_downloader.cpp
|
||||
src/client/network/interfaces/deck_stats_interface.cpp
|
||||
src/client/network/interfaces/tapped_out_interface.cpp
|
||||
src/client/network/parsers/deck_link_to_api_transformer.cpp
|
||||
src/client/network/update/client/client_update_checker.cpp
|
||||
src/client/network/update/client/release_channel.cpp
|
||||
src/client/network/update/card_spoiler/spoiler_background_updater.cpp
|
||||
src/client/sound_engine.cpp
|
||||
src/client/tabs/abstract_tab_deck_editor.cpp
|
||||
src/client/tabs/api/edhrec/tab_edhrec.cpp
|
||||
src/client/tabs/api/edhrec/tab_edhrec_main.cpp
|
||||
src/client/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp
|
||||
src/client/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
|
||||
src/client/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp
|
||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp
|
||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp
|
||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp
|
||||
src/client/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp
|
||||
src/client/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp
|
||||
src/client/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp
|
||||
src/client/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
|
||||
src/client/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
|
||||
src/client/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp
|
||||
src/client/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp
|
||||
src/client/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp
|
||||
src/client/tabs/tab.cpp
|
||||
src/client/tabs/tab_account.cpp
|
||||
src/client/tabs/tab_admin.cpp
|
||||
src/client/tabs/tab_deck_editor.cpp
|
||||
src/client/tabs/tab_deck_storage.cpp
|
||||
src/client/tabs/tab_game.cpp
|
||||
src/client/tabs/tab_logs.cpp
|
||||
src/client/tabs/tab_message.cpp
|
||||
src/client/tabs/tab_replays.cpp
|
||||
src/client/tabs/tab_room.cpp
|
||||
src/client/tabs/tab_server.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_startup_card_check.cpp
|
||||
src/dialogs/dlg_tip_of_the_day.cpp
|
||||
src/dialogs/dlg_update.cpp
|
||||
src/dialogs/dlg_view_log.cpp
|
||||
src/client/settings/cache_settings.cpp
|
||||
src/client/settings/card_counter_settings.cpp
|
||||
src/client/settings/shortcut_treeview.cpp
|
||||
src/client/settings/shortcuts_settings.cpp
|
||||
src/interface/deck_loader/deck_loader.cpp
|
||||
src/interface/widgets/dialogs/dlg_connect.cpp
|
||||
src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp
|
||||
src/interface/widgets/dialogs/dlg_create_game.cpp
|
||||
src/interface/widgets/dialogs/dlg_default_tags_editor.cpp
|
||||
src/interface/widgets/dialogs/dlg_edit_avatar.cpp
|
||||
src/interface/widgets/dialogs/dlg_edit_password.cpp
|
||||
src/interface/widgets/dialogs/dlg_edit_tokens.cpp
|
||||
src/interface/widgets/dialogs/dlg_edit_user.cpp
|
||||
src/interface/widgets/dialogs/dlg_filter_games.cpp
|
||||
src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp
|
||||
src/interface/widgets/dialogs/dlg_forgot_password_request.cpp
|
||||
src/interface/widgets/dialogs/dlg_forgot_password_reset.cpp
|
||||
src/interface/widgets/dialogs/dlg_load_deck.cpp
|
||||
src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp
|
||||
src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp
|
||||
src/interface/widgets/dialogs/dlg_load_remote_deck.cpp
|
||||
src/interface/widgets/dialogs/dlg_manage_sets.cpp
|
||||
src/interface/widgets/dialogs/dlg_register.cpp
|
||||
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
|
||||
src/interface/widgets/dialogs/dlg_settings.cpp
|
||||
src/interface/widgets/dialogs/dlg_startup_card_check.cpp
|
||||
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
||||
src/interface/widgets/dialogs/dlg_update.cpp
|
||||
src/interface/widgets/dialogs/dlg_view_log.cpp
|
||||
src/interface/widgets/dialogs/tip_of_the_day.cpp
|
||||
src/filters/deck_filter_string.cpp
|
||||
src/filters/filter_builder.cpp
|
||||
src/filters/filter_tree_model.cpp
|
||||
src/filters/syntax_help.cpp
|
||||
src/game/abstract_game.cpp
|
||||
src/game/board/abstract_card_drag_item.cpp
|
||||
src/game/board/abstract_card_item.cpp
|
||||
src/game/board/abstract_counter.cpp
|
||||
src/game/board/abstract_graphics_item.cpp
|
||||
src/game/board/arrow_item.cpp
|
||||
src/game/board/arrow_target.cpp
|
||||
src/game/board/card_drag_item.cpp
|
||||
src/game/board/card_item.cpp
|
||||
src/game/board/card_list.cpp
|
||||
src/game/board/counter_general.cpp
|
||||
src/game/cards/card_completer_proxy_model.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/board/translate_counter_name.cpp
|
||||
src/game/deckview/deck_view.cpp
|
||||
src/game/deckview/deck_view_container.cpp
|
||||
src/game/filters/deck_filter_string.cpp
|
||||
src/game/filters/filter_builder.cpp
|
||||
src/game/filters/filter_card.cpp
|
||||
src/game/filters/filter_string.cpp
|
||||
src/game/filters/filter_tree.cpp
|
||||
src/game/filters/filter_tree_model.cpp
|
||||
src/game/filters/syntax_help.cpp
|
||||
src/game/deckview/tabbed_deck_view_container.cpp
|
||||
src/game/dialogs/dlg_create_token.cpp
|
||||
src/game/dialogs/dlg_move_top_cards_until.cpp
|
||||
src/game/dialogs/dlg_roll_dice.cpp
|
||||
src/game/game.cpp
|
||||
src/game/game_event_handler.cpp
|
||||
src/game/game_meta_info.cpp
|
||||
src/game/game_scene.cpp
|
||||
src/game/game_selector.cpp
|
||||
src/game/game_state.cpp
|
||||
src/game/game_view.cpp
|
||||
src/game/games_model.cpp
|
||||
src/game/hand_counter.cpp
|
||||
src/game/log/message_log_widget.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_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_manager.cpp
|
||||
src/game/player/player_target.cpp
|
||||
src/game/replay.cpp
|
||||
src/game/zones/card_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/select_zone.cpp
|
||||
src/game/zones/stack_zone.cpp
|
||||
src/game/zones/table_zone.cpp
|
||||
src/game/zones/view_zone.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_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/server/chat_view/chat_view.cpp
|
||||
src/server/handle_public_servers.cpp
|
||||
src/server/local_client.cpp
|
||||
src/server/local_server.cpp
|
||||
src/server/local_server_interface.cpp
|
||||
src/server/message_log_widget.cpp
|
||||
src/server/pending_command.cpp
|
||||
src/server/remote/remote_client.cpp
|
||||
src/server/remote/remote_decklist_tree_widget.cpp
|
||||
src/server/remote/remote_replay_list_tree_widget.cpp
|
||||
src/server/user/user_context_menu.cpp
|
||||
src/server/user/user_info_box.cpp
|
||||
src/server/user/user_info_connection.cpp
|
||||
src/server/user/user_list_manager.cpp
|
||||
src/server/user/user_list_widget.cpp
|
||||
src/settings/cache_settings.cpp
|
||||
src/settings/card_counter_settings.cpp
|
||||
src/settings/card_database_settings.cpp
|
||||
src/settings/card_override_settings.cpp
|
||||
src/settings/debug_settings.cpp
|
||||
src/settings/download_settings.cpp
|
||||
src/settings/game_filters_settings.cpp
|
||||
src/settings/layouts_settings.cpp
|
||||
src/settings/message_settings.cpp
|
||||
src/settings/recents_settings.cpp
|
||||
src/settings/servers_settings.cpp
|
||||
src/settings/settings_manager.cpp
|
||||
src/settings/shortcut_treeview.cpp
|
||||
src/settings/shortcuts_settings.cpp
|
||||
src/utility/card_info_comparator.cpp
|
||||
src/utility/levenshtein.cpp
|
||||
src/utility/logger.cpp
|
||||
src/utility/sequence_edit.cpp
|
||||
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
|
||||
src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.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)
|
||||
@@ -266,15 +293,23 @@ configure_file(
|
||||
set(cockatrice_RESOURCES cockatrice.qrc)
|
||||
|
||||
if(UPDATE_TRANSLATIONS)
|
||||
# Cockatrice main sources
|
||||
file(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp
|
||||
${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")
|
||||
else()
|
||||
file(GLOB cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts")
|
||||
endif(UPDATE_TRANSLATIONS)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
|
||||
@@ -304,12 +339,6 @@ set(DESKTOPDIR
|
||||
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_UNIX_QM_INSTALL_DIR "share/cockatrice/translations")
|
||||
set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations")
|
||||
@@ -349,9 +378,31 @@ elseif(Qt5_FOUND)
|
||||
endif()
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
if(UNIX)
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
|
||||
<file>resources/icons/arrow_bottom_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_redo.svg</file>
|
||||
<file>resources/icons/arrow_right_blue.svg</file>
|
||||
<file>resources/icons/arrow_right_green.svg</file>
|
||||
<file>resources/icons/arrow_top_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/cogwheel.svg</file>
|
||||
<file>resources/icons/conceded.svg</file>
|
||||
@@ -25,6 +28,7 @@
|
||||
<file>resources/icons/lock.svg</file>
|
||||
<file>resources/icons/not_ready_start.svg</file>
|
||||
<file>resources/icons/pencil.svg</file>
|
||||
<file>resources/icons/pin.svg</file>
|
||||
<file>resources/icons/player.svg</file>
|
||||
<file>resources/icons/ready_start.svg</file>
|
||||
<file>resources/icons/reload.svg</file>
|
||||
@@ -33,6 +37,7 @@
|
||||
<file>resources/icons/scales.svg</file>
|
||||
<file>resources/icons/search.svg</file>
|
||||
<file>resources/icons/settings.svg</file>
|
||||
<file>resources/icons/share.svg</file>
|
||||
<file>resources/icons/spectator.svg</file>
|
||||
<file>resources/icons/swap.svg</file>
|
||||
<file>resources/icons/sync.svg</file>
|
||||
@@ -46,6 +51,8 @@
|
||||
<file>resources/icons/mana/U.svg</file>
|
||||
<file>resources/icons/mana/W.svg</file>
|
||||
|
||||
<file>resources/backgrounds/home.png</file>
|
||||
|
||||
<file>resources/config/general.svg</file>
|
||||
<file>resources/config/appearance.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,6 +1,10 @@
|
||||
[Rules]
|
||||
# The default log level is info
|
||||
*.debug = false
|
||||
#*.info = true
|
||||
#*.warning = true
|
||||
#*.critical = true
|
||||
#*.fatal = true
|
||||
|
||||
# Uncomment a rule to see debug level logs for that category,
|
||||
# or set <category> = false to disable logging
|
||||
@@ -19,6 +23,7 @@
|
||||
#tab_supervisor = true
|
||||
|
||||
#dlg_edit_avatar = true
|
||||
#dlg_load_deck_from_website = true
|
||||
#dlg_settings = true
|
||||
#dlg_tip_of_the_day = true
|
||||
#dlg_update = true
|
||||
@@ -36,12 +41,14 @@
|
||||
#card_zone = true
|
||||
#view_zone = true
|
||||
|
||||
#game_event_handler = true
|
||||
|
||||
#user_info_connection = true
|
||||
|
||||
#picture_loader = true
|
||||
#picture_loader.worker = true
|
||||
#picture_loader.card_back_cache_fail = true
|
||||
#picture_loader.picture_to_load = true
|
||||
#card_picture_loader = true
|
||||
#card_picture_loader.worker = true
|
||||
#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
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@page deck_search_syntax_help Deck Search Syntax Help
|
||||
|
||||
## Deck Search Syntax Help
|
||||
-----
|
||||
The search bar recognizes a set of special commands.<br>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@page 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>
|
||||
|
||||
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 |
@@ -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"
|
||||
inkscape:transform-center-x="0.094945927"
|
||||
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>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,14 +1,13 @@
|
||||
#include "deck_stats_interface.h"
|
||||
|
||||
#include "decklist.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrlQuery>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||
|
||||
DeckStatsInterface::DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent)
|
||||
: QObject(parent), cardDatabase(_cardDatabase)
|
||||
@@ -70,7 +69,7 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
|
||||
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
|
||||
{
|
||||
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()) {
|
||||
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
|
||||
addedCard->setNumber(card->getNumber());
|
||||
@@ -1,10 +1,14 @@
|
||||
/**
|
||||
* @file deck_stats_interface.h
|
||||
* @ingroup ApiInterfaces
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef DECKSTATS_INTERFACE_H
|
||||
#define DECKSTATS_INTERFACE_H
|
||||
|
||||
#include "../game/cards/card_database.h"
|
||||
#include "decklist.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
|
||||
class QByteArray;
|
||||
class QNetworkAccessManager;
|
||||
@@ -1,14 +1,13 @@
|
||||
#include "tapped_out_interface.h"
|
||||
|
||||
#include "decklist.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrlQuery>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||
|
||||
TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent)
|
||||
: QObject(parent), cardDatabase(_cardDatabase)
|
||||
@@ -95,7 +94,7 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
|
||||
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
||||
{
|
||||
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())
|
||||
return;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
/**
|
||||
* @file tapped_out_interface.h
|
||||
* @ingroup ApiInterfaces
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef TAPPEDOUT_INTERFACE_H
|
||||
#define TAPPEDOUT_INTERFACE_H
|
||||
|
||||
#include "../game/cards/card_database.h"
|
||||
#include "decklist.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QObject>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
|
||||
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,118 @@
|
||||
/**
|
||||
* @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/deck_loader.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
class IJsonDeckParser
|
||||
{
|
||||
public:
|
||||
virtual ~IJsonDeckParser() = default;
|
||||
|
||||
virtual DeckLoader *parse(const QJsonObject &obj) = 0;
|
||||
};
|
||||
|
||||
class ArchidektJsonParser : public IJsonDeckParser
|
||||
{
|
||||
public:
|
||||
DeckLoader *parse(const QJsonObject &obj) override
|
||||
{
|
||||
DeckLoader *loader = new DeckLoader(nullptr);
|
||||
|
||||
QString deckName = obj.value("name").toString();
|
||||
QString deckDescription = obj.value("description").toString();
|
||||
|
||||
loader->getDeckList()->setName(deckName);
|
||||
loader->getDeckList()->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';
|
||||
}
|
||||
|
||||
loader->getDeckList()->loadFromStream_Plain(outStream, false);
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
|
||||
|
||||
return loader;
|
||||
}
|
||||
};
|
||||
|
||||
class MoxfieldJsonParser : public IJsonDeckParser
|
||||
{
|
||||
public:
|
||||
DeckLoader *parse(const QJsonObject &obj) override
|
||||
{
|
||||
DeckLoader *loader = new DeckLoader(nullptr);
|
||||
|
||||
QString deckName = obj.value("name").toString();
|
||||
QString deckDescription = obj.value("description").toString();
|
||||
|
||||
loader->getDeckList()->setName(deckName);
|
||||
loader->getDeckList()->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';
|
||||
}
|
||||
|
||||
loader->getDeckList()->loadFromStream_Plain(outStream, false);
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
|
||||
|
||||
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();
|
||||
|
||||
loader->getDeckList()->setBannerCard({commanderName, providerId});
|
||||
loader->getDeckList()->addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
|
||||
}
|
||||
}
|
||||
|
||||
return loader;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INTERFACE_JSON_DECK_PARSER_H
|
||||
@@ -1,21 +1,19 @@
|
||||
#include "spoiler_background_updater.h"
|
||||
|
||||
#include "../../game/cards/card_database.h"
|
||||
#include "../../game/cards/card_database_manager.h"
|
||||
#include "../../main.h"
|
||||
#include "../../settings/cache_settings.h"
|
||||
#include "../ui/window_main.h"
|
||||
#include "../../../../interface/window_main.h"
|
||||
#include "../../../../main.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLocale>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrl>
|
||||
#include <QtConcurrent>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
#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"
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file spoiler_background_updater.h
|
||||
* @ingroup Client
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
|
||||
#define COCKATRICE_SPOILER_DOWNLOADER_H
|
||||
|
||||
@@ -16,7 +22,7 @@ public:
|
||||
inline QString getCardUpdaterBinaryName()
|
||||
{
|
||||
return "oracle";
|
||||
};
|
||||
}
|
||||
QByteArray getHash(const QString fileName);
|
||||
QByteArray getHash(QByteArray data);
|
||||
static bool deleteSpoilerFile();
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "client_update_checker.h"
|
||||
|
||||
#include "../../settings/cache_settings.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
#include "release_channel.h"
|
||||
|
||||
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
|
||||
#define CLIENT_UPDATE_CHECKER_H
|
||||
#include <QObject>
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file release_channel.h
|
||||
* @ingroup ClientUpdate
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef RELEASECHANNEL_H
|
||||
#define RELEASECHANNEL_H
|
||||
|
||||
@@ -51,27 +57,27 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
QString getName() const
|
||||
[[nodiscard]] QString getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
QString getDescriptionUrl() const
|
||||
[[nodiscard]] QString getDescriptionUrl() const
|
||||
{
|
||||
return descriptionUrl;
|
||||
}
|
||||
QString getDownloadUrl() const
|
||||
[[nodiscard]] QString getDownloadUrl() const
|
||||
{
|
||||
return downloadUrl;
|
||||
}
|
||||
QString getCommitHash() const
|
||||
[[nodiscard]] QString getCommitHash() const
|
||||
{
|
||||
return commitHash;
|
||||
}
|
||||
QDate getPublishDate() const
|
||||
[[nodiscard]] QDate getPublishDate() const
|
||||
{
|
||||
return publishDate;
|
||||
}
|
||||
bool isCompatibleVersionFound() const
|
||||
[[nodiscard]] bool isCompatibleVersionFound() const
|
||||
{
|
||||
return compatibleVersionFound;
|
||||
}
|
||||
@@ -91,15 +97,15 @@ protected:
|
||||
|
||||
protected:
|
||||
static bool downloadMatchesCurrentOS(const QString &fileName);
|
||||
virtual QString getReleaseChannelUrl() const = 0;
|
||||
[[nodiscard]] virtual QString getReleaseChannelUrl() const = 0;
|
||||
|
||||
public:
|
||||
Release *getLastRelease()
|
||||
{
|
||||
return lastRelease;
|
||||
}
|
||||
virtual QString getManualDownloadUrl() const = 0;
|
||||
virtual QString getName() const = 0;
|
||||
[[nodiscard]] virtual QString getManualDownloadUrl() const = 0;
|
||||
[[nodiscard]] virtual QString getName() const = 0;
|
||||
void checkForUpdates();
|
||||
signals:
|
||||
void finishedCheck(bool needToUpdate, bool isCompatible, Release *release);
|
||||
@@ -116,12 +122,12 @@ public:
|
||||
explicit StableReleaseChannel() = default;
|
||||
~StableReleaseChannel() override = default;
|
||||
|
||||
QString getManualDownloadUrl() const override;
|
||||
[[nodiscard]] QString getManualDownloadUrl() const override;
|
||||
|
||||
QString getName() const override;
|
||||
[[nodiscard]] QString getName() const override;
|
||||
|
||||
protected:
|
||||
QString getReleaseChannelUrl() const override;
|
||||
[[nodiscard]] QString getReleaseChannelUrl() const override;
|
||||
protected slots:
|
||||
|
||||
void releaseListFinished() override;
|
||||
@@ -137,12 +143,12 @@ public:
|
||||
BetaReleaseChannel() = default;
|
||||
~BetaReleaseChannel() override = default;
|
||||
|
||||
QString getManualDownloadUrl() const override;
|
||||
[[nodiscard]] QString getManualDownloadUrl() const override;
|
||||
|
||||
QString getName() const override;
|
||||
[[nodiscard]] QString getName() const override;
|
||||
|
||||
protected:
|
||||
QString getReleaseChannelUrl() const override;
|
||||
[[nodiscard]] QString getReleaseChannelUrl() const override;
|
||||
protected slots:
|
||||
|
||||
void releaseListFinished() override;
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "update_downloader.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
|
||||
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
|
||||
#define COCKATRICE_UPDATEDOWNLOADER_H
|
||||
|
||||
#include <QDate>
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QtNetwork>
|
||||
|
||||
class UpdateDownloader : public QObject
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "cache_settings.h"
|
||||
|
||||
#include "../client/network/release_channel.h"
|
||||
#include "../network/update/client/release_channel.h"
|
||||
#include "card_counter_settings.h"
|
||||
#include "card_override_settings.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QApplication>
|
||||
@@ -12,9 +11,15 @@
|
||||
#include <QGlobalStatic>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
#include <libcockatrice/settings/card_override_settings.h>
|
||||
#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()
|
||||
{
|
||||
@@ -61,9 +66,9 @@ void SettingsCache::translateLegacySettings()
|
||||
QStringList setsGroups = legacySetting.childGroups();
|
||||
for (int i = 0; i < setsGroups.size(); i++) {
|
||||
legacySetting.beginGroup(setsGroups.at(i));
|
||||
cardDatabase().setEnabled(setsGroups.at(i), legacySetting.value("enabled").toBool());
|
||||
cardDatabase().setIsKnown(setsGroups.at(i), legacySetting.value("isknown").toBool());
|
||||
cardDatabase().setSortKey(setsGroups.at(i), legacySetting.value("sortkey").toUInt());
|
||||
cardDatabase()->setEnabled(setsGroups.at(i), legacySetting.value("enabled").toBool());
|
||||
cardDatabase()->setIsKnown(setsGroups.at(i), legacySetting.value("isknown").toBool());
|
||||
cardDatabase()->setSortKey(setsGroups.at(i), legacySetting.value("sortkey").toUInt());
|
||||
legacySetting.endGroup();
|
||||
}
|
||||
QStringList setsKeys = legacySetting.allKeys();
|
||||
@@ -217,6 +222,9 @@ SettingsCache::SettingsCache()
|
||||
|
||||
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();
|
||||
tabServerOpen = settings->value("tabs/server", true).toBool();
|
||||
tabAccountOpen = settings->value("tabs/account", true).toBool();
|
||||
@@ -253,6 +261,7 @@ SettingsCache::SettingsCache()
|
||||
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
|
||||
clickPlaysAllSelected = settings->value("interface/clickPlaysAllSelected", true).toBool();
|
||||
playToStack = settings->value("interface/playtostack", true).toBool();
|
||||
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
||||
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
||||
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
||||
tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray();
|
||||
@@ -301,10 +310,15 @@ SettingsCache::SettingsCache()
|
||||
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
|
||||
defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
|
||||
visualDatabaseDisplayFilterToMostRecentSetsEnabled =
|
||||
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
|
||||
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", false).toBool();
|
||||
visualDatabaseDisplayFilterToMostRecentSetsAmount =
|
||||
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
|
||||
visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
|
||||
visualDeckEditorCardSize = settings->value("interface/visualdeckeditorcardsize", 100).toInt();
|
||||
visualDatabaseDisplayCardSize = settings->value("interface/visualdatabasedisplaycardsize", 100).toInt();
|
||||
edhrecCardSize = settings->value("interface/edhreccardsize", 100).toInt();
|
||||
archidektPreviewSize = settings->value("interface/archidektpreviewsize", 100).toInt();
|
||||
|
||||
horizontalHand = settings->value("hand/horizontal", true).toBool();
|
||||
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
||||
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
|
||||
@@ -355,6 +369,7 @@ SettingsCache::SettingsCache()
|
||||
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
|
||||
createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool();
|
||||
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
||||
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
|
||||
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
||||
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
|
||||
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
||||
@@ -549,6 +564,20 @@ void SettingsCache::setThemeName(const QString &_themeName)
|
||||
emit themeChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setHomeTabBackgroundSource(const QString &_backgroundSource)
|
||||
{
|
||||
homeTabBackgroundSource = _backgroundSource;
|
||||
settings->setValue("home/background", homeTabBackgroundSource);
|
||||
emit homeTabBackgroundSourceChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setHomeTabBackgroundShuffleFrequency(int _frequency)
|
||||
{
|
||||
homeTabBackgroundShuffleFrequency = _frequency;
|
||||
settings->setValue("home/background/shuffleTimer", homeTabBackgroundShuffleFrequency);
|
||||
emit homeTabBackgroundShuffleFrequencyChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
||||
{
|
||||
tabVisualDeckStorageOpen = value;
|
||||
@@ -641,6 +670,12 @@ void SettingsCache::setPlayToStack(QT_STATE_CHANGED_T _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)
|
||||
{
|
||||
startingHandSize = _startingHandSize;
|
||||
@@ -833,6 +868,34 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
|
||||
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
|
||||
}
|
||||
|
||||
void SettingsCache::setVisualDeckEditorCardSize(int _visualDeckEditorCardSize)
|
||||
{
|
||||
visualDeckEditorCardSize = _visualDeckEditorCardSize;
|
||||
settings->setValue("interface/visualdeckeditorcardsize", visualDeckEditorCardSize);
|
||||
emit visualDeckEditorCardSizeChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize)
|
||||
{
|
||||
visualDatabaseDisplayCardSize = _visualDatabaseDisplayCardSize;
|
||||
settings->setValue("interface/visualdatabasedisplaycardsize", visualDatabaseDisplayCardSize);
|
||||
emit visualDatabaseDisplayCardSizeChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setEDHRecCardSize(int _edhrecCardSize)
|
||||
{
|
||||
edhrecCardSize = _edhrecCardSize;
|
||||
settings->setValue("interface/edhreccardsize", edhrecCardSize);
|
||||
emit edhRecCardSizeChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setArchidektPreviewCardSize(int _archidektPreviewCardSize)
|
||||
{
|
||||
archidektPreviewSize = _archidektPreviewCardSize;
|
||||
settings->setValue("interface/archidektpreviewsize", archidektPreviewSize);
|
||||
emit archidektPreviewSizeChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setDefaultDeckEditorType(int value)
|
||||
{
|
||||
defaultDeckEditorType = value;
|
||||
@@ -1360,7 +1423,13 @@ void SettingsCache::setDefaultStartingLifeTotal(const int _defaultStartingLifeTo
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -1373,6 +1442,7 @@ void SettingsCache::setStartupCardUpdateCheckPromptForUpdate(bool value)
|
||||
startupCardUpdateCheckPromptForUpdate = value;
|
||||
settings->setValue("personal/startupCardUpdateCheckPromptForUpdate", startupCardUpdateCheckPromptForUpdate);
|
||||
}
|
||||
|
||||
void SettingsCache::setStartupCardUpdateCheckAlwaysUpdate(bool value)
|
||||
{
|
||||
startupCardUpdateCheckAlwaysUpdate = value;
|
||||
@@ -1475,11 +1545,6 @@ void SettingsCache::resetPaths()
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCache &SettingsCache::instance()
|
||||
{
|
||||
return *settingsCache;
|
||||
}
|
||||
|
||||
CardCounterSettings &SettingsCache::cardCounters() const
|
||||
{
|
||||
return *cardCounterSettings;
|
||||
@@ -1,23 +1,30 @@
|
||||
/**
|
||||
* @file cache_settings.h
|
||||
* @ingroup Settings
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef 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 <QDate>
|
||||
#include <QLoggingCategory>
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
#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");
|
||||
|
||||
@@ -126,15 +133,16 @@ inline QStringList defaultTags = {
|
||||
class QSettings;
|
||||
class CardCounterSettings;
|
||||
|
||||
class SettingsCache : public QObject
|
||||
class SettingsCache : public ICardDatabasePathProvider, public INetworkSettingsProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void langChanged();
|
||||
void picsPathChanged();
|
||||
void cardDatabasePathChanged();
|
||||
void themeChanged();
|
||||
void homeTabBackgroundSourceChanged();
|
||||
void homeTabBackgroundShuffleFrequencyChanged();
|
||||
void picDownloadChanged();
|
||||
void showStatusBarChanged(bool state);
|
||||
void displayCardNamesChanged();
|
||||
@@ -158,6 +166,10 @@ signals:
|
||||
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
|
||||
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
|
||||
void visualDeckEditorSampleHandSizeAmountChanged(int amount);
|
||||
void visualDeckEditorCardSizeChanged();
|
||||
void visualDatabaseDisplayCardSizeChanged();
|
||||
void edhRecCardSizeChanged();
|
||||
void archidektPreviewSizeChanged();
|
||||
void horizontalHandChanged();
|
||||
void handJustificationChanged();
|
||||
void invertVerticalCoordinateChanged();
|
||||
@@ -195,7 +207,7 @@ private:
|
||||
QByteArray setsDialogGeometry;
|
||||
QString lang;
|
||||
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,
|
||||
tabLogOpen;
|
||||
bool checkUpdatesOnStartup;
|
||||
@@ -208,6 +220,7 @@ private:
|
||||
bool notifyAboutNewVersion;
|
||||
bool showTipsOnStartup;
|
||||
QList<int> seenTips;
|
||||
int homeTabBackgroundShuffleFrequency;
|
||||
bool mbDownloadSpoilers;
|
||||
int updateReleaseChannel;
|
||||
int maxFontSize;
|
||||
@@ -218,6 +231,7 @@ private:
|
||||
bool doubleClickToPlay;
|
||||
bool clickPlaysAllSelected;
|
||||
bool playToStack;
|
||||
bool doNotDeleteArrowsInSubPhases;
|
||||
int startingHandSize;
|
||||
bool annotateTokens;
|
||||
QByteArray tabGameSplitterSizes;
|
||||
@@ -239,6 +253,10 @@ private:
|
||||
QStringList visualDeckStorageDefaultTagsList;
|
||||
bool visualDeckStorageSearchFolderNames;
|
||||
int visualDeckStorageCardSize;
|
||||
int visualDeckEditorCardSize;
|
||||
int visualDatabaseDisplayCardSize;
|
||||
int edhrecCardSize;
|
||||
int archidektPreviewSize;
|
||||
bool visualDeckStorageDrawUnusedColorIdentities;
|
||||
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||
int visualDeckStorageTooltipType;
|
||||
@@ -302,11 +320,12 @@ private:
|
||||
bool spectatorsCanSeeEverything;
|
||||
bool createGameAsSpectator;
|
||||
int defaultStartingLifeTotal;
|
||||
bool shareDecklistsOnLoad;
|
||||
int keepalive;
|
||||
int timeout;
|
||||
void translateLegacySettings();
|
||||
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
|
||||
QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
||||
[[nodiscard]] QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
|
||||
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
||||
void loadPaths();
|
||||
bool rememberGameSettings;
|
||||
QList<ReleaseChannel *> releaseChannels;
|
||||
@@ -318,129 +337,137 @@ public:
|
||||
SettingsCache();
|
||||
QString getDataPath();
|
||||
QString getSettingsPath();
|
||||
QString getCachePath() const;
|
||||
QString getNetworkCachePath() const;
|
||||
const QByteArray &getMainWindowGeometry() const
|
||||
[[nodiscard]] QString getCachePath() const;
|
||||
[[nodiscard]] QString getNetworkCachePath() const;
|
||||
[[nodiscard]] const QByteArray &getMainWindowGeometry() const
|
||||
{
|
||||
return mainWindowGeometry;
|
||||
}
|
||||
const QByteArray &getTokenDialogGeometry() const
|
||||
[[nodiscard]] const QByteArray &getTokenDialogGeometry() const
|
||||
{
|
||||
return tokenDialogGeometry;
|
||||
}
|
||||
const QByteArray &getSetsDialogGeometry() const
|
||||
[[nodiscard]] const QByteArray &getSetsDialogGeometry() const
|
||||
{
|
||||
return setsDialogGeometry;
|
||||
}
|
||||
QString getLang() const
|
||||
[[nodiscard]] QString getLang() const
|
||||
{
|
||||
return lang;
|
||||
}
|
||||
QString getDeckPath() const
|
||||
[[nodiscard]] QString getDeckPath() const
|
||||
{
|
||||
return deckPath;
|
||||
}
|
||||
QString getFiltersPath() const
|
||||
[[nodiscard]] QString getFiltersPath() const
|
||||
{
|
||||
return filtersPath;
|
||||
}
|
||||
QString getReplaysPath() const
|
||||
[[nodiscard]] QString getReplaysPath() const
|
||||
{
|
||||
return replaysPath;
|
||||
}
|
||||
QString getThemesPath() const
|
||||
[[nodiscard]] QString getThemesPath() const
|
||||
{
|
||||
return themesPath;
|
||||
}
|
||||
QString getPicsPath() const
|
||||
[[nodiscard]] QString getPicsPath() const
|
||||
{
|
||||
return picsPath;
|
||||
}
|
||||
QString getRedirectCachePath() const
|
||||
[[nodiscard]] QString getRedirectCachePath() const
|
||||
{
|
||||
return redirectCachePath;
|
||||
}
|
||||
QString getCustomPicsPath() const
|
||||
[[nodiscard]] QString getCustomPicsPath() const
|
||||
{
|
||||
return customPicsPath;
|
||||
}
|
||||
QString getCustomCardDatabasePath() const
|
||||
[[nodiscard]] QString getCustomCardDatabasePath() const override
|
||||
{
|
||||
return customCardDatabasePath;
|
||||
}
|
||||
QString getCardDatabasePath() const
|
||||
[[nodiscard]] QString getCardDatabasePath() const override
|
||||
{
|
||||
return cardDatabasePath;
|
||||
}
|
||||
QString getSpoilerCardDatabasePath() const
|
||||
[[nodiscard]] QString getSpoilerCardDatabasePath() const override
|
||||
{
|
||||
return spoilerDatabasePath;
|
||||
}
|
||||
QString getTokenDatabasePath() const
|
||||
[[nodiscard]] QString getTokenDatabasePath() const override
|
||||
{
|
||||
return tokenDatabasePath;
|
||||
}
|
||||
QString getThemeName() const
|
||||
[[nodiscard]] QString getThemeName() const
|
||||
{
|
||||
return themeName;
|
||||
}
|
||||
bool getTabVisualDeckStorageOpen() const
|
||||
[[nodiscard]] QString getHomeTabBackgroundSource() const
|
||||
{
|
||||
return homeTabBackgroundSource;
|
||||
}
|
||||
[[nodiscard]] int getHomeTabBackgroundShuffleFrequency() const
|
||||
{
|
||||
return homeTabBackgroundShuffleFrequency;
|
||||
}
|
||||
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
|
||||
{
|
||||
return tabVisualDeckStorageOpen;
|
||||
}
|
||||
bool getTabServerOpen() const
|
||||
[[nodiscard]] bool getTabServerOpen() const
|
||||
{
|
||||
return tabServerOpen;
|
||||
}
|
||||
bool getTabAccountOpen() const
|
||||
[[nodiscard]] bool getTabAccountOpen() const
|
||||
{
|
||||
return tabAccountOpen;
|
||||
}
|
||||
bool getTabDeckStorageOpen() const
|
||||
[[nodiscard]] bool getTabDeckStorageOpen() const
|
||||
{
|
||||
return tabDeckStorageOpen;
|
||||
}
|
||||
bool getTabReplaysOpen() const
|
||||
[[nodiscard]] bool getTabReplaysOpen() const
|
||||
{
|
||||
return tabReplaysOpen;
|
||||
}
|
||||
bool getTabAdminOpen() const
|
||||
[[nodiscard]] bool getTabAdminOpen() const
|
||||
{
|
||||
return tabAdminOpen;
|
||||
}
|
||||
bool getTabLogOpen() const
|
||||
[[nodiscard]] bool getTabLogOpen() const
|
||||
{
|
||||
return tabLogOpen;
|
||||
}
|
||||
QString getChatMentionColor() const
|
||||
[[nodiscard]] QString getChatMentionColor() const
|
||||
{
|
||||
return chatMentionColor;
|
||||
}
|
||||
QString getChatHighlightColor() const
|
||||
[[nodiscard]] QString getChatHighlightColor() const
|
||||
{
|
||||
return chatHighlightColor;
|
||||
}
|
||||
bool getPicDownload() const
|
||||
[[nodiscard]] bool getPicDownload() const
|
||||
{
|
||||
return picDownload;
|
||||
}
|
||||
bool getShowStatusBar() const
|
||||
[[nodiscard]] bool getShowStatusBar() const
|
||||
{
|
||||
return showStatusBar;
|
||||
}
|
||||
bool getNotificationsEnabled() const
|
||||
[[nodiscard]] bool getNotificationsEnabled() const
|
||||
{
|
||||
return notificationsEnabled;
|
||||
}
|
||||
bool getSpectatorNotificationsEnabled() const
|
||||
[[nodiscard]] bool getSpectatorNotificationsEnabled() const
|
||||
{
|
||||
return spectatorNotificationsEnabled;
|
||||
}
|
||||
bool getBuddyConnectNotificationsEnabled() const
|
||||
[[nodiscard]] bool getBuddyConnectNotificationsEnabled() const
|
||||
{
|
||||
return buddyConnectNotificationsEnabled;
|
||||
}
|
||||
bool getCheckUpdatesOnStartup() const
|
||||
[[nodiscard]] bool getCheckUpdatesOnStartup() const
|
||||
{
|
||||
return checkUpdatesOnStartup;
|
||||
}
|
||||
@@ -452,243 +479,263 @@ public:
|
||||
{
|
||||
return startupCardUpdateCheckAlwaysUpdate;
|
||||
}
|
||||
int getCardUpdateCheckInterval() const
|
||||
[[nodiscard]] int getCardUpdateCheckInterval() const
|
||||
{
|
||||
return cardUpdateCheckInterval;
|
||||
}
|
||||
QDate getLastCardUpdateCheck() const
|
||||
[[nodiscard]] QDate getLastCardUpdateCheck() const
|
||||
{
|
||||
return lastCardUpdateCheck;
|
||||
}
|
||||
bool getCardUpdateCheckRequired() const
|
||||
[[nodiscard]] bool getCardUpdateCheckRequired() const
|
||||
{
|
||||
return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() &&
|
||||
getLastCardUpdateCheck() != QDateTime::currentDateTime().date();
|
||||
}
|
||||
bool getNotifyAboutUpdates() const
|
||||
[[nodiscard]] bool getNotifyAboutUpdates() const override
|
||||
{
|
||||
return notifyAboutUpdates;
|
||||
}
|
||||
bool getNotifyAboutNewVersion() const
|
||||
[[nodiscard]] bool getNotifyAboutNewVersion() const
|
||||
{
|
||||
return notifyAboutNewVersion;
|
||||
}
|
||||
bool getShowTipsOnStartup() const
|
||||
[[nodiscard]] bool getShowTipsOnStartup() const
|
||||
{
|
||||
return showTipsOnStartup;
|
||||
}
|
||||
QList<int> getSeenTips() const
|
||||
[[nodiscard]] QList<int> getSeenTips() const
|
||||
{
|
||||
return seenTips;
|
||||
}
|
||||
int getUpdateReleaseChannelIndex() const
|
||||
[[nodiscard]] int getUpdateReleaseChannelIndex() const
|
||||
{
|
||||
return updateReleaseChannel;
|
||||
}
|
||||
ReleaseChannel *getUpdateReleaseChannel() const
|
||||
[[nodiscard]] ReleaseChannel *getUpdateReleaseChannel() const
|
||||
{
|
||||
return releaseChannels.at(qMax(0, updateReleaseChannel));
|
||||
}
|
||||
QList<ReleaseChannel *> getUpdateReleaseChannels() const
|
||||
[[nodiscard]] QList<ReleaseChannel *> getUpdateReleaseChannels() const
|
||||
{
|
||||
return releaseChannels;
|
||||
}
|
||||
|
||||
bool getDoubleClickToPlay() const
|
||||
[[nodiscard]] bool getDoubleClickToPlay() const
|
||||
{
|
||||
return doubleClickToPlay;
|
||||
}
|
||||
bool getClickPlaysAllSelected() const
|
||||
[[nodiscard]] bool getClickPlaysAllSelected() const
|
||||
{
|
||||
return clickPlaysAllSelected;
|
||||
}
|
||||
bool getPlayToStack() const
|
||||
[[nodiscard]] bool getPlayToStack() const
|
||||
{
|
||||
return playToStack;
|
||||
}
|
||||
int getStartingHandSize() const
|
||||
[[nodiscard]] bool getDoNotDeleteArrowsInSubPhases() const
|
||||
{
|
||||
return doNotDeleteArrowsInSubPhases;
|
||||
}
|
||||
[[nodiscard]] int getStartingHandSize() const
|
||||
{
|
||||
return startingHandSize;
|
||||
}
|
||||
bool getAnnotateTokens() const
|
||||
[[nodiscard]] bool getAnnotateTokens() const
|
||||
{
|
||||
return annotateTokens;
|
||||
}
|
||||
QByteArray getTabGameSplitterSizes() const
|
||||
[[nodiscard]] QByteArray getTabGameSplitterSizes() const
|
||||
{
|
||||
return tabGameSplitterSizes;
|
||||
}
|
||||
bool getShowShortcuts() const
|
||||
[[nodiscard]] bool getShowShortcuts() const
|
||||
{
|
||||
return showShortcuts;
|
||||
}
|
||||
bool getDisplayCardNames() const
|
||||
[[nodiscard]] bool getDisplayCardNames() const
|
||||
{
|
||||
return displayCardNames;
|
||||
}
|
||||
bool getOverrideAllCardArtWithPersonalPreference() const
|
||||
[[nodiscard]] bool getOverrideAllCardArtWithPersonalPreference() const
|
||||
{
|
||||
return overrideAllCardArtWithPersonalPreference;
|
||||
}
|
||||
bool getBumpSetsWithCardsInDeckToTop() const
|
||||
[[nodiscard]] bool getBumpSetsWithCardsInDeckToTop() const
|
||||
{
|
||||
return bumpSetsWithCardsInDeckToTop;
|
||||
}
|
||||
int getPrintingSelectorSortOrder() const
|
||||
[[nodiscard]] int getPrintingSelectorSortOrder() const
|
||||
{
|
||||
return printingSelectorSortOrder;
|
||||
}
|
||||
int getPrintingSelectorCardSize() const
|
||||
[[nodiscard]] int getPrintingSelectorCardSize() const
|
||||
{
|
||||
return printingSelectorCardSize;
|
||||
}
|
||||
bool getIncludeRebalancedCards() const
|
||||
[[nodiscard]] bool getIncludeRebalancedCards() const
|
||||
{
|
||||
return includeRebalancedCards;
|
||||
}
|
||||
bool getPrintingSelectorNavigationButtonsVisible() const
|
||||
[[nodiscard]] bool getPrintingSelectorNavigationButtonsVisible() const
|
||||
{
|
||||
return printingSelectorNavigationButtonsVisible;
|
||||
}
|
||||
bool getDeckEditorBannerCardComboBoxVisible() const
|
||||
[[nodiscard]] bool getDeckEditorBannerCardComboBoxVisible() const
|
||||
{
|
||||
return deckEditorBannerCardComboBoxVisible;
|
||||
}
|
||||
bool getDeckEditorTagsWidgetVisible() const
|
||||
[[nodiscard]] bool getDeckEditorTagsWidgetVisible() const
|
||||
{
|
||||
return deckEditorTagsWidgetVisible;
|
||||
}
|
||||
int getVisualDeckStorageSortingOrder() const
|
||||
[[nodiscard]] int getVisualDeckStorageSortingOrder() const
|
||||
{
|
||||
return visualDeckStorageSortingOrder;
|
||||
}
|
||||
bool getVisualDeckStorageShowFolders() const
|
||||
[[nodiscard]] bool getVisualDeckStorageShowFolders() const
|
||||
{
|
||||
return visualDeckStorageShowFolders;
|
||||
}
|
||||
bool getVisualDeckStorageShowTagFilter() const
|
||||
[[nodiscard]] bool getVisualDeckStorageShowTagFilter() const
|
||||
{
|
||||
return visualDeckStorageShowTagFilter;
|
||||
}
|
||||
QStringList getVisualDeckStorageDefaultTagsList() const
|
||||
[[nodiscard]] QStringList getVisualDeckStorageDefaultTagsList() const
|
||||
{
|
||||
return visualDeckStorageDefaultTagsList;
|
||||
}
|
||||
bool getVisualDeckStorageSearchFolderNames() const
|
||||
[[nodiscard]] bool getVisualDeckStorageSearchFolderNames() const
|
||||
{
|
||||
return visualDeckStorageSearchFolderNames;
|
||||
}
|
||||
bool getVisualDeckStorageShowBannerCardComboBox() const
|
||||
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
|
||||
{
|
||||
return visualDeckStorageShowBannerCardComboBox;
|
||||
}
|
||||
bool getVisualDeckStorageShowTagsOnDeckPreviews() const
|
||||
[[nodiscard]] bool getVisualDeckStorageShowTagsOnDeckPreviews() const
|
||||
{
|
||||
return visualDeckStorageShowTagsOnDeckPreviews;
|
||||
}
|
||||
int getVisualDeckStorageCardSize() const
|
||||
[[nodiscard]] int getVisualDeckStorageCardSize() const
|
||||
{
|
||||
return visualDeckStorageCardSize;
|
||||
}
|
||||
bool getVisualDeckStorageDrawUnusedColorIdentities() const
|
||||
[[nodiscard]] bool getVisualDeckStorageDrawUnusedColorIdentities() const
|
||||
{
|
||||
return visualDeckStorageDrawUnusedColorIdentities;
|
||||
}
|
||||
int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
|
||||
[[nodiscard]] int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
|
||||
{
|
||||
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||
}
|
||||
int getVisualDeckStorageTooltipType() const
|
||||
[[nodiscard]] int getVisualDeckStorageTooltipType() const
|
||||
{
|
||||
return visualDeckStorageTooltipType;
|
||||
}
|
||||
bool getVisualDeckStoragePromptForConversion() const
|
||||
[[nodiscard]] bool getVisualDeckStoragePromptForConversion() const
|
||||
{
|
||||
return visualDeckStoragePromptForConversion;
|
||||
}
|
||||
bool getVisualDeckStorageAlwaysConvert() const
|
||||
[[nodiscard]] bool getVisualDeckStorageAlwaysConvert() const
|
||||
{
|
||||
return visualDeckStorageAlwaysConvert;
|
||||
}
|
||||
bool getVisualDeckStorageInGame() const
|
||||
[[nodiscard]] bool getVisualDeckStorageInGame() const
|
||||
{
|
||||
return visualDeckStorageInGame;
|
||||
}
|
||||
bool getVisualDeckStorageSelectionAnimation() const
|
||||
[[nodiscard]] bool getVisualDeckStorageSelectionAnimation() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
|
||||
[[nodiscard]] bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
|
||||
{
|
||||
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
|
||||
}
|
||||
int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
|
||||
[[nodiscard]] int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
|
||||
{
|
||||
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
|
||||
}
|
||||
int getVisualDeckEditorSampleHandSize() const
|
||||
[[nodiscard]] int getVisualDeckEditorSampleHandSize() const
|
||||
{
|
||||
return visualDeckEditorSampleHandSize;
|
||||
}
|
||||
bool getHorizontalHand() const
|
||||
[[nodiscard]] bool getHorizontalHand() const
|
||||
{
|
||||
return horizontalHand;
|
||||
}
|
||||
bool getInvertVerticalCoordinate() const
|
||||
[[nodiscard]] bool getInvertVerticalCoordinate() const
|
||||
{
|
||||
return invertVerticalCoordinate;
|
||||
}
|
||||
int getMinPlayersForMultiColumnLayout() const
|
||||
[[nodiscard]] int getMinPlayersForMultiColumnLayout() const
|
||||
{
|
||||
return minPlayersForMultiColumnLayout;
|
||||
}
|
||||
bool getTapAnimation() const
|
||||
[[nodiscard]] bool getTapAnimation() const
|
||||
{
|
||||
return tapAnimation;
|
||||
}
|
||||
bool getAutoRotateSidewaysLayoutCards() const
|
||||
[[nodiscard]] bool getAutoRotateSidewaysLayoutCards() const
|
||||
{
|
||||
return autoRotateSidewaysLayoutCards;
|
||||
}
|
||||
bool getOpenDeckInNewTab() const
|
||||
[[nodiscard]] bool getOpenDeckInNewTab() const
|
||||
{
|
||||
return openDeckInNewTab;
|
||||
}
|
||||
int getRewindBufferingMs() const
|
||||
[[nodiscard]] int getRewindBufferingMs() const
|
||||
{
|
||||
return rewindBufferingMs;
|
||||
}
|
||||
bool getChatMention() const
|
||||
[[nodiscard]] bool getChatMention() const
|
||||
{
|
||||
return chatMention;
|
||||
}
|
||||
bool getChatMentionCompleter() const
|
||||
[[nodiscard]] bool getChatMentionCompleter() const
|
||||
{
|
||||
return chatMentionCompleter;
|
||||
}
|
||||
bool getChatMentionForeground() const
|
||||
[[nodiscard]] bool getChatMentionForeground() const
|
||||
{
|
||||
return chatMentionForeground;
|
||||
}
|
||||
bool getChatHighlightForeground() const
|
||||
[[nodiscard]] bool getChatHighlightForeground() const
|
||||
{
|
||||
return chatHighlightForeground;
|
||||
}
|
||||
/**
|
||||
* Currently selected index for the `Group by X` QComboBox
|
||||
*/
|
||||
int getZoneViewGroupByIndex() const
|
||||
[[nodiscard]] int getZoneViewGroupByIndex() const
|
||||
{
|
||||
return zoneViewGroupByIndex;
|
||||
}
|
||||
/**
|
||||
* Currently selected index for the `Sort by X` QComboBox
|
||||
*/
|
||||
int getZoneViewSortByIndex() const
|
||||
[[nodiscard]] int getZoneViewSortByIndex() const
|
||||
{
|
||||
return zoneViewSortByIndex;
|
||||
}
|
||||
@@ -696,144 +743,148 @@ public:
|
||||
Returns 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;
|
||||
}
|
||||
bool getSoundEnabled() const
|
||||
[[nodiscard]] bool getSoundEnabled() const
|
||||
{
|
||||
return soundEnabled;
|
||||
}
|
||||
QString getSoundThemeName() const
|
||||
[[nodiscard]] QString getSoundThemeName() const
|
||||
{
|
||||
return soundThemeName;
|
||||
}
|
||||
bool getIgnoreUnregisteredUsers() const
|
||||
[[nodiscard]] bool getIgnoreUnregisteredUsers() const
|
||||
{
|
||||
return ignoreUnregisteredUsers;
|
||||
}
|
||||
bool getIgnoreUnregisteredUserMessages() const
|
||||
[[nodiscard]] bool getIgnoreUnregisteredUserMessages() const
|
||||
{
|
||||
return ignoreUnregisteredUserMessages;
|
||||
}
|
||||
int getPixmapCacheSize() const
|
||||
[[nodiscard]] int getPixmapCacheSize() const
|
||||
{
|
||||
return pixmapCacheSize;
|
||||
}
|
||||
int getNetworkCacheSizeInMB() const
|
||||
[[nodiscard]] int getNetworkCacheSizeInMB() const
|
||||
{
|
||||
return networkCacheSize;
|
||||
}
|
||||
int getRedirectCacheTtl() const
|
||||
[[nodiscard]] int getRedirectCacheTtl() const
|
||||
{
|
||||
return redirectCacheTtl;
|
||||
}
|
||||
bool getScaleCards() const
|
||||
[[nodiscard]] bool getScaleCards() const
|
||||
{
|
||||
return scaleCards;
|
||||
}
|
||||
int getStackCardOverlapPercent() const
|
||||
[[nodiscard]] int getStackCardOverlapPercent() const
|
||||
{
|
||||
return verticalCardOverlapPercent;
|
||||
}
|
||||
bool getShowMessagePopup() const
|
||||
[[nodiscard]] bool getShowMessagePopup() const
|
||||
{
|
||||
return showMessagePopups;
|
||||
}
|
||||
bool getShowMentionPopup() const
|
||||
[[nodiscard]] bool getShowMentionPopup() const
|
||||
{
|
||||
return showMentionPopups;
|
||||
}
|
||||
bool getRoomHistory() const
|
||||
[[nodiscard]] bool getRoomHistory() const
|
||||
{
|
||||
return roomHistory;
|
||||
}
|
||||
bool getLeftJustified() const
|
||||
[[nodiscard]] bool getLeftJustified() const
|
||||
{
|
||||
return leftJustified;
|
||||
}
|
||||
int getMasterVolume() const
|
||||
[[nodiscard]] int getMasterVolume() const
|
||||
{
|
||||
return masterVolume;
|
||||
}
|
||||
int getCardInfoViewMode() const
|
||||
[[nodiscard]] int getCardInfoViewMode() const
|
||||
{
|
||||
return cardInfoViewMode;
|
||||
}
|
||||
QStringList getCountries() const;
|
||||
QString getHighlightWords() const
|
||||
[[nodiscard]] QStringList getCountries() const;
|
||||
[[nodiscard]] QString getHighlightWords() const
|
||||
{
|
||||
return highlightWords;
|
||||
}
|
||||
QString getGameDescription() const
|
||||
[[nodiscard]] QString getGameDescription() const
|
||||
{
|
||||
return gameDescription;
|
||||
}
|
||||
int getMaxPlayers() const
|
||||
[[nodiscard]] int getMaxPlayers() const
|
||||
{
|
||||
return maxPlayers;
|
||||
}
|
||||
QString getGameTypes() const
|
||||
[[nodiscard]] QString getGameTypes() const
|
||||
{
|
||||
return gameTypes;
|
||||
}
|
||||
bool getOnlyBuddies() const
|
||||
[[nodiscard]] bool getOnlyBuddies() const
|
||||
{
|
||||
return onlyBuddies;
|
||||
}
|
||||
bool getOnlyRegistered() const
|
||||
[[nodiscard]] bool getOnlyRegistered() const
|
||||
{
|
||||
return onlyRegistered;
|
||||
}
|
||||
bool getSpectatorsAllowed() const
|
||||
[[nodiscard]] bool getSpectatorsAllowed() const
|
||||
{
|
||||
return spectatorsAllowed;
|
||||
}
|
||||
bool getSpectatorsNeedPassword() const
|
||||
[[nodiscard]] bool getSpectatorsNeedPassword() const
|
||||
{
|
||||
return spectatorsNeedPassword;
|
||||
}
|
||||
bool getSpectatorsCanTalk() const
|
||||
[[nodiscard]] bool getSpectatorsCanTalk() const
|
||||
{
|
||||
return spectatorsCanTalk;
|
||||
}
|
||||
bool getSpectatorsCanSeeEverything() const
|
||||
[[nodiscard]] bool getSpectatorsCanSeeEverything() const
|
||||
{
|
||||
return spectatorsCanSeeEverything;
|
||||
}
|
||||
int getDefaultStartingLifeTotal() const
|
||||
[[nodiscard]] int getDefaultStartingLifeTotal() const
|
||||
{
|
||||
return defaultStartingLifeTotal;
|
||||
}
|
||||
bool getCreateGameAsSpectator() const
|
||||
[[nodiscard]] bool getShareDecklistsOnLoad() const
|
||||
{
|
||||
return shareDecklistsOnLoad;
|
||||
}
|
||||
[[nodiscard]] bool getCreateGameAsSpectator() const
|
||||
{
|
||||
return createGameAsSpectator;
|
||||
}
|
||||
bool getRememberGameSettings() const
|
||||
[[nodiscard]] bool getRememberGameSettings() const
|
||||
{
|
||||
return rememberGameSettings;
|
||||
}
|
||||
int getKeepAlive() const
|
||||
[[nodiscard]] int getKeepAlive() const override
|
||||
{
|
||||
return keepalive;
|
||||
}
|
||||
int getTimeOut() const
|
||||
[[nodiscard]] int getTimeOut() const override
|
||||
{
|
||||
return timeout;
|
||||
}
|
||||
int getMaxFontSize() const
|
||||
[[nodiscard]] int getMaxFontSize() const
|
||||
{
|
||||
return maxFontSize;
|
||||
}
|
||||
void setClientID(const QString &clientID);
|
||||
void setClientVersion(const QString &clientVersion);
|
||||
void setKnownMissingFeatures(const QString &_knownMissingFeatures);
|
||||
void setKnownMissingFeatures(const QString &_knownMissingFeatures) override;
|
||||
void setUseTearOffMenus(bool _useTearOffMenus);
|
||||
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
|
||||
void setCardViewExpandedRowsMax(int value);
|
||||
void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
|
||||
void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
|
||||
QString getClientID()
|
||||
QString getClientID() override
|
||||
{
|
||||
return clientID;
|
||||
}
|
||||
@@ -841,7 +892,7 @@ public:
|
||||
{
|
||||
return clientVersion;
|
||||
}
|
||||
QString getKnownMissingFeatures()
|
||||
QString getKnownMissingFeatures() override
|
||||
{
|
||||
return knownMissingFeatures;
|
||||
}
|
||||
@@ -849,73 +900,73 @@ public:
|
||||
{
|
||||
return useTearOffMenus;
|
||||
}
|
||||
int getCardViewInitialRowsMax() const
|
||||
[[nodiscard]] int getCardViewInitialRowsMax() const
|
||||
{
|
||||
return cardViewInitialRowsMax;
|
||||
}
|
||||
int getCardViewExpandedRowsMax() const
|
||||
[[nodiscard]] int getCardViewExpandedRowsMax() const
|
||||
{
|
||||
return cardViewExpandedRowsMax;
|
||||
}
|
||||
bool getCloseEmptyCardView() const
|
||||
[[nodiscard]] bool getCloseEmptyCardView() const
|
||||
{
|
||||
return closeEmptyCardView;
|
||||
}
|
||||
bool getFocusCardViewSearchBar() const
|
||||
[[nodiscard]] bool getFocusCardViewSearchBar() const
|
||||
{
|
||||
return focusCardViewSearchBar;
|
||||
}
|
||||
ShortcutsSettings &shortcuts() const
|
||||
[[nodiscard]] ShortcutsSettings &shortcuts() const
|
||||
{
|
||||
return *shortcutsSettings;
|
||||
}
|
||||
CardDatabaseSettings &cardDatabase() const
|
||||
[[nodiscard]] CardDatabaseSettings *cardDatabase() const
|
||||
{
|
||||
return *cardDatabaseSettings;
|
||||
return cardDatabaseSettings;
|
||||
}
|
||||
ServersSettings &servers() const
|
||||
[[nodiscard]] ServersSettings &servers() const
|
||||
{
|
||||
return *serversSettings;
|
||||
}
|
||||
MessageSettings &messages() const
|
||||
[[nodiscard]] MessageSettings &messages() const
|
||||
{
|
||||
return *messageSettings;
|
||||
}
|
||||
GameFiltersSettings &gameFilters() const
|
||||
[[nodiscard]] GameFiltersSettings &gameFilters() const
|
||||
{
|
||||
return *gameFiltersSettings;
|
||||
}
|
||||
LayoutsSettings &layouts() const
|
||||
[[nodiscard]] LayoutsSettings &layouts() const
|
||||
{
|
||||
return *layoutsSettings;
|
||||
}
|
||||
DownloadSettings &downloads() const
|
||||
[[nodiscard]] DownloadSettings &downloads() const
|
||||
{
|
||||
return *downloadSettings;
|
||||
}
|
||||
RecentsSettings &recents() const
|
||||
[[nodiscard]] RecentsSettings &recents() const
|
||||
{
|
||||
return *recentsSettings;
|
||||
}
|
||||
CardOverrideSettings &cardOverrides() const
|
||||
[[nodiscard]] CardOverrideSettings &cardOverrides() const
|
||||
{
|
||||
return *cardOverrideSettings;
|
||||
}
|
||||
DebugSettings &debug() const
|
||||
[[nodiscard]] DebugSettings &debug() const
|
||||
{
|
||||
return *debugSettings;
|
||||
}
|
||||
CardCounterSettings &cardCounters() const;
|
||||
[[nodiscard]] CardCounterSettings &cardCounters() const;
|
||||
|
||||
bool getIsPortableBuild() const
|
||||
[[nodiscard]] bool getIsPortableBuild() const
|
||||
{
|
||||
return isPortableBuild;
|
||||
}
|
||||
bool getDownloadSpoilersStatus() const
|
||||
[[nodiscard]] bool getDownloadSpoilersStatus() const
|
||||
{
|
||||
return mbDownloadSpoilers;
|
||||
}
|
||||
bool getRoundCardCorners() const
|
||||
[[nodiscard]] bool getRoundCardCorners() const
|
||||
{
|
||||
return roundCardCorners;
|
||||
}
|
||||
@@ -942,6 +993,8 @@ public slots:
|
||||
void setSpoilerDatabasePath(const QString &_spoilerDatabasePath);
|
||||
void setTokenDatabasePath(const QString &_tokenDatabasePath);
|
||||
void setThemeName(const QString &_themeName);
|
||||
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
||||
void setHomeTabBackgroundShuffleFrequency(int _frequency);
|
||||
void setTabVisualDeckStorageOpen(bool value);
|
||||
void setTabServerOpen(bool value);
|
||||
void setTabAccountOpen(bool value);
|
||||
@@ -959,6 +1012,7 @@ public slots:
|
||||
void setDoubleClickToPlay(QT_STATE_CHANGED_T _doubleClickToPlay);
|
||||
void setClickPlaysAllSelected(QT_STATE_CHANGED_T _clickPlaysAllSelected);
|
||||
void setPlayToStack(QT_STATE_CHANGED_T _playToStack);
|
||||
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
||||
void setStartingHandSize(int _startingHandSize);
|
||||
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
||||
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
|
||||
@@ -987,6 +1041,10 @@ public slots:
|
||||
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
|
||||
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
|
||||
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
|
||||
void setVisualDeckEditorCardSize(int _visualDeckEditorCardSize);
|
||||
void setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize);
|
||||
void setEDHRecCardSize(int _EDHRecCardSize);
|
||||
void setArchidektPreviewCardSize(int _archidektPreviewCardSize);
|
||||
void setDefaultDeckEditorType(int value);
|
||||
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
|
||||
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
|
||||
@@ -1032,6 +1090,7 @@ public slots:
|
||||
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
|
||||
void setCreateGameAsSpectator(const bool _createGameAsSpectator);
|
||||
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
||||
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
|
||||
void setRememberGameSettings(const bool _rememberGameSettings);
|
||||
void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
|
||||
void setStartupCardUpdateCheckPromptForUpdate(bool value);
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <QtMath>
|
||||
|
||||
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
|
||||
#define CARD_COUNTER_SETTINGS_H
|
||||
|
||||
#include "settings_manager.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <libcockatrice/settings/settings_manager.h>
|
||||
|
||||
class QSettings;
|
||||
class QColor;
|
||||
@@ -15,9 +19,9 @@ class CardCounterSettings : public SettingsManager
|
||||
public:
|
||||
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:
|
||||
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
|
||||
#define SHORTCUT_TREEVIEW_H
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTreeView>
|
||||
@@ -16,7 +21,7 @@ public:
|
||||
explicit ShortcutFilterProxyModel(QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
[[nodiscard]] bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
};
|
||||
|
||||
class ShortcutTreeView : public QTreeView
|
||||
@@ -115,6 +115,13 @@ ShortcutKey ShortcutsSettings::getShortcut(const QString &name) const
|
||||
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
|
||||
{
|
||||
return getShortcut(name).at(0);
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file shortcuts_settings.h
|
||||
* @ingroup CoreSettings
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef SHORTCUTSSETTINGS_H
|
||||
#define SHORTCUTSSETTINGS_H
|
||||
|
||||
@@ -27,6 +33,7 @@ public:
|
||||
Move_bottom,
|
||||
Gameplay,
|
||||
Drawing,
|
||||
Hand,
|
||||
Chat_room,
|
||||
Game_window,
|
||||
Load_deck,
|
||||
@@ -65,6 +72,8 @@ public:
|
||||
return QApplication::translate("shortcutsTab", "Gameplay");
|
||||
case Drawing:
|
||||
return QApplication::translate("shortcutsTab", "Drawing");
|
||||
case Hand:
|
||||
return QApplication::translate("shortcutsTab", "Hand");
|
||||
case Chat_room:
|
||||
return QApplication::translate("shortcutsTab", "Chat Room");
|
||||
case Game_window:
|
||||
@@ -90,15 +99,15 @@ public:
|
||||
void setSequence(const QList &_sequence)
|
||||
{
|
||||
QList::operator=(_sequence);
|
||||
};
|
||||
QString getName() const
|
||||
}
|
||||
[[nodiscard]] QString getName() const
|
||||
{
|
||||
return QApplication::translate("shortcutsTab", name.toUtf8().data());
|
||||
};
|
||||
QString getGroupName() const
|
||||
}
|
||||
[[nodiscard]] QString getGroupName() const
|
||||
{
|
||||
return ShortcutGroup::getGroupName(group);
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
QString name;
|
||||
@@ -111,24 +120,24 @@ class ShortcutsSettings : public QObject
|
||||
public:
|
||||
explicit ShortcutsSettings(const QString &settingsFilePath, QObject *parent = nullptr);
|
||||
|
||||
ShortcutKey getDefaultShortcut(const QString &name) const;
|
||||
ShortcutKey getShortcut(const QString &name) const;
|
||||
QKeySequence getSingleShortcut(const QString &name) const;
|
||||
QString getDefaultShortcutString(const QString &name) const;
|
||||
QString getShortcutString(const QString &name) const;
|
||||
QString getShortcutFriendlyName(const QString &shortcutName) const;
|
||||
QList<QString> getAllShortcutKeys() const
|
||||
[[nodiscard]] ShortcutKey getDefaultShortcut(const QString &name) const;
|
||||
[[nodiscard]] ShortcutKey getShortcut(const QString &name) const;
|
||||
[[nodiscard]] QKeySequence getSingleShortcut(const QString &name) const;
|
||||
[[nodiscard]] QString getDefaultShortcutString(const QString &name) const;
|
||||
[[nodiscard]] QString getShortcutString(const QString &name) const;
|
||||
[[nodiscard]] QString getShortcutFriendlyName(const QString &shortcutName) const;
|
||||
[[nodiscard]] QList<QString> getAllShortcutKeys() const
|
||||
{
|
||||
return shortCuts.keys();
|
||||
};
|
||||
}
|
||||
|
||||
void setShortcuts(const QString &name, const QList<QKeySequence> &Sequence);
|
||||
void setShortcuts(const QString &name, const QKeySequence &Sequence);
|
||||
void setShortcuts(const QString &name, const QString &sequences);
|
||||
|
||||
bool isKeyAllowed(const QString &name, const QString &sequences) const;
|
||||
bool isValid(const QString &name, const QString &sequences) const;
|
||||
QStringList findOverlaps(const QString &name, const QString &sequences) const;
|
||||
[[nodiscard]] bool isKeyAllowed(const QString &name, const QString &sequences) const;
|
||||
[[nodiscard]] bool isValid(const QString &name, const QString &sequences) const;
|
||||
[[nodiscard]] QStringList findOverlaps(const QString &name, const QString &sequences) const;
|
||||
|
||||
void resetAllShortcuts();
|
||||
void clearAllShortcuts();
|
||||
@@ -143,8 +152,8 @@ private:
|
||||
QString settingsFilePath;
|
||||
QHash<QString, ShortcutKey> shortCuts;
|
||||
|
||||
QString stringifySequence(const QList<QKeySequence> &Sequence) const;
|
||||
QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
|
||||
[[nodiscard]] QString stringifySequence(const QList<QKeySequence> &Sequence) const;
|
||||
[[nodiscard]] QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
|
||||
|
||||
const QHash<QString, ShortcutKey> defaultShortCuts = {
|
||||
{"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..."),
|
||||
parseSequenceString("Ctrl+\\"),
|
||||
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)"),
|
||||
parseSequenceString("Ctrl++;Ctrl+="),
|
||||
ShortcutGroup::Power_Toughness)},
|
||||
@@ -530,6 +543,9 @@ private:
|
||||
{"Player/aSelectColumn", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Column"),
|
||||
parseSequenceString("Ctrl+Shift+C"),
|
||||
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"),
|
||||
parseSequenceString("Ctrl+B"),
|
||||
ShortcutGroup::Move_selected)},
|
||||
@@ -659,6 +675,22 @@ private:
|
||||
{"Player/aAlwaysLookAtTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Look At Top Card"),
|
||||
parseSequenceString("Ctrl+Shift+N"),
|
||||
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"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Gameplay)},
|
||||
@@ -700,6 +732,8 @@ private:
|
||||
ShortcutGroup::Replays)},
|
||||
{"Tabs/aTabDeckEditor",
|
||||
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"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Tabs)},
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "sound_engine.h"
|
||||
|
||||
#include "../settings/cache_settings.h"
|
||||
#include "settings/cache_settings.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QMediaPlayer>
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file sound_engine.h
|
||||
* @ingroup Core
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef 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,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);
|
||||
|
||||
private:
|
||||
QThread *pictureLoaderThread;
|
||||
QNetworkAccessManager *networkManager;
|
||||
bool picDownload, downloadRunning, loadQueueRunning;
|
||||
|
||||
void startNextPicDownload();
|
||||
void picDownloadFailed();
|
||||
QImage tryLoadImageFromReply(QNetworkReply *reply);
|
||||
void concludeImageLoad(const QImage &image);
|
||||
|
||||
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 "../cards/card_database_manager.h"
|
||||
#include "filter_string.h"
|
||||
#include "lib/peglib.h"
|
||||
#include <QFileInfo>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/filters/filter_string.h>
|
||||
#include <libcockatrice/utility/peglib.h>
|
||||
|
||||
static peg::parser search(R"(
|
||||
Start <- QueryPartList
|
||||
@@ -117,8 +118,8 @@ static void setupParserRules()
|
||||
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
||||
int count = 0;
|
||||
deck->deckLoader->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) {
|
||||
auto cardInfoPtr = CardDatabaseManager::getInstance()->getCard(node->getName());
|
||||
deck->deckLoader->getDeckList()->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) {
|
||||
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
||||
count += node->getNumber();
|
||||
}
|
||||
@@ -136,7 +137,7 @@ static void setupParserRules()
|
||||
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto name = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||
return deck->deckLoader->getName().contains(name, Qt::CaseInsensitive);
|
||||
return deck->deckLoader->getDeckList()->getName().contains(name, Qt::CaseInsensitive);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
/**
|
||||
* @file deck_filter_string.h
|
||||
* @ingroup DeckStorageWidgets
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef 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 <QMap>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
|
||||
|
||||
@@ -34,7 +38,7 @@ public:
|
||||
return filter(deck, info);
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
[[nodiscard]] bool valid() const
|
||||
{
|
||||
return _error.isEmpty();
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "filter_builder.h"
|
||||
|
||||
#include "../../deck/custom_line_edit.h"
|
||||
#include "filter_card.h"
|
||||
#include "../interface/widgets/utility/custom_line_edit.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
#include <libcockatrice/filters/filter_card.h>
|
||||
|
||||
FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file filter_builder.h
|
||||
* @ingroup CardDatabaseModelFilters
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef FILTERBUILDER_H
|
||||
#define FILTERBUILDER_H
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#include "filter_tree_model.h"
|
||||
|
||||
#include "filter_card.h"
|
||||
#include "filter_tree.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <libcockatrice/filters/filter_card.h>
|
||||
#include <libcockatrice/filters/filter_tree.h>
|
||||
|
||||
FilterTreeModel::FilterTreeModel(QObject *parent) : QAbstractItemModel(parent)
|
||||
{
|
||||
@@ -1,9 +1,14 @@
|
||||
/**
|
||||
* @file filter_tree_model.h
|
||||
* @ingroup CardDatabaseModelFilters
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef FILTERTREEMODEL_H
|
||||
#define FILTERTREEMODEL_H
|
||||
|
||||
#include "filter_card.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <libcockatrice/filters/filter_card.h>
|
||||
|
||||
class FilterTree;
|
||||
class CardFilter;
|
||||
@@ -19,8 +24,8 @@ public slots:
|
||||
void addFilter(const CardFilter *f);
|
||||
void removeFilter(const CardFilter *f);
|
||||
void clearFiltersOfType(CardFilter::Attr filterType);
|
||||
QList<const CardFilter *> getFiltersOfType(CardFilter::Attr filterType) const;
|
||||
QList<const CardFilter *> allFilters() const;
|
||||
[[nodiscard]] QList<const CardFilter *> getFiltersOfType(CardFilter::Attr filterType) const;
|
||||
[[nodiscard]] QList<const CardFilter *> allFilters() const;
|
||||
|
||||
private slots:
|
||||
void proxyBeginInsertRow(const FilterTreeNode *, int);
|
||||
@@ -29,23 +34,23 @@ private slots:
|
||||
void proxyEndRemoveRow(const FilterTreeNode *, int);
|
||||
|
||||
private:
|
||||
FilterTreeNode *indexToNode(const QModelIndex &idx) const;
|
||||
[[nodiscard]] FilterTreeNode *indexToNode(const QModelIndex &idx) const;
|
||||
QModelIndex nodeIndex(const FilterTreeNode *node, int row, int column) const;
|
||||
|
||||
public:
|
||||
FilterTreeModel(QObject *parent = nullptr);
|
||||
~FilterTreeModel() override;
|
||||
FilterTree *filterTree() const
|
||||
[[nodiscard]] FilterTree *filterTree() const
|
||||
{
|
||||
return fTree;
|
||||
}
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
[[nodiscard]] int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QModelIndex parent(const QModelIndex &ind) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
[[nodiscard]] QModelIndex parent(const QModelIndex &ind) const override;
|
||||
[[nodiscard]] QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
bool removeRows(int row, int count, const QModelIndex &parent) override;
|
||||
void clear();
|
||||
};
|
||||
@@ -22,8 +22,11 @@ static QTextBrowser *createBrowser(const QString &helpFile)
|
||||
QString text = in.readAll();
|
||||
file.close();
|
||||
|
||||
// Poor Markdown Converter
|
||||
// --- Remove @page declarations at the top of the file ---
|
||||
auto opts = QRegularExpression::MultilineOption;
|
||||
text = text.replace(QRegularExpression(R"(^\s*@page[^\n]*\n)", opts), "");
|
||||
|
||||
// Poor Markdown Converter
|
||||
text = text.replace(QRegularExpression("^(###)(.*)", opts), "<h3>\\2</h3>")
|
||||
.replace(QRegularExpression("^(##)(.*)", opts), "<h2>\\2</h2>")
|
||||
.replace(QRegularExpression("^(#)(.*)", opts), "<h1>\\2</h1>")
|
||||
@@ -1,3 +1,10 @@
|
||||
/**
|
||||
* @file syntax_help.h
|
||||
* @ingroup CardDatabaseModelFilters
|
||||
* @ingroup DeckStorageWidgets
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef SEARCH_SYNTAX_HELP_H
|
||||
#define SEARCH_SYNTAX_HELP_H
|
||||
|
||||