mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-14 22:42:14 -07:00
Merge branch 'master' into tooomm-ci_attestations
This commit is contained in:
commit
e56df7b2df
45 changed files with 649 additions and 173 deletions
|
|
@ -7,6 +7,7 @@ RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
|
||||||
git \
|
git \
|
||||||
gtest \
|
gtest \
|
||||||
mariadb-libs \
|
mariadb-libs \
|
||||||
|
ninja \
|
||||||
protobuf \
|
protobuf \
|
||||||
qt6-base \
|
qt6-base \
|
||||||
qt6-imageformats \
|
qt6-imageformats \
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ RUN apt-get update && \
|
||||||
libqt5sql5-mysql \
|
libqt5sql5-mysql \
|
||||||
libqt5svg5-dev \
|
libqt5svg5-dev \
|
||||||
libqt5websockets5-dev \
|
libqt5websockets5-dev \
|
||||||
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt5-image-formats-plugins \
|
qt5-image-formats-plugins \
|
||||||
qtmultimedia5-dev \
|
qtmultimedia5-dev \
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,14 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
qt6-svg-dev \
|
ninja-build \
|
||||||
qt6-websockets-dev \
|
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
qt6-l10n-tools \
|
qt6-l10n-tools \
|
||||||
qt6-multimedia-dev \
|
qt6-multimedia-dev \
|
||||||
|
qt6-svg-dev \
|
||||||
qt6-tools-dev \
|
qt6-tools-dev \
|
||||||
qt6-tools-dev-tools \
|
qt6-tools-dev-tools \
|
||||||
|
qt6-websockets-dev \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ RUN dnf install -y \
|
||||||
gcc-c++ \
|
gcc-c++ \
|
||||||
git \
|
git \
|
||||||
mariadb-devel \
|
mariadb-devel \
|
||||||
|
ninja-build \
|
||||||
protobuf-devel \
|
protobuf-devel \
|
||||||
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||||
qt6-qtimageformats \
|
qt6-qtimageformats \
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ RUN dnf install -y \
|
||||||
gcc-c++ \
|
gcc-c++ \
|
||||||
git \
|
git \
|
||||||
mariadb-devel \
|
mariadb-devel \
|
||||||
|
ninja-build \
|
||||||
protobuf-devel \
|
protobuf-devel \
|
||||||
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||||
qt6-qtimageformats \
|
qt6-qtimageformats \
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
||||||
build-essential \
|
|
||||||
ccache \
|
|
||||||
clang-format \
|
|
||||||
cmake \
|
|
||||||
file \
|
|
||||||
g++ \
|
|
||||||
git \
|
|
||||||
liblzma-dev \
|
|
||||||
libmariadb-dev-compat \
|
|
||||||
libprotobuf-dev \
|
|
||||||
libqt5multimedia5-plugins \
|
|
||||||
libqt5sql5-mysql \
|
|
||||||
libqt5svg5-dev \
|
|
||||||
libqt5websockets5-dev \
|
|
||||||
protobuf-compiler \
|
|
||||||
qt5-default \
|
|
||||||
qt5-image-formats-plugins \
|
|
||||||
qtmultimedia5-dev \
|
|
||||||
qttools5-dev \
|
|
||||||
qttools5-dev-tools \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
@ -17,6 +17,7 @@ RUN apt-get update && \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
libqt6svg6-dev \
|
libqt6svg6-dev \
|
||||||
libqt6websockets6-dev \
|
libqt6websockets6-dev \
|
||||||
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
qt6-l10n-tools \
|
qt6-l10n-tools \
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,14 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
qt6-svg-dev \
|
ninja-build \
|
||||||
qt6-websockets-dev \
|
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
qt6-l10n-tools \
|
qt6-l10n-tools \
|
||||||
qt6-multimedia-dev \
|
qt6-multimedia-dev \
|
||||||
|
qt6-svg-dev \
|
||||||
qt6-tools-dev \
|
qt6-tools-dev \
|
||||||
qt6-tools-dev-tools \
|
qt6-tools-dev-tools \
|
||||||
|
qt6-websockets-dev \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,8 @@
|
||||||
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
||||||
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
||||||
# --dir <dir> sets the name of the build dir, default is "build"
|
# --dir <dir> sets the name of the build dir, default is "build"
|
||||||
# --parallel <core count> sets how many cores cmake should build with in parallel
|
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR CMAKE_GENERATOR
|
||||||
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR PARALLEL_COUNT
|
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir>)
|
||||||
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir> --parallel <core_count>)
|
|
||||||
# exitcode: 1 for failure, 3 for invalid arguments
|
# exitcode: 1 for failure, 3 for invalid arguments
|
||||||
|
|
||||||
# Read arguments
|
# Read arguments
|
||||||
|
|
@ -76,15 +75,6 @@ while [[ $# != 0 ]]; do
|
||||||
BUILD_DIR="$1"
|
BUILD_DIR="$1"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
'--parallel')
|
|
||||||
shift
|
|
||||||
if [[ $# == 0 ]]; then
|
|
||||||
echo "::error file=$0::--parallel expects an argument"
|
|
||||||
exit 3
|
|
||||||
fi
|
|
||||||
PARALLEL_COUNT="$1"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "::error file=$0::unrecognized option: $1"
|
echo "::error file=$0::unrecognized option: $1"
|
||||||
exit 3
|
exit 3
|
||||||
|
|
@ -126,16 +116,6 @@ fi
|
||||||
|
|
||||||
# Add cmake --build flags
|
# Add cmake --build flags
|
||||||
buildflags=(--config "$BUILDTYPE")
|
buildflags=(--config "$BUILDTYPE")
|
||||||
if [[ $PARALLEL_COUNT ]]; then
|
|
||||||
if [[ $(cmake --build /not_a_dir --parallel 2>&1 | head -1) =~ parallel ]]; then
|
|
||||||
# workaround for bionic having an old cmake
|
|
||||||
echo "this version of cmake does not support --parallel, using native build tool -j instead"
|
|
||||||
buildflags+=(-- -j "$PARALLEL_COUNT")
|
|
||||||
# note, no normal build flags should be added after this
|
|
||||||
else
|
|
||||||
buildflags+=(--parallel "$PARALLEL_COUNT")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
function ccachestatsverbose() {
|
function ccachestatsverbose() {
|
||||||
# note, verbose only works on newer ccache, discard the error
|
# note, verbose only works on newer ccache, discard the error
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,9 @@ function RUN ()
|
||||||
args+=(--mount "type=bind,source=$CCACHE_DIR,target=/.ccache")
|
args+=(--mount "type=bind,source=$CCACHE_DIR,target=/.ccache")
|
||||||
args+=(--env "CCACHE_DIR=/.ccache")
|
args+=(--env "CCACHE_DIR=/.ccache")
|
||||||
fi
|
fi
|
||||||
|
if [[ -n "$CMAKE_GENERATOR" ]]; then
|
||||||
|
args+=(--env "CMAKE_GENERATOR=$CMAKE_GENERATOR")
|
||||||
|
fi
|
||||||
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
||||||
return $?
|
return $?
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ Available pre-compiled binaries for installation:
|
||||||
<b>Linux</b>
|
<b>Linux</b>
|
||||||
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
||||||
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
|
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
|
||||||
• <kbd>Ubuntu 20.04 LTS</kbd> <sub><i>Focal Fossa</i></sub>
|
|
||||||
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
||||||
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
|
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
|
||||||
• <kbd>Fedora 42</kbd>
|
• <kbd>Fedora 42</kbd>
|
||||||
|
|
|
||||||
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -9,14 +9,24 @@ assignees: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- READ THIS BEFORE POSTING
|
<!-- READ THIS BEFORE POSTING
|
||||||
Go to "Help → View Debug Log" in Cockatrice and copy all information at the
|
In Cockatrice, go to "Help" → "View Debug Log" and copy all information displayed at the
|
||||||
top (above the separation line) below "System Information" in this ticket!
|
top (above the separation line "----"), to below "System Information" section in this ticket!
|
||||||
If you can't start Cockatrice to access these details, make
|
If you can't start Cockatrice to access these details, make
|
||||||
sure to post your OS and the file name of the setup binary instead. -->
|
sure to post your OS and the file name of the setup binary instead.
|
||||||
|
-->
|
||||||
|
|
||||||
**System Information:**
|
**System Information:**
|
||||||
|
<!-- Read the hint above on where to find the important information to provide here! -->
|
||||||
|
|
||||||
|
|
||||||
|
<details><summary>Debug Log:</summary>
|
||||||
|
<!--
|
||||||
|
In Cockatrice, go to "Help" → "View Debug Log", click the "Copy to clickboard" button and paste the output here.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
_______________________________________________________________________________________
|
_______________________________________________________________________________________
|
||||||
|
|
||||||
<!-- Explain your issue in detail here! Please attach screenshots if possible. -->
|
<!-- Explain your issue in detail here! Please attach screenshots if possible. -->
|
||||||
|
|
@ -26,7 +36,7 @@ ________________________________________________________________________________
|
||||||
|
|
||||||
_______________________________________________________________________________________
|
_______________________________________________________________________________________
|
||||||
|
|
||||||
<!-- Describe the sequence of actions needed to experience the bug -->
|
<!-- Describe the sequence of actions needed to experience the bug. -->
|
||||||
|
|
||||||
**Steps to reproduce:**
|
**Steps to reproduce:**
|
||||||
- Do A
|
- Do A
|
||||||
|
|
|
||||||
99
.github/workflows/desktop-build.yml
vendored
99
.github/workflows/desktop-build.yml
vendored
|
|
@ -110,11 +110,6 @@ jobs:
|
||||||
version: 42
|
version: 42
|
||||||
package: RPM
|
package: RPM
|
||||||
|
|
||||||
- distro: Ubuntu
|
|
||||||
version: 20.04
|
|
||||||
package: DEB
|
|
||||||
test: skip # Ubuntu 20.04 has a broken Qt for debug builds
|
|
||||||
|
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 22.04
|
version: 22.04
|
||||||
package: DEB
|
package: DEB
|
||||||
|
|
@ -130,29 +125,25 @@ jobs:
|
||||||
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
||||||
env:
|
env:
|
||||||
NAME: ${{matrix.distro}}${{matrix.version}}
|
NAME: ${{matrix.distro}}${{matrix.version}}
|
||||||
CACHE: /tmp/${{matrix.distro}}${{matrix.version}}-cache # ${{runner.temp}} does not work?
|
CACHE: ${{github.workspace}}/.cache/${{matrix.distro}}${{matrix.version}} # directory for caching docker image and ccache
|
||||||
# Cache size over the entire repo is 10Gi:
|
# Cache size over the entire repo is 10Gi:
|
||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||||
CCACHE_SIZE: 500M
|
CCACHE_SIZE: 500M
|
||||||
|
CMAKE_GENERATOR: 'Ninja'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Generate cache timestamp
|
- name: Restore compiler cache (ccache)
|
||||||
id: cache_timestamp
|
id: ccache_restore
|
||||||
shell: bash
|
uses: actions/cache/restore@v4
|
||||||
run: echo "timestamp=$(date -u '+%Y%m%d%H%M%S')" >>"$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Restore cache
|
|
||||||
uses: actions/cache@v4
|
|
||||||
env:
|
env:
|
||||||
timestamp: ${{steps.cache_timestamp.outputs.timestamp}}
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
with:
|
with:
|
||||||
path: ${{env.CACHE}}
|
path: ${{env.CACHE}}
|
||||||
key: docker-${{matrix.distro}}${{matrix.version}}-cache-${{env.timestamp}}
|
key: ccache-${{matrix.distro}}${{matrix.version}}-${{env.BRANCH_NAME}}
|
||||||
restore-keys: |
|
restore-keys: ccache-${{matrix.distro}}${{matrix.version}}-
|
||||||
docker-${{matrix.distro}}${{matrix.version}}-cache-
|
|
||||||
|
|
||||||
- name: Build ${{matrix.distro}} ${{matrix.version}} Docker image
|
- name: Build ${{matrix.distro}} ${{matrix.version}} Docker image
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
@ -161,9 +152,11 @@ jobs:
|
||||||
- name: Build debug and test
|
- name: Build debug and test
|
||||||
if: matrix.test != 'skip'
|
if: matrix.test != 'skip'
|
||||||
shell: bash
|
shell: bash
|
||||||
|
env:
|
||||||
|
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||||
run: |
|
run: |
|
||||||
source .ci/docker.sh
|
source .ci/docker.sh
|
||||||
RUN --server --debug --test --ccache "$CCACHE_SIZE" --parallel 4
|
RUN --server --debug --test --ccache "$CCACHE_SIZE"
|
||||||
|
|
||||||
- name: Build release package
|
- name: Build release package
|
||||||
id: build
|
id: build
|
||||||
|
|
@ -172,13 +165,21 @@ jobs:
|
||||||
env:
|
env:
|
||||||
BUILD_DIR: build
|
BUILD_DIR: build
|
||||||
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
||||||
type: '${{matrix.package}}'
|
package: '${{matrix.package}}'
|
||||||
|
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||||
run: |
|
run: |
|
||||||
source .ci/docker.sh
|
source .ci/docker.sh
|
||||||
RUN --server --release --package "$type" --dir "$BUILD_DIR" \
|
RUN --server --release --package "$package" --dir "$BUILD_DIR" \
|
||||||
--ccache "$CCACHE_SIZE" --parallel 4
|
--ccache "$CCACHE_SIZE"
|
||||||
.ci/name_build.sh
|
.ci/name_build.sh
|
||||||
|
|
||||||
|
- name: Save compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
with:
|
||||||
|
path: ${{env.CACHE}}
|
||||||
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
id: upload_artifact
|
id: upload_artifact
|
||||||
if: matrix.package != 'skip'
|
if: matrix.package != 'skip'
|
||||||
|
|
@ -223,7 +224,6 @@ jobs:
|
||||||
os: macos-13
|
os: macos-13
|
||||||
xcode: "14.3.1"
|
xcode: "14.3.1"
|
||||||
type: Release
|
type: Release
|
||||||
core_count: 4
|
|
||||||
make_package: 1
|
make_package: 1
|
||||||
|
|
||||||
- target: 14
|
- target: 14
|
||||||
|
|
@ -231,7 +231,6 @@ jobs:
|
||||||
os: macos-14
|
os: macos-14
|
||||||
xcode: "15.4"
|
xcode: "15.4"
|
||||||
type: Release
|
type: Release
|
||||||
core_count: 3
|
|
||||||
make_package: 1
|
make_package: 1
|
||||||
|
|
||||||
- target: 15
|
- target: 15
|
||||||
|
|
@ -239,7 +238,6 @@ jobs:
|
||||||
os: macos-15
|
os: macos-15
|
||||||
xcode: "16.2"
|
xcode: "16.2"
|
||||||
type: Release
|
type: Release
|
||||||
core_count: 3
|
|
||||||
make_package: 1
|
make_package: 1
|
||||||
|
|
||||||
- target: 15
|
- target: 15
|
||||||
|
|
@ -247,15 +245,17 @@ jobs:
|
||||||
os: macos-15
|
os: macos-15
|
||||||
xcode: "16.2"
|
xcode: "16.2"
|
||||||
type: Debug
|
type: Debug
|
||||||
core_count: 3
|
|
||||||
|
|
||||||
name: macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
name: macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||||
needs: configure
|
needs: configure
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
||||||
env:
|
env:
|
||||||
|
CCACHE_DIR: ${{github.workspace}}/.ccache/${{matrix.os}}-${{matrix.type}}
|
||||||
|
CCACHE_SIZE: 500M
|
||||||
DEVELOPER_DIR:
|
DEVELOPER_DIR:
|
||||||
/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer
|
/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer
|
||||||
|
CMAKE_GENERATOR: 'Ninja'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
@ -269,23 +269,30 @@ jobs:
|
||||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||||
run: |
|
run: |
|
||||||
brew update
|
brew update
|
||||||
brew install protobuf qt --force-bottle
|
brew install ccache protobuf qt --force-bottle
|
||||||
|
|
||||||
|
- name: Restore compiler cache (ccache)
|
||||||
|
id: ccache_restore
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
|
with:
|
||||||
|
path: ${{env.CCACHE_DIR}}
|
||||||
|
key: ccache-${{matrix.os}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
||||||
|
restore-keys: ccache-${{matrix.os}}-${{matrix.type}}-
|
||||||
|
|
||||||
- name: Build & Sign on Xcode ${{matrix.xcode}}
|
- name: Build & Sign on Xcode ${{matrix.xcode}}
|
||||||
shell: bash
|
shell: bash
|
||||||
id: build
|
id: build
|
||||||
env:
|
env:
|
||||||
BUILDTYPE: '${{matrix.type}}'
|
BUILDTYPE: '${{matrix.type}}'
|
||||||
MAKE_TEST: 1
|
|
||||||
MAKE_PACKAGE: '${{matrix.make_package}}'
|
MAKE_PACKAGE: '${{matrix.make_package}}'
|
||||||
PACKAGE_SUFFIX: '-macOS${{matrix.target}}_${{matrix.soc}}'
|
PACKAGE_SUFFIX: '-macOS${{matrix.target}}_${{matrix.soc}}'
|
||||||
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
||||||
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
||||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
# macOS runner have 3 cores usually - only the macos-13 image has 4:
|
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||||
# https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
|
|
||||||
# https://github.com/actions/runner-images?tab=readme-ov-file#available-images
|
|
||||||
run: |
|
run: |
|
||||||
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
|
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
|
||||||
then
|
then
|
||||||
|
|
@ -297,10 +304,17 @@ jobs:
|
||||||
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
||||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||||
fi
|
fi
|
||||||
.ci/compile.sh --server --parallel ${{matrix.core_count}}
|
.ci/compile.sh --server --test --ccache "$CCACHE_SIZE"
|
||||||
|
|
||||||
|
- name: Save compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
with:
|
||||||
|
path: ${{env.CCACHE_DIR}}
|
||||||
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
|
||||||
- name: Sign app bundle
|
- name: Sign app bundle
|
||||||
if: matrix.make_package
|
if: matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||||
env:
|
env:
|
||||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
|
|
@ -312,7 +326,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Notarize app bundle
|
- name: Notarize app bundle
|
||||||
if: matrix.make_package
|
if: matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||||
env:
|
env:
|
||||||
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
||||||
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
||||||
|
|
@ -354,7 +368,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload to release
|
- name: Upload to release
|
||||||
id: upload_release
|
id: upload_release
|
||||||
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
|
if: matrix.make_package && needs.configure.outputs.tag != null
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
|
|
@ -419,16 +433,11 @@ jobs:
|
||||||
tools: ${{matrix.qt_tools}}
|
tools: ${{matrix.qt_tools}}
|
||||||
modules: ${{matrix.qt_modules}}
|
modules: ${{matrix.qt_modules}}
|
||||||
|
|
||||||
# TODO: re-enable when https://github.com/lukka/run-vcpkg/issues/243 is fixed
|
- name: Setup vcpkg cache
|
||||||
- if: false
|
id: vcpkg-cache
|
||||||
name: Run vcpkg (disabled)
|
uses: TAServers/vcpkg-cache@v3
|
||||||
uses: lukka/run-vcpkg@v11
|
|
||||||
with:
|
with:
|
||||||
runVcpkgInstall: true
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
doNotCache: false
|
|
||||||
env:
|
|
||||||
VCPKG_DEFAULT_TRIPLET: 'x64-windows'
|
|
||||||
VCPKG_DISABLE_METRICS: 1
|
|
||||||
|
|
||||||
- name: Build Cockatrice
|
- name: Build Cockatrice
|
||||||
id: build
|
id: build
|
||||||
|
|
@ -438,6 +447,8 @@ jobs:
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||||
CMAKE_GENERATOR_PLATFORM: 'x64'
|
CMAKE_GENERATOR_PLATFORM: 'x64'
|
||||||
QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win64_${{matrix.qt_arch}}'
|
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,
|
# 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/
|
# project and process parallelism: https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
|
||||||
run: .ci/compile.sh --server --release --test --package
|
run: .ci/compile.sh --server --release --test --package
|
||||||
|
|
@ -461,7 +472,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload to release
|
- name: Upload to release
|
||||||
id: upload_release
|
id: upload_release
|
||||||
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
|
if: needs.configure.outputs.tag != null
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{github.token}}
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,7 @@ set(cockatrice_SOURCES
|
||||||
src/game/cards/card_search_model.cpp
|
src/game/cards/card_search_model.cpp
|
||||||
src/game/deckview/deck_view.cpp
|
src/game/deckview/deck_view.cpp
|
||||||
src/game/deckview/deck_view_container.cpp
|
src/game/deckview/deck_view_container.cpp
|
||||||
|
src/game/filters/deck_filter_string.cpp
|
||||||
src/game/filters/filter_builder.cpp
|
src/game/filters/filter_builder.cpp
|
||||||
src/game/filters/filter_card.cpp
|
src/game/filters/filter_card.cpp
|
||||||
src/game/filters/filter_string.cpp
|
src/game/filters/filter_string.cpp
|
||||||
|
|
|
||||||
|
|
@ -379,5 +379,6 @@
|
||||||
<file>resources/tips/tips_of_the_day.xml</file>
|
<file>resources/tips/tips_of_the_day.xml</file>
|
||||||
|
|
||||||
<file>resources/help/search.md</file>
|
<file>resources/help/search.md</file>
|
||||||
|
<file>resources/help/deck_search.md</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
||||||
|
|
@ -60,4 +60,6 @@
|
||||||
|
|
||||||
# pixel_map_generator = false
|
# pixel_map_generator = false
|
||||||
|
|
||||||
|
# deck_filter_string = false
|
||||||
# filter_string = false
|
# filter_string = false
|
||||||
|
# syntax_help = false
|
||||||
|
|
|
||||||
26
cockatrice/resources/help/deck_search.md
Normal file
26
cockatrice/resources/help/deck_search.md
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
## Deck Search Syntax Help
|
||||||
|
-----
|
||||||
|
The search bar recognizes a set of special commands.<br>
|
||||||
|
In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all
|
||||||
|
searches are case insensitive.
|
||||||
|
<dl>
|
||||||
|
<dt>Filename:</dt>
|
||||||
|
<dd>[red deck wins](#red deck wins) <small>(Any deck filename containing the words red, deck, and wins)</small></dd>
|
||||||
|
<dd>["red deck wins"](#%22red deck wins%22) <small>(Any deck filename containing the exact phrase "red deck wins")</small></dd>
|
||||||
|
|
||||||
|
<dt>Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):</dt>
|
||||||
|
<dd><a href="#[[plains]]">[[plains]]</a> <small>(Any deck that contains at least one card with "plains" in its name)</small></dd>
|
||||||
|
<dd><a href="#[[t:legendary]]">[[t:legendary]]</a> <small>(Any deck that contains at least one legendary)</small></dd>
|
||||||
|
<dd><a href="#[[t:legendary]]>5">[[t:legendary]]>5</a> <small>(Any card that contains at least 5 legendaries)</small></dd>
|
||||||
|
<dd><a href="#[[]]:100">[[]]:100</a> <small>(Any deck that contains exactly 100 cards)</small></dd>
|
||||||
|
|
||||||
|
<dt>Negate:</dt>
|
||||||
|
<dd>[soldier -aggro](#soldier -aggro) <small>(Any deck filename that contains "soldier", but not "aggro")</small></dd>
|
||||||
|
|
||||||
|
<dt>Branching:</dt>
|
||||||
|
<dd>[t:aggro OR o:control](#t:aggro OR o:control) <small>(Any deck filename that contains either aggro or control)</small></dd>
|
||||||
|
|
||||||
|
<dt>Grouping:</dt>
|
||||||
|
<dd><a href="#red -([[]]:100 or aggro)">red -([[]]:100 or aggro)</a> <small>(Any deck that has red in its filename but is not 100 cards or has aggro in its filename)</small></dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
@ -1538,7 +1538,7 @@ void TabGame::createPlayAreaWidget(bool bReplay)
|
||||||
scene = new GameScene(phasesToolbar, this);
|
scene = new GameScene(phasesToolbar, this);
|
||||||
gameView = new GameView(scene);
|
gameView = new GameView(scene);
|
||||||
|
|
||||||
gamePlayAreaVBox = new QVBoxLayout;
|
auto gamePlayAreaVBox = new QVBoxLayout;
|
||||||
gamePlayAreaVBox->setContentsMargins(0, 0, 0, 0);
|
gamePlayAreaVBox->setContentsMargins(0, 0, 0, 0);
|
||||||
gamePlayAreaVBox->addWidget(gameView);
|
gamePlayAreaVBox->addWidget(gameView);
|
||||||
|
|
||||||
|
|
@ -1594,12 +1594,12 @@ void TabGame::createReplayDock()
|
||||||
connect(replayFastForwardButton, &QToolButton::toggled, this, &TabGame::replayFastForwardButtonToggled);
|
connect(replayFastForwardButton, &QToolButton::toggled, this, &TabGame::replayFastForwardButtonToggled);
|
||||||
|
|
||||||
// putting everything together
|
// putting everything together
|
||||||
replayControlLayout = new QHBoxLayout;
|
auto replayControlLayout = new QHBoxLayout;
|
||||||
replayControlLayout->addWidget(timelineWidget, 10);
|
replayControlLayout->addWidget(timelineWidget, 10);
|
||||||
replayControlLayout->addWidget(replayPlayButton);
|
replayControlLayout->addWidget(replayPlayButton);
|
||||||
replayControlLayout->addWidget(replayFastForwardButton);
|
replayControlLayout->addWidget(replayFastForwardButton);
|
||||||
|
|
||||||
replayControlWidget = new QWidget();
|
auto replayControlWidget = new QWidget();
|
||||||
replayControlWidget->setObjectName("replayControlWidget");
|
replayControlWidget->setObjectName("replayControlWidget");
|
||||||
replayControlWidget->setLayout(replayControlLayout);
|
replayControlWidget->setLayout(replayControlLayout);
|
||||||
|
|
||||||
|
|
@ -1635,13 +1635,13 @@ void TabGame::createCardInfoDock(bool bReplay)
|
||||||
Q_UNUSED(bReplay);
|
Q_UNUSED(bReplay);
|
||||||
|
|
||||||
cardInfoFrameWidget = new CardInfoFrameWidget();
|
cardInfoFrameWidget = new CardInfoFrameWidget();
|
||||||
cardHInfoLayout = new QHBoxLayout;
|
auto cardHInfoLayout = new QHBoxLayout;
|
||||||
cardVInfoLayout = new QVBoxLayout;
|
auto cardVInfoLayout = new QVBoxLayout;
|
||||||
cardVInfoLayout->setContentsMargins(0, 0, 0, 0);
|
cardVInfoLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
cardVInfoLayout->addWidget(cardInfoFrameWidget);
|
cardVInfoLayout->addWidget(cardInfoFrameWidget);
|
||||||
cardVInfoLayout->addLayout(cardHInfoLayout);
|
cardVInfoLayout->addLayout(cardHInfoLayout);
|
||||||
|
|
||||||
cardBoxLayoutWidget = new QWidget;
|
auto cardBoxLayoutWidget = new QWidget;
|
||||||
cardBoxLayoutWidget->setLayout(cardVInfoLayout);
|
cardBoxLayoutWidget->setLayout(cardVInfoLayout);
|
||||||
|
|
||||||
cardInfoDock = new QDockWidget(this);
|
cardInfoDock = new QDockWidget(this);
|
||||||
|
|
@ -1679,6 +1679,22 @@ void TabGame::createPlayerListDock(bool bReplay)
|
||||||
|
|
||||||
void TabGame::createMessageDock(bool bReplay)
|
void TabGame::createMessageDock(bool bReplay)
|
||||||
{
|
{
|
||||||
|
auto messageLogLayout = new QVBoxLayout;
|
||||||
|
messageLogLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
// clock
|
||||||
|
if (!bReplay) {
|
||||||
|
timeElapsedLabel = new QLabel;
|
||||||
|
timeElapsedLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
gameTimer = new QTimer(this);
|
||||||
|
gameTimer->setInterval(1000);
|
||||||
|
connect(gameTimer, &QTimer::timeout, this, &TabGame::incrementGameTime);
|
||||||
|
gameTimer->start();
|
||||||
|
|
||||||
|
messageLogLayout->addWidget(timeElapsedLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// message log
|
||||||
messageLog = new MessageLogWidget(tabSupervisor, this);
|
messageLog = new MessageLogWidget(tabSupervisor, this);
|
||||||
connect(messageLog, &MessageLogWidget::cardNameHovered, cardInfoFrameWidget,
|
connect(messageLog, &MessageLogWidget::cardNameHovered, cardInfoFrameWidget,
|
||||||
qOverload<const QString &>(&CardInfoFrameWidget::setCard));
|
qOverload<const QString &>(&CardInfoFrameWidget::setCard));
|
||||||
|
|
@ -1690,14 +1706,12 @@ void TabGame::createMessageDock(bool bReplay)
|
||||||
connect(messageLog, &MessageLogWidget::addMentionTag, this, &TabGame::addMentionTag);
|
connect(messageLog, &MessageLogWidget::addMentionTag, this, &TabGame::addMentionTag);
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::chatMentionCompleterChanged, this,
|
connect(&SettingsCache::instance(), &SettingsCache::chatMentionCompleterChanged, this,
|
||||||
&TabGame::actCompleterChanged);
|
&TabGame::actCompleterChanged);
|
||||||
|
}
|
||||||
|
|
||||||
timeElapsedLabel = new QLabel;
|
messageLogLayout->addWidget(messageLog);
|
||||||
timeElapsedLabel->setAlignment(Qt::AlignCenter);
|
|
||||||
gameTimer = new QTimer(this);
|
|
||||||
gameTimer->setInterval(1000);
|
|
||||||
connect(gameTimer, &QTimer::timeout, this, &TabGame::incrementGameTime);
|
|
||||||
gameTimer->start();
|
|
||||||
|
|
||||||
|
// chat entry
|
||||||
|
if (!bReplay) {
|
||||||
sayLabel = new QLabel;
|
sayLabel = new QLabel;
|
||||||
sayEdit = new LineEditCompleter;
|
sayEdit = new LineEditCompleter;
|
||||||
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
|
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
|
||||||
|
|
@ -1726,20 +1740,15 @@ void TabGame::createMessageDock(bool bReplay)
|
||||||
connect(tabSupervisor, &TabSupervisor::adminLockChanged, this, &TabGame::adminLockChanged);
|
connect(tabSupervisor, &TabSupervisor::adminLockChanged, this, &TabGame::adminLockChanged);
|
||||||
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabGame::actSay);
|
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabGame::actSay);
|
||||||
|
|
||||||
sayHLayout = new QHBoxLayout;
|
auto sayHLayout = new QHBoxLayout;
|
||||||
sayHLayout->addWidget(sayLabel);
|
sayHLayout->addWidget(sayLabel);
|
||||||
sayHLayout->addWidget(sayEdit);
|
sayHLayout->addWidget(sayEdit);
|
||||||
|
|
||||||
|
messageLogLayout->addLayout(sayHLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
messageLogLayout = new QVBoxLayout;
|
// dock
|
||||||
messageLogLayout->setContentsMargins(0, 0, 0, 0);
|
auto messageLogLayoutWidget = new QWidget;
|
||||||
if (!bReplay)
|
|
||||||
messageLogLayout->addWidget(timeElapsedLabel);
|
|
||||||
messageLogLayout->addWidget(messageLog);
|
|
||||||
if (!bReplay)
|
|
||||||
messageLogLayout->addLayout(sayHLayout);
|
|
||||||
|
|
||||||
messageLogLayoutWidget = new QWidget;
|
|
||||||
messageLogLayoutWidget->setLayout(messageLogLayout);
|
messageLogLayoutWidget->setLayout(messageLogLayout);
|
||||||
|
|
||||||
messageLayoutDock = new QDockWidget(this);
|
messageLayoutDock = new QDockWidget(this);
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,8 @@ private:
|
||||||
GameScene *scene;
|
GameScene *scene;
|
||||||
GameView *gameView;
|
GameView *gameView;
|
||||||
QMap<int, DeckViewContainer *> deckViewContainers;
|
QMap<int, DeckViewContainer *> deckViewContainers;
|
||||||
QVBoxLayout *cardVInfoLayout, *messageLogLayout, *gamePlayAreaVBox, *deckViewContainerLayout;
|
QVBoxLayout *deckViewContainerLayout;
|
||||||
QHBoxLayout *cardHInfoLayout, *sayHLayout, *mainHLayout, *replayControlLayout;
|
QWidget *gamePlayAreaWidget, *deckViewContainerWidget;
|
||||||
QWidget *cardBoxLayoutWidget, *messageLogLayoutWidget, *gamePlayAreaWidget, *deckViewContainerWidget,
|
|
||||||
*replayControlWidget;
|
|
||||||
QDockWidget *cardInfoDock, *messageLayoutDock, *playerListDock, *replayDock;
|
QDockWidget *cardInfoDock, *messageLayoutDock, *playerListDock, *replayDock;
|
||||||
QAction *playersSeparator;
|
QAction *playersSeparator;
|
||||||
QMenu *gameMenu, *viewMenu, *cardInfoDockMenu, *messageLayoutDockMenu, *playerListDockMenu, *replayDockMenu;
|
QMenu *gameMenu, *viewMenu, *cardInfoDockMenu, *messageLayoutDockMenu, *playerListDockMenu, *replayDockMenu;
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,20 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckModel->getDeckList());
|
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckModel->getDeckList());
|
||||||
deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible());
|
deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible());
|
||||||
|
|
||||||
|
activeGroupCriteriaLabel = new QLabel(this);
|
||||||
|
|
||||||
|
activeGroupCriteriaComboBox = new QComboBox(this);
|
||||||
|
activeGroupCriteriaComboBox->addItem(tr("Main Type"), DeckListModelGroupCriteria::MAIN_TYPE);
|
||||||
|
activeGroupCriteriaComboBox->addItem(tr("Mana Cost"), DeckListModelGroupCriteria::MANA_COST);
|
||||||
|
activeGroupCriteriaComboBox->addItem(tr("Colors"), DeckListModelGroupCriteria::COLOR);
|
||||||
|
connect(activeGroupCriteriaComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() {
|
||||||
|
deckModel->setActiveGroupCriteria(
|
||||||
|
static_cast<DeckListModelGroupCriteria>(activeGroupCriteriaComboBox->currentData(Qt::UserRole).toInt()));
|
||||||
|
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||||
|
deckView->expandAll();
|
||||||
|
deckView->expandAll();
|
||||||
|
});
|
||||||
|
|
||||||
aIncrement = new QAction(QString(), this);
|
aIncrement = new QAction(QString(), this);
|
||||||
aIncrement->setIcon(QPixmap("theme:icons/increment"));
|
aIncrement->setIcon(QPixmap("theme:icons/increment"));
|
||||||
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrement);
|
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrement);
|
||||||
|
|
@ -144,6 +158,9 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
|
|
||||||
upperLayout->addWidget(deckTagsDisplayWidget, 3, 1);
|
upperLayout->addWidget(deckTagsDisplayWidget, 3, 1);
|
||||||
|
|
||||||
|
upperLayout->addWidget(activeGroupCriteriaLabel, 4, 0);
|
||||||
|
upperLayout->addWidget(activeGroupCriteriaComboBox, 4, 1);
|
||||||
|
|
||||||
hashLabel1 = new QLabel();
|
hashLabel1 = new QLabel();
|
||||||
hashLabel1->setObjectName("hashLabel1");
|
hashLabel1->setObjectName("hashLabel1");
|
||||||
auto *hashSizePolicy = new QSizePolicy();
|
auto *hashSizePolicy = new QSizePolicy();
|
||||||
|
|
@ -286,11 +303,7 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const auto &pair : pairList) {
|
for (const auto &pair : pairList) {
|
||||||
QVariantMap dataMap;
|
bannerCardComboBox->addItem(pair.first, QVariant::fromValue(pair));
|
||||||
dataMap["name"] = pair.first;
|
|
||||||
dataMap["uuid"] = pair.second;
|
|
||||||
|
|
||||||
bannerCardComboBox->addItem(pair.first, dataMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to restore the previous selection by finding the currentText
|
// Try to restore the previous selection by finding the currentText
|
||||||
|
|
@ -298,7 +311,7 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
if (restoredIndex != -1) {
|
if (restoredIndex != -1) {
|
||||||
bannerCardComboBox->setCurrentIndex(restoredIndex);
|
bannerCardComboBox->setCurrentIndex(restoredIndex);
|
||||||
if (deckModel->getDeckList()->getBannerCard().second !=
|
if (deckModel->getDeckList()->getBannerCard().second !=
|
||||||
bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap()["uuid"].toString()) {
|
bannerCardComboBox->currentData().value<QPair<QString, QString>>().second) {
|
||||||
setBannerCard(restoredIndex);
|
setBannerCard(restoredIndex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -318,9 +331,8 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
|
void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
|
||||||
{
|
{
|
||||||
QVariantMap itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
|
auto cardAndId = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
||||||
deckModel->getDeckList()->setBannerCard(
|
deckModel->getDeckList()->setBannerCard(cardAndId);
|
||||||
QPair<QString, QString>(itemData["name"].toString(), itemData["uuid"].toString()));
|
|
||||||
emit deckModified();
|
emit deckModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -578,6 +590,7 @@ void DeckEditorDeckDockWidget::retranslateUi()
|
||||||
showBannerCardCheckBox->setText(tr("Show banner card selection menu"));
|
showBannerCardCheckBox->setText(tr("Show banner card selection menu"));
|
||||||
showTagsWidgetCheckBox->setText(tr("Show tags selection menu"));
|
showTagsWidgetCheckBox->setText(tr("Show tags selection menu"));
|
||||||
commentsLabel->setText(tr("&Comments:"));
|
commentsLabel->setText(tr("&Comments:"));
|
||||||
|
activeGroupCriteriaLabel->setText(tr("Group by:"));
|
||||||
hashLabel1->setText(tr("Hash:"));
|
hashLabel1->setText(tr("Hash:"));
|
||||||
|
|
||||||
aIncrement->setText(tr("&Increment number"));
|
aIncrement->setText(tr("&Increment number"));
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,8 @@ private:
|
||||||
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
|
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
|
||||||
QLabel *hashLabel1;
|
QLabel *hashLabel1;
|
||||||
LineEditUnfocusable *hashLabel;
|
LineEditUnfocusable *hashLabel;
|
||||||
|
QLabel *activeGroupCriteriaLabel;
|
||||||
|
QComboBox *activeGroupCriteriaComboBox;
|
||||||
|
|
||||||
QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
|
QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
|
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
|
||||||
: QWidget(_parent), deckList(nullptr)
|
: QWidget(_parent), deckList(nullptr)
|
||||||
|
|
@ -77,6 +78,21 @@ static QStringList getAllFiles(const QString &filePath)
|
||||||
return allFiles;
|
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()
|
void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
|
||||||
{
|
{
|
||||||
if (qobject_cast<DeckPreviewWidget *>(parentWidget())) {
|
if (qobject_cast<DeckPreviewWidget *>(parentWidget())) {
|
||||||
|
|
@ -91,6 +107,10 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
|
||||||
// Retrieve saved preference if the prompt is disabled
|
// Retrieve saved preference if the prompt is disabled
|
||||||
if (!SettingsCache::instance().getVisualDeckStoragePromptForConversion()) {
|
if (!SettingsCache::instance().getVisualDeckStoragePromptForConversion()) {
|
||||||
if (SettingsCache::instance().getVisualDeckStorageAlwaysConvert()) {
|
if (SettingsCache::instance().getVisualDeckStorageAlwaysConvert()) {
|
||||||
|
|
||||||
|
if (!confirmOverwriteIfExists(this, deckPreviewWidget->filePath))
|
||||||
|
return;
|
||||||
|
|
||||||
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
||||||
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getLastFileName();
|
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getLastFileName();
|
||||||
deckPreviewWidget->refreshBannerCardText();
|
deckPreviewWidget->refreshBannerCardText();
|
||||||
|
|
@ -100,6 +120,10 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
|
||||||
// Show the dialog to the user
|
// Show the dialog to the user
|
||||||
DialogConvertDeckToCodFormat conversionDialog(parentWidget());
|
DialogConvertDeckToCodFormat conversionDialog(parentWidget());
|
||||||
if (conversionDialog.exec() == QDialog::Accepted) {
|
if (conversionDialog.exec() == QDialog::Accepted) {
|
||||||
|
|
||||||
|
if (!confirmOverwriteIfExists(this, deckPreviewWidget->filePath))
|
||||||
|
return;
|
||||||
|
|
||||||
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
||||||
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getLastFileName();
|
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getLastFileName();
|
||||||
deckPreviewWidget->refreshBannerCardText();
|
deckPreviewWidget->refreshBannerCardText();
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,10 @@ void DeckPreviewTagDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
switch (event->button()) {
|
switch (event->button()) {
|
||||||
case Qt::LeftButton:
|
case Qt::LeftButton:
|
||||||
setState(TagState::Selected);
|
setState(state != TagState::Selected ? TagState::Selected : TagState::NotSelected);
|
||||||
break;
|
break;
|
||||||
case Qt::RightButton:
|
case Qt::RightButton:
|
||||||
setState(TagState::Excluded);
|
setState(state != TagState::Excluded ? TagState::Excluded : TagState::NotSelected);
|
||||||
break;
|
break;
|
||||||
case Qt::MiddleButton:
|
case Qt::MiddleButton:
|
||||||
setState(TagState::NotSelected);
|
setState(TagState::NotSelected);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ DeckPreviewWidget::DeckPreviewWidget(QWidget *_parent,
|
||||||
&DeckPreviewWidget::updateTagsVisibility);
|
&DeckPreviewWidget::updateTagsVisibility);
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageShowBannerCardComboBoxChanged, this,
|
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageShowBannerCardComboBoxChanged, this,
|
||||||
&DeckPreviewWidget::updateBannerCardComboBoxVisibility);
|
&DeckPreviewWidget::updateBannerCardComboBoxVisibility);
|
||||||
|
connect(visualDeckStorageWidget->settings(), &VisualDeckStorageQuickSettingsWidget::deckPreviewTooltipChanged, this,
|
||||||
|
&DeckPreviewWidget::refreshBannerCardToolTip);
|
||||||
|
|
||||||
layout->addWidget(bannerCardDisplayWidget);
|
layout->addWidget(bannerCardDisplayWidget);
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +81,6 @@ void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess)
|
||||||
|
|
||||||
bannerCardDisplayWidget->setCard(bannerCard);
|
bannerCardDisplayWidget->setCard(bannerCard);
|
||||||
bannerCardDisplayWidget->setFontSize(24);
|
bannerCardDisplayWidget->setFontSize(24);
|
||||||
refreshBannerCardText();
|
|
||||||
setFilePath(deckLoader->getLastFileName());
|
setFilePath(deckLoader->getLastFileName());
|
||||||
|
|
||||||
colorIdentityWidget = new ColorIdentityWidget(this, getColorIdentity());
|
colorIdentityWidget = new ColorIdentityWidget(this, getColorIdentity());
|
||||||
|
|
@ -104,6 +105,8 @@ void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess)
|
||||||
layout->addWidget(bannerCardLabel);
|
layout->addWidget(bannerCardLabel);
|
||||||
layout->addWidget(bannerCardComboBox);
|
layout->addWidget(bannerCardComboBox);
|
||||||
|
|
||||||
|
refreshBannerCardText();
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,10 +187,29 @@ void DeckPreviewWidget::setFilePath(const QString &_filePath)
|
||||||
filePath = _filePath;
|
filePath = _filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the banner card text.
|
||||||
|
* This also calls `refreshBannerCardToolTip`, since those two often need to be updated together.
|
||||||
|
*/
|
||||||
void DeckPreviewWidget::refreshBannerCardText()
|
void DeckPreviewWidget::refreshBannerCardText()
|
||||||
{
|
{
|
||||||
bannerCardDisplayWidget->setOverlayText(
|
bannerCardDisplayWidget->setOverlayText(
|
||||||
deckLoader->getName().isEmpty() ? QFileInfo(deckLoader->getLastFileName()).fileName() : deckLoader->getName());
|
deckLoader->getName().isEmpty() ? QFileInfo(deckLoader->getLastFileName()).fileName() : deckLoader->getName());
|
||||||
|
|
||||||
|
refreshBannerCardToolTip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewWidget::refreshBannerCardToolTip()
|
||||||
|
{
|
||||||
|
auto type = visualDeckStorageWidget->settings()->getDeckPreviewTooltip();
|
||||||
|
switch (type) {
|
||||||
|
case VisualDeckStorageQuickSettingsWidget::TooltipType::None:
|
||||||
|
bannerCardDisplayWidget->setToolTip("");
|
||||||
|
break;
|
||||||
|
case VisualDeckStorageQuickSettingsWidget::TooltipType::Filepath:
|
||||||
|
bannerCardDisplayWidget->setToolTip(filePath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckPreviewWidget::updateBannerCardComboBox()
|
void DeckPreviewWidget::updateBannerCardComboBox()
|
||||||
|
|
@ -260,11 +282,11 @@ void DeckPreviewWidget::updateBannerCardComboBox()
|
||||||
|
|
||||||
void DeckPreviewWidget::setBannerCard(int /* changedIndex */)
|
void DeckPreviewWidget::setBannerCard(int /* changedIndex */)
|
||||||
{
|
{
|
||||||
QVariant itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex());
|
auto nameAndId = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
||||||
deckLoader->setBannerCard(QPair<QString, QString>(bannerCardComboBox->currentText(), itemData.toString()));
|
deckLoader->setBannerCard(nameAndId);
|
||||||
deckLoader->saveToFile(filePath, DeckLoader::getFormatFromName(filePath));
|
deckLoader->saveToFile(filePath, DeckLoader::getFormatFromName(filePath));
|
||||||
bannerCardDisplayWidget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
|
bannerCardDisplayWidget->setCard(
|
||||||
bannerCardComboBox->currentText(), itemData.toString()));
|
CardDatabaseManager::getInstance()->getCardByNameAndProviderId(nameAndId.first, nameAndId.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
void setFilePath(const QString &filePath);
|
void setFilePath(const QString &filePath);
|
||||||
void refreshBannerCardText();
|
void refreshBannerCardText();
|
||||||
|
void refreshBannerCardToolTip();
|
||||||
void updateBannerCardComboBox();
|
void updateBannerCardComboBox();
|
||||||
void setBannerCard(int);
|
void setBannerCard(int);
|
||||||
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "visual_deck_storage_widget.h"
|
#include "visual_deck_storage_widget.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
|
|
||||||
VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidget *parent)
|
VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidget *parent)
|
||||||
|
|
@ -80,6 +81,26 @@ VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidg
|
||||||
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
|
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
|
||||||
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
|
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
|
||||||
|
|
||||||
|
// tooltip selector
|
||||||
|
auto deckPreviewTooltipWidget = new QWidget(this);
|
||||||
|
|
||||||
|
deckPreviewTooltipLabel = new QLabel(deckPreviewTooltipWidget);
|
||||||
|
deckPreviewTooltipComboBox = new QComboBox(deckPreviewTooltipWidget);
|
||||||
|
deckPreviewTooltipComboBox->setFocusPolicy(Qt::StrongFocus);
|
||||||
|
deckPreviewTooltipComboBox->addItem("", TooltipType::None);
|
||||||
|
deckPreviewTooltipComboBox->addItem("", TooltipType::Filepath);
|
||||||
|
|
||||||
|
deckPreviewTooltipComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageTooltipType());
|
||||||
|
connect(deckPreviewTooltipComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
[this] { emit deckPreviewTooltipChanged(getDeckPreviewTooltip()); });
|
||||||
|
connect(deckPreviewTooltipComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), &SettingsCache::instance(),
|
||||||
|
&SettingsCache::setVisualDeckStorageTooltipType);
|
||||||
|
|
||||||
|
auto deckPreviewTooltipLayout = new QHBoxLayout(deckPreviewTooltipWidget);
|
||||||
|
deckPreviewTooltipLayout->setContentsMargins(11, 0, 11, 0);
|
||||||
|
deckPreviewTooltipLayout->addWidget(deckPreviewTooltipLabel);
|
||||||
|
deckPreviewTooltipLayout->addWidget(deckPreviewTooltipComboBox);
|
||||||
|
|
||||||
// card size slider
|
// card size slider
|
||||||
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
|
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
|
||||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
|
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
|
||||||
|
|
@ -95,6 +116,7 @@ VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidg
|
||||||
this->addSettingsWidget(searchFolderNamesCheckBox);
|
this->addSettingsWidget(searchFolderNamesCheckBox);
|
||||||
this->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
|
this->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
|
||||||
this->addSettingsWidget(unusedColorIdentityOpacityWidget);
|
this->addSettingsWidget(unusedColorIdentityOpacityWidget);
|
||||||
|
this->addSettingsWidget(deckPreviewTooltipWidget);
|
||||||
this->addSettingsWidget(cardSizeWidget);
|
this->addSettingsWidget(cardSizeWidget);
|
||||||
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::langChanged, this,
|
connect(&SettingsCache::instance(), &SettingsCache::langChanged, this,
|
||||||
|
|
@ -112,6 +134,10 @@ void VisualDeckStorageQuickSettingsWidget::retranslateUi()
|
||||||
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
|
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
|
||||||
unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
|
unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
|
||||||
unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
|
unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
|
||||||
|
|
||||||
|
deckPreviewTooltipLabel->setText(tr("Deck tooltip:"));
|
||||||
|
deckPreviewTooltipComboBox->setItemText(0, tr("None"));
|
||||||
|
deckPreviewTooltipComboBox->setItemText(1, tr("Filepath"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualDeckStorageQuickSettingsWidget::getShowFolders() const
|
bool VisualDeckStorageQuickSettingsWidget::getShowFolders() const
|
||||||
|
|
@ -149,6 +175,11 @@ int VisualDeckStorageQuickSettingsWidget::getUnusedColorIdentitiesOpacity() cons
|
||||||
return unusedColorIdentitiesOpacitySpinBox->value();
|
return unusedColorIdentitiesOpacitySpinBox->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VisualDeckStorageQuickSettingsWidget::TooltipType VisualDeckStorageQuickSettingsWidget::getDeckPreviewTooltip() const
|
||||||
|
{
|
||||||
|
return deckPreviewTooltipComboBox->currentData().value<TooltipType>();
|
||||||
|
}
|
||||||
|
|
||||||
int VisualDeckStorageQuickSettingsWidget::getCardSize() const
|
int VisualDeckStorageQuickSettingsWidget::getCardSize() const
|
||||||
{
|
{
|
||||||
return cardSizeWidget->getSlider()->value();
|
return cardSizeWidget->getSlider()->value();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ class CardSizeWidget;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QSpinBox;
|
class QSpinBox;
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
|
class QComboBox;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The VDS's quick settings menu.
|
* The VDS's quick settings menu.
|
||||||
|
|
@ -25,9 +26,21 @@ class VisualDeckStorageQuickSettingsWidget : public SettingsButtonWidget
|
||||||
QCheckBox *searchFolderNamesCheckBox;
|
QCheckBox *searchFolderNamesCheckBox;
|
||||||
QLabel *unusedColorIdentitiesOpacityLabel;
|
QLabel *unusedColorIdentitiesOpacityLabel;
|
||||||
QSpinBox *unusedColorIdentitiesOpacitySpinBox;
|
QSpinBox *unusedColorIdentitiesOpacitySpinBox;
|
||||||
|
QLabel *deckPreviewTooltipLabel;
|
||||||
|
QComboBox *deckPreviewTooltipComboBox;
|
||||||
CardSizeWidget *cardSizeWidget;
|
CardSizeWidget *cardSizeWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* The info to display in the deck preview's banner card tooltip.
|
||||||
|
*/
|
||||||
|
enum TooltipType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Filepath
|
||||||
|
};
|
||||||
|
Q_ENUM(TooltipType)
|
||||||
|
|
||||||
explicit VisualDeckStorageQuickSettingsWidget(QWidget *parent = nullptr);
|
explicit VisualDeckStorageQuickSettingsWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
@ -39,6 +52,7 @@ public:
|
||||||
bool getShowTagsOnDeckPreviews() const;
|
bool getShowTagsOnDeckPreviews() const;
|
||||||
bool getSearchFolderNames() const;
|
bool getSearchFolderNames() const;
|
||||||
int getUnusedColorIdentitiesOpacity() const;
|
int getUnusedColorIdentitiesOpacity() const;
|
||||||
|
TooltipType getDeckPreviewTooltip() const;
|
||||||
int getCardSize() const;
|
int getCardSize() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
@ -49,6 +63,7 @@ signals:
|
||||||
void showTagsOnDeckPreviewsChanged(bool enabled);
|
void showTagsOnDeckPreviewsChanged(bool enabled);
|
||||||
void searchFolderNamesChanged(bool enabled);
|
void searchFolderNamesChanged(bool enabled);
|
||||||
void unusedColorIdentitiesOpacityChanged(int opacity);
|
void unusedColorIdentitiesOpacityChanged(int opacity);
|
||||||
|
void deckPreviewTooltipChanged(TooltipType tooltip);
|
||||||
void cardSizeChanged(int scale);
|
void cardSizeChanged(int scale);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
#include "visual_deck_storage_search_widget.h"
|
#include "visual_deck_storage_search_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../game/filters/deck_filter_string.h"
|
||||||
|
#include "../../../../game/filters/syntax_help.h"
|
||||||
#include "../../../../settings/cache_settings.h"
|
#include "../../../../settings/cache_settings.h"
|
||||||
|
#include "../../pixel_map_generator.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a PrintingSelectorCardSearchWidget for searching cards by set name or set code.
|
* @brief Constructs a PrintingSelectorCardSearchWidget for searching cards by set name or set code.
|
||||||
|
|
@ -17,7 +22,13 @@ VisualDeckStorageSearchWidget::VisualDeckStorageSearchWidget(VisualDeckStorageWi
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
searchBar = new QLineEdit(this);
|
searchBar = new QLineEdit(this);
|
||||||
searchBar->setPlaceholderText(tr("Search by filename"));
|
searchBar->setPlaceholderText(tr("Search by filename (or search expression)"));
|
||||||
|
searchBar->setClearButtonEnabled(true);
|
||||||
|
searchBar->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
|
||||||
|
|
||||||
|
auto help = searchBar->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
|
||||||
|
connect(help, &QAction::triggered, this, [this] { createDeckSearchSyntaxHelpWindow(searchBar); });
|
||||||
|
|
||||||
layout->addWidget(searchBar);
|
layout->addWidget(searchBar);
|
||||||
|
|
||||||
// Add a debounce timer for the search bar to limit frequent updates
|
// Add a debounce timer for the search bar to limit frequent updates
|
||||||
|
|
@ -52,11 +63,11 @@ static QString getFileSearchName(const QString &filePath, bool includeFolderName
|
||||||
{
|
{
|
||||||
QString deckPath = SettingsCache::instance().getDeckPath();
|
QString deckPath = SettingsCache::instance().getDeckPath();
|
||||||
if (includeFolderName && filePath.startsWith(deckPath)) {
|
if (includeFolderName && filePath.startsWith(deckPath)) {
|
||||||
return filePath.mid(deckPath.length()).toLower();
|
return filePath.mid(deckPath.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfo fileInfo(filePath);
|
QFileInfo fileInfo(filePath);
|
||||||
QString fileName = fileInfo.fileName().toLower();
|
QString fileName = fileInfo.fileName();
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,14 +75,10 @@ void VisualDeckStorageSearchWidget::filterWidgets(QList<DeckPreviewWidget *> wid
|
||||||
const QString &searchText,
|
const QString &searchText,
|
||||||
bool includeFolderName)
|
bool includeFolderName)
|
||||||
{
|
{
|
||||||
if (searchText.isEmpty() || searchText.isNull()) {
|
auto filterString = DeckFilterString(searchText);
|
||||||
for (auto widget : widgets) {
|
|
||||||
widget->filteredBySearch = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto file : widgets) {
|
for (auto widget : widgets) {
|
||||||
QString fileSearchName = getFileSearchName(file->filePath, includeFolderName);
|
QString fileSearchName = getFileSearchName(widget->filePath, includeFolderName);
|
||||||
file->filteredBySearch = !fileSearchName.contains(searchText.toLower());
|
widget->filteredBySearch = !filterString.check(widget, {fileSearchName});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1099,7 +1099,7 @@ void MainWindow::cardDatabaseLoadingFailed()
|
||||||
|
|
||||||
void MainWindow::cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames)
|
void MainWindow::cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames)
|
||||||
{
|
{
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox(this);
|
||||||
msgBox.setWindowTitle(tr("New sets found"));
|
msgBox.setWindowTitle(tr("New sets found"));
|
||||||
msgBox.setIcon(QMessageBox::Question);
|
msgBox.setIcon(QMessageBox::Question);
|
||||||
msgBox.setText(tr("%n new set(s) found in the card database\n"
|
msgBox.setText(tr("%n new set(s) found in the card database\n"
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,24 @@ DeckListModel::~DeckListModel()
|
||||||
delete root;
|
delete root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString DeckListModel::getSortCriteriaForCard(CardInfoPtr info)
|
||||||
|
{
|
||||||
|
if (!info) {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (activeGroupCriteria) {
|
||||||
|
case DeckListModelGroupCriteria::MAIN_TYPE:
|
||||||
|
return info->getMainCardType();
|
||||||
|
case DeckListModelGroupCriteria::MANA_COST:
|
||||||
|
return info->getCmc();
|
||||||
|
case DeckListModelGroupCriteria::COLOR:
|
||||||
|
return info->getColors() == "" ? "Colorless" : info->getColors();
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DeckListModel::rebuildTree()
|
void DeckListModel::rebuildTree()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
@ -49,7 +67,7 @@ void DeckListModel::rebuildTree()
|
||||||
}
|
}
|
||||||
|
|
||||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
||||||
QString cardType = info ? info->getMainCardType() : "unknown";
|
QString cardType = getSortCriteriaForCard(info);
|
||||||
|
|
||||||
auto *cardTypeNode = dynamic_cast<InnerDecklistNode *>(node->findChild(cardType));
|
auto *cardTypeNode = dynamic_cast<InnerDecklistNode *>(node->findChild(cardType));
|
||||||
|
|
||||||
|
|
@ -467,6 +485,12 @@ void DeckListModel::sort(int column, Qt::SortOrder order)
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckListModel::setActiveGroupCriteria(DeckListModelGroupCriteria newCriteria)
|
||||||
|
{
|
||||||
|
activeGroupCriteria = newCriteria;
|
||||||
|
rebuildTree();
|
||||||
|
}
|
||||||
|
|
||||||
void DeckListModel::cleanList()
|
void DeckListModel::cleanList()
|
||||||
{
|
{
|
||||||
setDeckList(new DeckLoader);
|
setDeckList(new DeckLoader);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,13 @@ class CardDatabase;
|
||||||
class QPrinter;
|
class QPrinter;
|
||||||
class QTextCursor;
|
class QTextCursor;
|
||||||
|
|
||||||
|
enum DeckListModelGroupCriteria
|
||||||
|
{
|
||||||
|
MAIN_TYPE,
|
||||||
|
MANA_COST,
|
||||||
|
COLOR
|
||||||
|
};
|
||||||
|
|
||||||
class DecklistModelCardNode : public AbstractDecklistCardNode
|
class DecklistModelCardNode : public AbstractDecklistCardNode
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
@ -85,6 +92,7 @@ signals:
|
||||||
public:
|
public:
|
||||||
explicit DeckListModel(QObject *parent = nullptr);
|
explicit DeckListModel(QObject *parent = nullptr);
|
||||||
~DeckListModel() override;
|
~DeckListModel() override;
|
||||||
|
QString getSortCriteriaForCard(CardInfoPtr info);
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
@ -113,10 +121,12 @@ public:
|
||||||
QList<CardInfoPtr> getCardsAsCardInfoPtrs() const;
|
QList<CardInfoPtr> getCardsAsCardInfoPtrs() const;
|
||||||
QList<CardInfoPtr> getCardsAsCardInfoPtrsForZone(QString zoneName) const;
|
QList<CardInfoPtr> getCardsAsCardInfoPtrsForZone(QString zoneName) const;
|
||||||
QList<QString> *getZones() const;
|
QList<QString> *getZones() const;
|
||||||
|
void setActiveGroupCriteria(DeckListModelGroupCriteria newCriteria);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeckLoader *deckList;
|
DeckLoader *deckList;
|
||||||
InnerDecklistNode *root;
|
InnerDecklistNode *root;
|
||||||
|
DeckListModelGroupCriteria activeGroupCriteria = DeckListModelGroupCriteria::MAIN_TYPE;
|
||||||
int lastKnownColumn;
|
int lastKnownColumn;
|
||||||
Qt::SortOrder lastKnownOrder;
|
Qt::SortOrder lastKnownOrder;
|
||||||
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
|
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../../client/ui/picture_loader/picture_loader.h"
|
#include "../../client/ui/picture_loader/picture_loader.h"
|
||||||
#include "../../deck/deck_loader.h"
|
#include "../../deck/deck_loader.h"
|
||||||
#include "../../dialogs/dlg_load_deck.h"
|
#include "../../dialogs/dlg_load_deck.h"
|
||||||
|
#include "../../dialogs/dlg_load_deck_from_clipboard.h"
|
||||||
#include "../../dialogs/dlg_load_remote_deck.h"
|
#include "../../dialogs/dlg_load_remote_deck.h"
|
||||||
#include "../../server/pending_command.h"
|
#include "../../server/pending_command.h"
|
||||||
#include "../../settings/cache_settings.h"
|
#include "../../settings/cache_settings.h"
|
||||||
|
|
@ -52,6 +53,7 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||||
{
|
{
|
||||||
loadLocalButton = new QPushButton;
|
loadLocalButton = new QPushButton;
|
||||||
loadRemoteButton = new QPushButton;
|
loadRemoteButton = new QPushButton;
|
||||||
|
loadFromClipboardButton = new QPushButton;
|
||||||
unloadDeckButton = new QPushButton;
|
unloadDeckButton = new QPushButton;
|
||||||
readyStartButton = new ToggleButton;
|
readyStartButton = new ToggleButton;
|
||||||
forceStartGameButton = new QPushButton;
|
forceStartGameButton = new QPushButton;
|
||||||
|
|
@ -59,6 +61,7 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||||
|
|
||||||
connect(loadLocalButton, &QPushButton::clicked, this, &DeckViewContainer::loadLocalDeck);
|
connect(loadLocalButton, &QPushButton::clicked, this, &DeckViewContainer::loadLocalDeck);
|
||||||
connect(loadRemoteButton, &QPushButton::clicked, this, &DeckViewContainer::loadRemoteDeck);
|
connect(loadRemoteButton, &QPushButton::clicked, this, &DeckViewContainer::loadRemoteDeck);
|
||||||
|
connect(loadFromClipboardButton, &QPushButton::clicked, this, &DeckViewContainer::loadFromClipboard);
|
||||||
connect(readyStartButton, &QPushButton::clicked, this, &DeckViewContainer::readyStart);
|
connect(readyStartButton, &QPushButton::clicked, this, &DeckViewContainer::readyStart);
|
||||||
connect(unloadDeckButton, &QPushButton::clicked, this, &DeckViewContainer::unloadDeck);
|
connect(unloadDeckButton, &QPushButton::clicked, this, &DeckViewContainer::unloadDeck);
|
||||||
connect(forceStartGameButton, &QPushButton::clicked, this, &DeckViewContainer::forceStart);
|
connect(forceStartGameButton, &QPushButton::clicked, this, &DeckViewContainer::forceStart);
|
||||||
|
|
@ -68,6 +71,7 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||||
auto *buttonHBox = new QHBoxLayout;
|
auto *buttonHBox = new QHBoxLayout;
|
||||||
buttonHBox->addWidget(loadLocalButton);
|
buttonHBox->addWidget(loadLocalButton);
|
||||||
buttonHBox->addWidget(loadRemoteButton);
|
buttonHBox->addWidget(loadRemoteButton);
|
||||||
|
buttonHBox->addWidget(loadFromClipboardButton);
|
||||||
buttonHBox->addWidget(unloadDeckButton);
|
buttonHBox->addWidget(unloadDeckButton);
|
||||||
buttonHBox->addWidget(readyStartButton);
|
buttonHBox->addWidget(readyStartButton);
|
||||||
buttonHBox->addWidget(sideboardLockButton);
|
buttonHBox->addWidget(sideboardLockButton);
|
||||||
|
|
@ -118,6 +122,7 @@ void DeckViewContainer::retranslateUi()
|
||||||
{
|
{
|
||||||
loadLocalButton->setText(tr("Load deck..."));
|
loadLocalButton->setText(tr("Load deck..."));
|
||||||
loadRemoteButton->setText(tr("Load remote deck..."));
|
loadRemoteButton->setText(tr("Load remote deck..."));
|
||||||
|
loadFromClipboardButton->setText(tr("Load from clipboard..."));
|
||||||
unloadDeckButton->setText(tr("Unload deck"));
|
unloadDeckButton->setText(tr("Unload deck"));
|
||||||
readyStartButton->setText(tr("Ready to start"));
|
readyStartButton->setText(tr("Ready to start"));
|
||||||
forceStartGameButton->setText(tr("Force start"));
|
forceStartGameButton->setText(tr("Force start"));
|
||||||
|
|
@ -148,6 +153,7 @@ void DeckViewContainer::switchToDeckSelectView()
|
||||||
|
|
||||||
setVisibility(loadLocalButton, true);
|
setVisibility(loadLocalButton, true);
|
||||||
setVisibility(loadRemoteButton, !parentGame->getIsLocalGame());
|
setVisibility(loadRemoteButton, !parentGame->getIsLocalGame());
|
||||||
|
setVisibility(loadFromClipboardButton, true);
|
||||||
setVisibility(unloadDeckButton, false);
|
setVisibility(unloadDeckButton, false);
|
||||||
setVisibility(readyStartButton, false);
|
setVisibility(readyStartButton, false);
|
||||||
setVisibility(sideboardLockButton, false);
|
setVisibility(sideboardLockButton, false);
|
||||||
|
|
@ -172,6 +178,7 @@ void DeckViewContainer::switchToDeckLoadedView()
|
||||||
|
|
||||||
setVisibility(loadLocalButton, false);
|
setVisibility(loadLocalButton, false);
|
||||||
setVisibility(loadRemoteButton, false);
|
setVisibility(loadRemoteButton, false);
|
||||||
|
setVisibility(loadFromClipboardButton, false);
|
||||||
setVisibility(unloadDeckButton, true);
|
setVisibility(unloadDeckButton, true);
|
||||||
setVisibility(readyStartButton, true);
|
setVisibility(readyStartButton, true);
|
||||||
setVisibility(sideboardLockButton, true);
|
setVisibility(sideboardLockButton, true);
|
||||||
|
|
@ -198,8 +205,11 @@ void DeckViewContainer::refreshShortcuts()
|
||||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||||
loadLocalButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadLocalButton"));
|
loadLocalButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadLocalButton"));
|
||||||
loadRemoteButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadRemoteButton"));
|
loadRemoteButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadRemoteButton"));
|
||||||
|
loadFromClipboardButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadFromClipboardButton"));
|
||||||
|
unloadDeckButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/unloadDeckButton"));
|
||||||
readyStartButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/readyStartButton"));
|
readyStartButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/readyStartButton"));
|
||||||
sideboardLockButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/sideboardLockButton"));
|
sideboardLockButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/sideboardLockButton"));
|
||||||
|
forceStartGameButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/forceStartGameButton"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -247,19 +257,27 @@ void DeckViewContainer::loadLocalDeck()
|
||||||
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||||
{
|
{
|
||||||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(filePath);
|
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(filePath);
|
||||||
QString deckString;
|
|
||||||
DeckLoader deck;
|
DeckLoader deck;
|
||||||
|
|
||||||
bool error = !deck.loadFromFile(filePath, fmt, true);
|
bool success = deck.loadFromFile(filePath, fmt, true);
|
||||||
if (!error) {
|
|
||||||
deckString = deck.writeToString_Native();
|
if (!success) {
|
||||||
error = deckString.length() > MAX_FILE_LENGTH;
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadDeckFromDeckLoader(&deck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckViewContainer::loadDeckFromDeckLoader(const DeckLoader *deck)
|
||||||
|
{
|
||||||
|
QString deckString = deck->writeToString_Native();
|
||||||
|
|
||||||
|
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Command_DeckSelect cmd;
|
Command_DeckSelect cmd;
|
||||||
cmd.set_deck(deckString.toStdString());
|
cmd.set_deck(deckString.toStdString());
|
||||||
PendingCommand *pend = parentGame->prepareGameCommand(cmd);
|
PendingCommand *pend = parentGame->prepareGameCommand(cmd);
|
||||||
|
|
@ -279,6 +297,18 @@ void DeckViewContainer::loadRemoteDeck()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckViewContainer::loadFromClipboard()
|
||||||
|
{
|
||||||
|
auto dlg = DlgLoadDeckFromClipboard(this);
|
||||||
|
|
||||||
|
if (!dlg.exec()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeckLoader *deck = dlg.getDeckList();
|
||||||
|
loadDeckFromDeckLoader(deck);
|
||||||
|
}
|
||||||
|
|
||||||
void DeckViewContainer::deckSelectFinished(const Response &r)
|
void DeckViewContainer::deckSelectFinished(const Response &r)
|
||||||
{
|
{
|
||||||
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ class DeckViewContainer : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *deckViewLayout;
|
QVBoxLayout *deckViewLayout;
|
||||||
QPushButton *loadLocalButton, *loadRemoteButton, *unloadDeckButton, *forceStartGameButton;
|
QPushButton *loadLocalButton, *loadRemoteButton, *loadFromClipboardButton;
|
||||||
|
QPushButton *unloadDeckButton, *forceStartGameButton;
|
||||||
ToggleButton *readyStartButton, *sideboardLockButton;
|
ToggleButton *readyStartButton, *sideboardLockButton;
|
||||||
DeckView *deckView;
|
DeckView *deckView;
|
||||||
VisualDeckStorageWidget *visualDeckStorageWidget;
|
VisualDeckStorageWidget *visualDeckStorageWidget;
|
||||||
|
|
@ -58,6 +59,7 @@ private slots:
|
||||||
void switchToDeckLoadedView();
|
void switchToDeckLoadedView();
|
||||||
void loadLocalDeck();
|
void loadLocalDeck();
|
||||||
void loadRemoteDeck();
|
void loadRemoteDeck();
|
||||||
|
void loadFromClipboard();
|
||||||
void unloadDeck();
|
void unloadDeck();
|
||||||
void readyStart();
|
void readyStart();
|
||||||
void forceStart();
|
void forceStart();
|
||||||
|
|
@ -81,6 +83,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadDeckFromFile(const QString &filePath);
|
void loadDeckFromFile(const QString &filePath);
|
||||||
|
void loadDeckFromDeckLoader(const DeckLoader *deck);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECK_VIEW_CONTAINER_H
|
#endif // DECK_VIEW_CONTAINER_H
|
||||||
|
|
|
||||||
167
cockatrice/src/game/filters/deck_filter_string.cpp
Normal file
167
cockatrice/src/game/filters/deck_filter_string.cpp
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
#include "deck_filter_string.h"
|
||||||
|
|
||||||
|
#include "../cards/card_database_manager.h"
|
||||||
|
#include "filter_string.h"
|
||||||
|
#include "lib/peglib.h"
|
||||||
|
|
||||||
|
static peg::parser search(R"(
|
||||||
|
Start <- QueryPartList
|
||||||
|
~ws <- [ ]+
|
||||||
|
QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
|
||||||
|
|
||||||
|
ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
|
||||||
|
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
||||||
|
|
||||||
|
QueryPart <- NotQuery / DeckContentQuery / GenericQuery
|
||||||
|
|
||||||
|
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
||||||
|
|
||||||
|
DeckContentQuery <- CardSearch NumericExpression?
|
||||||
|
CardSearch <- '[[' CardFilterString ']]'
|
||||||
|
CardFilterString <- (!']]'.)*
|
||||||
|
|
||||||
|
GenericQuery <- String
|
||||||
|
|
||||||
|
NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["].
|
||||||
|
NonSingleQuoteUnlessEscaped <- "\\\'". / !['].
|
||||||
|
UnescapedStringListPart <- !['":<>=! ].
|
||||||
|
SingleApostropheString <- (UnescapedStringListPart+ ws*)* ['] (UnescapedStringListPart+ ws*)*
|
||||||
|
|
||||||
|
String <- SingleApostropheString / UnescapedStringListPart+ / ["] <NonDoubleQuoteUnlessEscaped*> ["] / ['] <NonSingleQuoteUnlessEscaped*> [']
|
||||||
|
|
||||||
|
NumericExpression <- NumericOperator ws? NumericValue
|
||||||
|
NumericOperator <- [=:] / <[><!][=]?>
|
||||||
|
NumericValue <- [0-9]+
|
||||||
|
)");
|
||||||
|
|
||||||
|
static std::once_flag init;
|
||||||
|
|
||||||
|
static void setupParserRules()
|
||||||
|
{
|
||||||
|
// plumbing
|
||||||
|
auto passthru = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
return !sv.empty() ? std::any_cast<DeckFilter>(sv[0]) : nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
search["Start"] = passthru;
|
||||||
|
search["QueryPartList"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) {
|
||||||
|
auto matchesFilter = [&deck, &info](const std::any &query) {
|
||||||
|
return std::any_cast<DeckFilter>(query)(deck, info);
|
||||||
|
};
|
||||||
|
return std::all_of(sv.begin(), sv.end(), matchesFilter);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
search["ComplexQueryPart"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) {
|
||||||
|
auto matchesFilter = [&deck, &info](const std::any &query) {
|
||||||
|
return std::any_cast<DeckFilter>(query)(deck, info);
|
||||||
|
};
|
||||||
|
return std::any_of(sv.begin(), sv.end(), matchesFilter);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
search["SomewhatComplexQueryPart"] = passthru;
|
||||||
|
search["QueryPart"] = passthru;
|
||||||
|
search["NotQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
const auto dependent = std::any_cast<DeckFilter>(sv[0]);
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) -> bool {
|
||||||
|
return !dependent(deck, info);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
search["String"] = [](const peg::SemanticValues &sv) -> QString {
|
||||||
|
if (sv.choice() == 0) {
|
||||||
|
return QString::fromStdString(std::string(sv.sv()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromStdString(std::string(sv.token(0)));
|
||||||
|
};
|
||||||
|
|
||||||
|
search["NumericExpression"] = [](const peg::SemanticValues &sv) -> NumberMatcher {
|
||||||
|
const auto arg = std::any_cast<int>(sv[1]);
|
||||||
|
const auto op = std::any_cast<QString>(sv[0]);
|
||||||
|
|
||||||
|
if (op == ">")
|
||||||
|
return [=](const int s) { return s > arg; };
|
||||||
|
if (op == ">=")
|
||||||
|
return [=](const int s) { return s >= arg; };
|
||||||
|
if (op == "<")
|
||||||
|
return [=](const int s) { return s < arg; };
|
||||||
|
if (op == "<=")
|
||||||
|
return [=](const int s) { return s <= arg; };
|
||||||
|
if (op == "=")
|
||||||
|
return [=](const int s) { return s == arg; };
|
||||||
|
if (op == ":")
|
||||||
|
return [=](const int s) { return s == arg; };
|
||||||
|
if (op == "!=")
|
||||||
|
return [=](const int s) { return s != arg; };
|
||||||
|
return [](int) { return false; };
|
||||||
|
};
|
||||||
|
|
||||||
|
search["NumericValue"] = [](const peg::SemanticValues &sv) -> int {
|
||||||
|
return QString::fromStdString(std::string(sv.sv())).toInt();
|
||||||
|
};
|
||||||
|
|
||||||
|
search["NumericOperator"] = [](const peg::SemanticValues &sv) -> QString {
|
||||||
|
return QString::fromStdString(std::string(sv.sv()));
|
||||||
|
};
|
||||||
|
|
||||||
|
// actual functionality
|
||||||
|
search["DeckContentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
auto cardFilter = FilterString(std::any_cast<QString>(sv[0]));
|
||||||
|
auto numberMatcher = sv.size() > 1 ? std::any_cast<NumberMatcher>(sv[1]) : [](int count) { return count > 0; };
|
||||||
|
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
||||||
|
int count = 0;
|
||||||
|
deck->deckLoader->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) {
|
||||||
|
auto cardInfoPtr = CardDatabaseManager::getInstance()->getCard(node->getName());
|
||||||
|
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
||||||
|
count += node->getNumber();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return numberMatcher(count);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
search["CardSearch"] = [](const peg::SemanticValues &sv) -> QString { return std::any_cast<QString>(sv[0]); };
|
||||||
|
|
||||||
|
search["CardFilterString"] = [](const peg::SemanticValues &sv) -> QString {
|
||||||
|
return QString::fromStdString(std::string(sv.sv()));
|
||||||
|
};
|
||||||
|
|
||||||
|
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
auto name = std::any_cast<QString>(sv[0]);
|
||||||
|
return [=](const DeckPreviewWidget *, const ExtraDeckSearchInfo &info) {
|
||||||
|
return info.fileSearchName.contains(name, Qt::CaseInsensitive);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DeckFilterString::DeckFilterString()
|
||||||
|
{
|
||||||
|
filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; };
|
||||||
|
_error = "Not initialized";
|
||||||
|
}
|
||||||
|
|
||||||
|
DeckFilterString::DeckFilterString(const QString &expr)
|
||||||
|
{
|
||||||
|
QByteArray ba = expr.simplified().toUtf8();
|
||||||
|
|
||||||
|
std::call_once(init, setupParserRules);
|
||||||
|
|
||||||
|
_error = QString();
|
||||||
|
|
||||||
|
if (ba.isEmpty()) {
|
||||||
|
filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return true; };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
search.set_logger([&](size_t /*ln*/, size_t col, const std::string &msg) {
|
||||||
|
_error = QString("Error at position %1: %2").arg(col).arg(QString::fromStdString(msg));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!search.parse(ba.data(), filter)) {
|
||||||
|
qCInfo(DeckFilterStringLog).nospace() << "DeckFilterString error for " << expr << "; " << qPrintable(_error);
|
||||||
|
filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; };
|
||||||
|
}
|
||||||
|
}
|
||||||
51
cockatrice/src/game/filters/deck_filter_string.h
Normal file
51
cockatrice/src/game/filters/deck_filter_string.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef DECK_FILTER_STRING_H
|
||||||
|
#define DECK_FILTER_STRING_H
|
||||||
|
|
||||||
|
#include "../../client/ui/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");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra info relevant to filtering that isn't present in the DeckPreviewWidget
|
||||||
|
*/
|
||||||
|
struct ExtraDeckSearchInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The filename used for filtering. Varies based on settings.
|
||||||
|
*/
|
||||||
|
QString fileSearchName;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::function<bool(const DeckPreviewWidget *, const ExtraDeckSearchInfo &)> DeckFilter;
|
||||||
|
|
||||||
|
class DeckFilterString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeckFilterString();
|
||||||
|
explicit DeckFilterString(const QString &expr);
|
||||||
|
bool check(const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) const
|
||||||
|
{
|
||||||
|
return filter(deck, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid() const
|
||||||
|
{
|
||||||
|
return _error.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString error()
|
||||||
|
{
|
||||||
|
return _error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _error;
|
||||||
|
DeckFilter filter;
|
||||||
|
};
|
||||||
|
#endif // DECK_FILTER_STRING_H
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
peg::parser search(R"(
|
static peg::parser search(R"(
|
||||||
Start <- QueryPartList
|
Start <- QueryPartList
|
||||||
~ws <- [ ]+
|
~ws <- [ ]+
|
||||||
QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
|
QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
|
||||||
|
|
@ -63,7 +63,7 @@ NumericOperator <- [=:] / <[><!][=]?>
|
||||||
NumericValue <- [0-9]+
|
NumericValue <- [0-9]+
|
||||||
)");
|
)");
|
||||||
|
|
||||||
std::once_flag init;
|
static std::once_flag init;
|
||||||
|
|
||||||
static void setupParserRules()
|
static void setupParserRules()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,12 @@
|
||||||
*
|
*
|
||||||
* @return the QTextBrowser
|
* @return the QTextBrowser
|
||||||
*/
|
*/
|
||||||
static QTextBrowser *createBrowser()
|
static QTextBrowser *createBrowser(const QString &helpFile)
|
||||||
{
|
{
|
||||||
QFile file("theme:help/search.md");
|
QFile file(helpFile);
|
||||||
|
|
||||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
qCWarning(SyntaxHelpLog) << "Could not open syntax help file: " << helpFile;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,9 +55,29 @@ static QTextBrowser *createBrowser()
|
||||||
*/
|
*/
|
||||||
QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit)
|
QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit)
|
||||||
{
|
{
|
||||||
auto browser = createBrowser();
|
auto browser = createBrowser("theme:help/search.md");
|
||||||
QObject::connect(browser, &QTextBrowser::anchorClicked,
|
QObject::connect(browser, &QTextBrowser::anchorClicked,
|
||||||
[lineEdit](const QUrl &link) { lineEdit->setText(link.fragment()); });
|
[lineEdit](const QUrl &link) { lineEdit->setText(link.fragment()); });
|
||||||
QObject::connect(lineEdit, &QObject::destroyed, browser, &QTextBrowser::close);
|
QObject::connect(lineEdit, &QObject::destroyed, browser, &QTextBrowser::close);
|
||||||
return browser;
|
return browser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the deck search syntax help window and connects its anchorClicked signal to the given QLineEdit.
|
||||||
|
* The window will automatically close when the QLineEdit is destroyed.
|
||||||
|
*
|
||||||
|
* @return the QTextBrowser
|
||||||
|
*/
|
||||||
|
QTextBrowser *createDeckSearchSyntaxHelpWindow(QLineEdit *lineEdit)
|
||||||
|
{
|
||||||
|
auto browser = createBrowser("theme:help/deck_search.md");
|
||||||
|
QObject::connect(browser, &QTextBrowser::anchorClicked, [lineEdit](const QUrl &link) {
|
||||||
|
if (link.fragment() == "cardSearchSyntaxHelp") {
|
||||||
|
createSearchSyntaxHelpWindow(lineEdit);
|
||||||
|
} else {
|
||||||
|
lineEdit->setText(link.fragment());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
QObject::connect(lineEdit, &QObject::destroyed, browser, &QTextBrowser::close);
|
||||||
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
@ -2,8 +2,13 @@
|
||||||
#define SEARCH_SYNTAX_HELP_H
|
#define SEARCH_SYNTAX_HELP_H
|
||||||
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include <QLoggingCategory>
|
||||||
#include <QTextBrowser>
|
#include <QTextBrowser>
|
||||||
|
|
||||||
|
inline Q_LOGGING_CATEGORY(SyntaxHelpLog, "syntax_help");
|
||||||
|
|
||||||
QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit);
|
QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit);
|
||||||
|
|
||||||
|
QTextBrowser *createDeckSearchSyntaxHelpWindow(QLineEdit *lineEdit);
|
||||||
|
|
||||||
#endif // SEARCH_SYNTAX_HELP_H
|
#endif // SEARCH_SYNTAX_HELP_H
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,7 @@ SettingsCache::SettingsCache()
|
||||||
settings->value("interface/visualdeckstoragedrawunusedcoloridentities", true).toBool();
|
settings->value("interface/visualdeckstoragedrawunusedcoloridentities", true).toBool();
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacity =
|
visualDeckStorageUnusedColorIdentitiesOpacity =
|
||||||
settings->value("interface/visualdeckstorageunusedcoloridentitiesopacity", 15).toInt();
|
settings->value("interface/visualdeckstorageunusedcoloridentitiesopacity", 15).toInt();
|
||||||
|
visualDeckStorageTooltipType = settings->value("interface/visualdeckstoragetooltiptype", 0).toInt();
|
||||||
visualDeckStoragePromptForConversion =
|
visualDeckStoragePromptForConversion =
|
||||||
settings->value("interface/visualdeckstoragepromptforconversion", true).toBool();
|
settings->value("interface/visualdeckstoragepromptforconversion", true).toBool();
|
||||||
visualDeckStorageAlwaysConvert = settings->value("interface/visualdeckstoragealwaysconvert", false).toBool();
|
visualDeckStorageAlwaysConvert = settings->value("interface/visualdeckstoragealwaysconvert", false).toBool();
|
||||||
|
|
@ -774,6 +775,12 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visual
|
||||||
emit visualDeckStorageUnusedColorIdentitiesOpacityChanged(visualDeckStorageUnusedColorIdentitiesOpacity);
|
emit visualDeckStorageUnusedColorIdentitiesOpacityChanged(visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setVisualDeckStorageTooltipType(int value)
|
||||||
|
{
|
||||||
|
visualDeckStorageTooltipType = value;
|
||||||
|
settings->setValue("interface/visualdeckstoragetooltiptype", visualDeckStorageTooltipType);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setVisualDeckStoragePromptForConversion(bool _visualDeckStoragePromptForConversion)
|
void SettingsCache::setVisualDeckStoragePromptForConversion(bool _visualDeckStoragePromptForConversion)
|
||||||
{
|
{
|
||||||
visualDeckStoragePromptForConversion = _visualDeckStoragePromptForConversion;
|
visualDeckStoragePromptForConversion = _visualDeckStoragePromptForConversion;
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ private:
|
||||||
int visualDeckStorageCardSize;
|
int visualDeckStorageCardSize;
|
||||||
bool visualDeckStorageDrawUnusedColorIdentities;
|
bool visualDeckStorageDrawUnusedColorIdentities;
|
||||||
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
|
int visualDeckStorageTooltipType;
|
||||||
bool visualDeckStoragePromptForConversion;
|
bool visualDeckStoragePromptForConversion;
|
||||||
bool visualDeckStorageAlwaysConvert;
|
bool visualDeckStorageAlwaysConvert;
|
||||||
bool visualDeckStorageInGame;
|
bool visualDeckStorageInGame;
|
||||||
|
|
@ -476,6 +477,10 @@ public:
|
||||||
{
|
{
|
||||||
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
}
|
}
|
||||||
|
int getVisualDeckStorageTooltipType() const
|
||||||
|
{
|
||||||
|
return visualDeckStorageTooltipType;
|
||||||
|
}
|
||||||
bool getVisualDeckStoragePromptForConversion() const
|
bool getVisualDeckStoragePromptForConversion() const
|
||||||
{
|
{
|
||||||
return visualDeckStoragePromptForConversion;
|
return visualDeckStoragePromptForConversion;
|
||||||
|
|
@ -852,6 +857,7 @@ public slots:
|
||||||
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
||||||
void setVisualDeckStorageDrawUnusedColorIdentities(QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities);
|
void setVisualDeckStorageDrawUnusedColorIdentities(QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities);
|
||||||
void setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity);
|
void setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
|
void setVisualDeckStorageTooltipType(int value);
|
||||||
void setVisualDeckStoragePromptForConversion(bool _visualDeckStoragePromptForConversion);
|
void setVisualDeckStoragePromptForConversion(bool _visualDeckStoragePromptForConversion);
|
||||||
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
|
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
|
||||||
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
|
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,13 @@ private:
|
||||||
{"DeckViewContainer/loadRemoteButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Remote Deck..."),
|
{"DeckViewContainer/loadRemoteButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Remote Deck..."),
|
||||||
parseSequenceString("Ctrl+Alt+O"),
|
parseSequenceString("Ctrl+Alt+O"),
|
||||||
ShortcutGroup::Game_Lobby)},
|
ShortcutGroup::Game_Lobby)},
|
||||||
|
{"DeckViewContainer/loadFromClipboardButton",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Deck from Clipboard..."),
|
||||||
|
parseSequenceString("Ctrl+Shift+V"),
|
||||||
|
ShortcutGroup::Game_Lobby)},
|
||||||
|
{"DeckViewContainer/unloadDeckButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Unload Deck"),
|
||||||
|
parseSequenceString("Ctrl+Alt+U"),
|
||||||
|
ShortcutGroup::Game_Lobby)},
|
||||||
{"DeckViewContainer/readyStartButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Ready to Start"),
|
{"DeckViewContainer/readyStartButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Ready to Start"),
|
||||||
parseSequenceString("Ctrl+Shift+S"),
|
parseSequenceString("Ctrl+Shift+S"),
|
||||||
ShortcutGroup::Game_Lobby)},
|
ShortcutGroup::Game_Lobby)},
|
||||||
|
|
@ -274,6 +281,9 @@ private:
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Sideboard Lock"),
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Sideboard Lock"),
|
||||||
parseSequenceString("Ctrl+Shift+B"),
|
parseSequenceString("Ctrl+Shift+B"),
|
||||||
ShortcutGroup::Game_Lobby)},
|
ShortcutGroup::Game_Lobby)},
|
||||||
|
{"DeckViewContainer/forceStartGameButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Force Start"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Game_Lobby)},
|
||||||
{"Player/aCCGreen", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Green Counter"),
|
{"Player/aCCGreen", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Green Counter"),
|
||||||
parseSequenceString("Ctrl+>"),
|
parseSequenceString("Ctrl+>"),
|
||||||
ShortcutGroup::Card_Counters)},
|
ShortcutGroup::Card_Counters)},
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,7 @@ bool DeckList::readElement(QXmlStreamReader *xml)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckList::write(QXmlStreamWriter *xml)
|
void DeckList::write(QXmlStreamWriter *xml) const
|
||||||
{
|
{
|
||||||
xml->writeStartElement("cockatrice_deck");
|
xml->writeStartElement("cockatrice_deck");
|
||||||
xml->writeAttribute("version", "1");
|
xml->writeAttribute("version", "1");
|
||||||
|
|
@ -508,7 +508,7 @@ bool DeckList::loadFromString_Native(const QString &nativeString)
|
||||||
return loadFromXml(&xml);
|
return loadFromXml(&xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DeckList::writeToString_Native()
|
QString DeckList::writeToString_Native() const
|
||||||
{
|
{
|
||||||
QString result;
|
QString result;
|
||||||
QXmlStreamWriter xml(&result);
|
QXmlStreamWriter xml(&result);
|
||||||
|
|
|
||||||
|
|
@ -345,10 +345,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readElement(QXmlStreamReader *xml);
|
bool readElement(QXmlStreamReader *xml);
|
||||||
void write(QXmlStreamWriter *xml);
|
void write(QXmlStreamWriter *xml) const;
|
||||||
bool loadFromXml(QXmlStreamReader *xml);
|
bool loadFromXml(QXmlStreamReader *xml);
|
||||||
bool loadFromString_Native(const QString &nativeString);
|
bool loadFromString_Native(const QString &nativeString);
|
||||||
QString writeToString_Native();
|
QString writeToString_Native() const;
|
||||||
bool loadFromFile_Native(QIODevice *device);
|
bool loadFromFile_Native(QIODevice *device);
|
||||||
bool saveToFile_Native(QIODevice *device);
|
bool saveToFile_Native(QIODevice *device);
|
||||||
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
|
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,9 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
|
||||||
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setVisualDeckStorageTooltipType(int /* value */)
|
||||||
|
{
|
||||||
|
}
|
||||||
void SettingsCache::setVisualDeckStoragePromptForConversion(bool /* _visualDeckStoragePromptForConversion */)
|
void SettingsCache::setVisualDeckStoragePromptForConversion(bool /* _visualDeckStoragePromptForConversion */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,9 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
|
||||||
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setVisualDeckStorageTooltipType(int /* value */)
|
||||||
|
{
|
||||||
|
}
|
||||||
void SettingsCache::setVisualDeckStoragePromptForConversion(bool /* _visualDeckStoragePromptForConversion */)
|
void SettingsCache::setVisualDeckStoragePromptForConversion(bool /* _visualDeckStoragePromptForConversion */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue