Compare commits

..

1 Commits

Author SHA1 Message Date
ZeldaZach
316c9d13a0 Find OpenSSL on Windows 2023-01-11 18:58:02 -05:00
353 changed files with 42138 additions and 47984 deletions

View File

@@ -9,7 +9,6 @@ RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
mariadb-libs \
protobuf \
qt6-base \
qt6-imageformats \
qt6-multimedia \
qt6-svg \
qt6-tools \

25
.ci/Debian10/Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
FROM debian:10
RUN apt-get update && 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 \
qtbase5-dev \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -17,7 +17,6 @@ RUN apt-get update && \
libqt5svg5-dev \
libqt5websockets5-dev \
protobuf-compiler \
qt5-image-formats-plugins \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \

View File

@@ -1,27 +0,0 @@
FROM debian:12
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
ccache \
clang-format \
cmake \
file \
g++ \
git \
libgl-dev \
liblzma-dev \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
qt6-svg-dev \
qt6-websockets-dev \
protobuf-compiler \
qt6-image-formats-plugins \
qt6-l10n-tools \
qt6-multimedia-dev \
qt6-tools-dev \
qt6-tools-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

21
.ci/Fedora35/Dockerfile Normal file
View File

@@ -0,0 +1,21 @@
FROM fedora:35
RUN dnf install -y \
@development-tools \
ccache \
cmake \
desktop-file-utils \
file \
gcc-c++ \
git \
hicolor-icon-theme \
libappstream-glib \
mariadb-devel \
protobuf-devel \
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
rpm-build \
sqlite-devel \
wget \
xz-devel \
zlib-devel \
&& dnf clean all

View File

@@ -1,4 +1,4 @@
FROM fedora:39
FROM fedora:36
RUN dnf install -y \
ccache \
@@ -8,7 +8,6 @@ RUN dnf install -y \
mariadb-devel \
protobuf-devel \
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
qt6-qtimageformats \
rpm-build \
xz-devel \
zlib-devel \

View File

@@ -1,15 +0,0 @@
FROM fedora:40
RUN dnf install -y \
ccache \
cmake \
gcc-c++ \
git \
mariadb-devel \
protobuf-devel \
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
qt6-qtimageformats \
rpm-build \
xz-devel \
zlib-devel \
&& dnf clean all

View File

@@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libqt5websockets5-dev \
protobuf-compiler \
qt5-default \
qt5-image-formats-plugins \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \

View File

@@ -18,7 +18,6 @@ RUN apt-get update && \
libqt5websockets5-dev \
protobuf-compiler \
qt5-default \
qt5-image-formats-plugins \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \

View File

@@ -18,7 +18,6 @@ RUN apt-get update && \
libqt6svg6-dev \
libqt6websockets6-dev \
protobuf-compiler \
qt6-image-formats-plugins \
qt6-l10n-tools \
qt6-multimedia-dev \
qt6-tools-dev \

View File

@@ -1,27 +0,0 @@
FROM ubuntu:noble
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
ccache \
clang-format \
cmake \
file \
g++ \
git \
libgl-dev \
liblzma-dev \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
qt6-svg-dev \
qt6-websockets-dev \
protobuf-compiler \
qt6-image-formats-plugins \
qt6-l10n-tools \
qt6-multimedia-dev \
qt6-tools-dev \
qt6-tools-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -127,7 +127,7 @@ fi
# Add cmake --build flags
buildflags=(--config "$BUILDTYPE")
if [[ $PARALLEL_COUNT ]]; then
if [[ $(cmake --build /not_a_dir --parallel 2>&1 | head -1) =~ parallel ]]; then
if [[ $(cmake --build /not_a_dir --parallel |& 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")
@@ -160,13 +160,7 @@ cmake .. "${flags[@]}"
echo "::endgroup::"
echo "::group::Build project"
if [[ $RUNNER_OS == Windows ]]; then
# Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
# and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt
cmake --build . "${buildflags[@]}" -- -p:UseMultiToolTask=true -p:EnableClServerMode=true
else
cmake --build . "${buildflags[@]}"
fi
cmake --build . "${buildflags[@]}"
echo "::endgroup::"
if [[ $USE_CCACHE ]]; then
@@ -177,7 +171,7 @@ fi
if [[ $MAKE_TEST ]]; then
echo "::group::Run tests"
ctest -C "$BUILDTYPE" --output-on-failure
ctest -C "$BUILDTYPE"
echo "::endgroup::"
fi

View File

@@ -8,20 +8,21 @@ git push -d origin --REPLACE-WITH-BETA-LIST--
include different targets -->
<pre>
<b>Pre-compiled binaries we serve:</b>
- <kbd>Windows 7+</kbd>
- <kbd>Windows 10+</kbd>
- <kbd>macOS 10.15+</kbd> ("Catalina")
- <kbd>macOS 13+</kbd> ("Ventura")
- <kbd>Ubuntu 18.04 LTS</kbd> ("Bionic Beaver")
- <kbd>Ubuntu 20.04 LTS</kbd> ("Focal Fossa")
- <kbd>Ubuntu 22.04 LTS</kbd> ("Jammy Jellyfish")
- <kbd>Ubuntu 24.04 LTS</kbd> ("Noble Numbat")
- <kbd>Windows 7/8/10/11 (32-bit)</kbd>
- <kbd>Windows 7/8 (64-bit)</kbd>
- <kbd>Windows 10/11 (64-bit)</kbd>
- <kbd>macOS 10.14</kbd> ("Mojave")
- <kbd>macOS 10.15</kbd> ("Catalina")
- <kbd>macOS 11.0+</kbd> ("Big Sur")
- <kbd>Ubuntu 18.04</kbd> ("Bionic Beaver")
- <kbd>Ubuntu 20.04</kbd> ("Focal Fossa")
- <kbd>Ubuntu 22.04</kbd> ("Jammy Jellyfish")
- <kbd>Debian 10</kbd> ("Buster")
- <kbd>Debian 11</kbd> ("Bullseye")
- <kbd>Debian 12</kbd> ("Bookworm")
- <kbd>Fedora 39</kbd>
- <kbd>Fedora 40</kbd>
- <kbd>Fedora 35</kbd>
- <kbd>Fedora 36</kbd>
<kbd>We are also packaged in Arch Linux's official community repository, courtesy of @FFY00</kbd></i>
<kbd>General Linux support is available via a flatpak package (Flathub)</kbd></i>
<kbd>General linux support is available via a flatpak package (Flathub)</kbd></i>
</pre>

View File

@@ -1,58 +0,0 @@
#!/bin/bash
# ci script to update translation files
# usage:
# $0 cockatrice/cockatrice_en@source.ts cockatrice/src common
# or
# FILE="cockatrice/cockatrice_en@source.ts"
# DIRS="cockatrice/src common"
# $0
# note: directories can't contain spaces
# check parameters
if [[ ! $FILE ]]; then
FILE="$1"
shift
fi
if [[ ! $FILE ]]; then
echo "no output file selected" >&2
exit 2;
fi
if [[ ! $DIRS ]]; then
DIRS="$*"
fi
if [[ ! $DIRS ]]; then
echo "no source directories selected to translate" >&2
exit 2;
fi
if [[ ! -e $FILE ]]; then
echo "output file does not exist at: $FILE" >&2
exit 3;
fi
# print version
if ! lupdate -version; then
echo "failed to run lupdate" >&2
exit 4;
fi
# run lupdate, duplicating the output in stderr and saving it
# for convenience we ignore that $DIRS will be split on spaces
# shellcheck disable=SC2086
if ! got="$(lupdate $DIRS -ts "$FILE" | tee /dev/stderr)"; then
echo "failed to update $FILE with $DIRS" >&2
exit 4;
fi
# trim output
# the line we are interested in is:
# Found xxx source text(s) (x new and xxx already existing)
output="${got##* source text(s) (}" # get stuff in between brackets
output="${output%%)*}" # trim everything after first )
if [[ $output == "$got" ]]; then
echo "could not parse generated output" >&2
exit 4;
fi
# write output to ci environment file
echo "output=$output" >> "$GITHUB_OUTPUT"

View File

@@ -1,14 +0,0 @@
Updated source strings for translations:
- {{ .cockatrice_output }} (Cockatrice)
- {{ .oracle_output }} (Oracle)
<br>
Last changes are based on commit {{ .commit }}.
---
*This PR is automatically generated and updated by the workflow at `.github/workflows/translations-push.yml`. Review [action runs][2].*<br>
*After merging, all changes to the source language are available for translation at [Transifex][1] shortly.*
[1]: https://app.transifex.com/cockatrice/cockatrice/
[2]: https://github.com/Cockatrice/Cockatrice/actions/workflows/translations-push.yml?query=branch%3Amaster

View File

@@ -290,21 +290,20 @@ be included in the next release 👍
Basic workflow for translations:
1. Developer adds a `tr("foo")` string in the code;
2. CI updates the `*_en@source.ts files` regularly and creates a PR automatically;
3. Maintainer verifies and merges the change;
4. Transifex picks up the new files from GitHub automatically;
5. Translators translate the new untranslated strings on Transifex;
6. Before a release, a maintainer fetches the updated translations from Transifex.
2. Every few days, a maintainer updates the `*_en@source.ts files` with the new strings;
3. Transifex picks up the new files from GitHub every 24 hours;
4. Translators translate the new untranslated strings on Transifex;
5. Before a release, a maintainer fetches the updated translations from Transifex.
### Using Translations (for developers) ###
All user interface strings inside Cockatrice's source code must be written
in English (US).
All the user-interface strings inside Cockatrice's source code must be written
in English(US).
Translations to other languages are managed using [Transifex](
https://www.transifex.com/projects/p/cockatrice/).
Adding a new string to translate is as easy as adding the string in the
`tr("")` function, the string will be picked up as translatable automatically
'tr("")' function, the string will be picked up as translatable automatically
and translated as needed.
For example, setting the text of a label in the way that the string
`"My name is:"` can be translated:
@@ -313,7 +312,7 @@ nameLabel.setText(tr("My name is:"));
```
To translate a string that would have plural forms you can add the amount to
the tr() call, also you can add an extra string as a hint for translators:
the tr call, also you can add an extra string as a hint for translators:
```c++
QString message = tr("Everyone draws %n cards", "pop up message", amount);
```
@@ -322,46 +321,20 @@ https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
If you're about to propose a change that adds or modifies any translatable
string in the code, you don't need to take care of adding the new strings to
the translation files.<br>
We have an automated process to update our language source files on a schedule
and provide the translators on Transifex with the new contents.<br>
Maintainers can also manually trigger this on demand.
the translation files.
Every few days, or when a lot of new strings have been added, someone from the
development team will take care of extracting all the new strings and adding
them to the english translation files and making them available to translators
on Transifex.
### Maintaining Translations (for maintainers) ###
When new translatable strings have been added to the code, a maintainer has to
make them available to translators on Transifex.
When new translatable strings have been added to the code, a maintainer should
make them available to translators on Transifex. Every few days, or when a lot
of new strings have been added, a maintainer should take care of extracting all
the new strings and add them to the english translation files.
To help with that, we have an automated CI workflow, that regularly looks at the
code in the master branch, extracts all strings and updates dedicated source string
files with any changes. These updates are not commited right away, the CI creates a
PR for reviewing instead.<br>
After approval, our translation tool automatically picks the changes up and deploys
them to our translators. Be mindful when merging only a few changes!
Once a release is planned, or when a lot of strings have been added or changed, a
maintainer can manually trigger a CI run to extract all strings on demand.
<details>
<summary><b>Manually trigger CI run (Workflow Dispatch)</b></summary>
Maintainers can always request the CI to run on demand if it's required.
Go to the `Actions` tab and select our dedicated translation workflow:
https://github.com/Cockatrice/Cockatrice/actions/workflows/translations.yml
You see a "This workflow has a workflow_dispatch event trigger." hint at the top of
the list.<br>
Select `Run workflow` on the right and trigger a run from master branch.
The CI will now check for changed strings and create a PR if there are any updates.
</details>
<details>
<summary><b>Manually update source strings locally</b></summary>
To update the english source files for translation, re-run cmake enabling the appropriate
To update the english translation files, re-run cmake enabling the appropriate
parameter and then run make:
```sh
cd cockatrice/build
@@ -384,13 +357,11 @@ It is recommended to disable the parameter afterwards using:
```sh
cmake .. -DUPDATE_TRANSLATIONS=OFF
```
Now you are ready to commit your changes and open a PR.
Now you are ready to propose your change.
</details>
Once the changes get merged, Transifex will pick up the modified files
automatically (checked every few hours) and update their online editor where
translators will be able to translate the new strings right in the browser.
Once your change gets merged, Transifex will pick up the modified files
automatically (checked every 24 hours) and update the interface where
translators will be able to translate the new strings.
### Releasing Translations (for maintainers) ###

View File

@@ -1,49 +0,0 @@
# Configuration options: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# # Enable version updates for git submodules
# Not yet possible to bump only on tags or releases, see:
# https://github.com/dependabot/dependabot-core/issues/1639
# https://github.com/dependabot/dependabot-core/issues/2192
# Alternative: Action that updates submodule and can be manually run on demand (workflow_dispatch)
# - package-ecosystem: "gitsubmodule"
# # Look for `.gitmodules` in the `root` directory
# directory: "/"
# # Check for updates once a month
# schedule:
# interval: "monthly"
# # Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
# open-pull-requests-limit: 1
# # Enable version updates for Docker
# Not yet possible to bump from one LTS version to the next and skip others, see:
# https://github.com/dependabot/dependabot-core/issues/2247
# - package-ecosystem: "docker"
# # Look for a `Dockerfile` in the `root` directory
# directory: "/"
# # Check for updates once a week
# schedule:
# interval: "weekly"
# # Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
# open-pull-requests-limit: 1
# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
# Directory must be set to "/" to check for workflow files in .github/workflows
directory: "/"
# Check for updates to GitHub Actions once a week
schedule:
interval: "weekly"
# Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
open-pull-requests-limit: 2
# # Enable version updates for npm
# - package-ecosystem: "npm"
# # Look for `package.json` and `lock` files in the `webclient` subdirectory
# directory: "/webclient"
# # Check the npm registry for updates once a week
# schedule:
# interval: "weekly"
# # Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
# open-pull-requests-limit: 5

View File

@@ -8,7 +8,6 @@ on:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
tags:
- '*'
pull_request:
@@ -16,12 +15,6 @@ on:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on master)
concurrency:
group: "${{ github.workflow }} @ ${{ github.ref_name }}"
cancel-in-progress: ${{ github.ref_name != 'master' }}
jobs:
configure:
@@ -30,8 +23,14 @@ jobs:
outputs:
tag: ${{steps.configure.outputs.tag}}
sha: ${{steps.configure.outputs.sha}}
upload_url: ${{steps.create_release.outputs.upload_url}}
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{github.token}} # needs other token https://github.com/styfle/cancel-workflow-action/issues/7
steps:
- name: Configure
id: configure
shell: bash
@@ -50,7 +49,7 @@ jobs:
- name: Checkout
if: steps.configure.outputs.tag != null
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
@@ -65,21 +64,15 @@ jobs:
- name: Create release
if: steps.configure.outputs.tag != null
id: create_release
shell: bash
uses: actions/create-release@v1
env:
GH_TOKEN: ${{github.token}}
tag_name: ${{steps.configure.outputs.tag}}
target: ${{steps.configure.outputs.sha}}
GITHUB_TOKEN: ${{github.token}}
with:
tag_name: ${{github.ref}}
release_name: ${{steps.prepare.outputs.title}}
body_path: ${{steps.prepare.outputs.body_path}}
prerelease: ${{steps.prepare.outputs.is_beta}}
run: |
if [[ $prerelease == yes ]]; then
args="--prerelease"
fi
gh release create "$tag_name" --draft --verify-tag $args \
--target "$target" --title "$release_name" \
--notes-file "$body_path"
draft: true
prerelease: ${{steps.prepare.outputs.is_beta == 'yes'}}
build-linux:
strategy:
@@ -91,16 +84,18 @@ jobs:
package: skip # we are packaged in arch already
allow-failure: yes
- distro: Debian10
package: DEB
test: skip # running tests on all distros is superfluous
- distro: Debian11
package: DEB
- distro: Debian12
package: DEB
- distro: Fedora39
- distro: Fedora35
package: RPM
test: skip
- distro: Fedora40
- distro: Fedora36
package: RPM
- distro: UbuntuBionic
@@ -112,10 +107,6 @@ jobs:
- distro: UbuntuJammy
package: DEB
test: skip # running tests on all distros is superfluous
- distro: UbuntuNoble
package: DEB
name: ${{matrix.distro}}
needs: configure
@@ -130,7 +121,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Get cache timestamp
id: cache_timestamp
@@ -138,7 +129,7 @@ jobs:
run: echo "timestamp=$(date -u '+%Y%m%d%H%M%S')" >>"$GITHUB_OUTPUT"
- name: Restore cache
uses: actions/cache@v4
uses: actions/cache@v3
env:
timestamp: ${{steps.cache_timestamp.outputs.timestamp}}
with:
@@ -158,10 +149,10 @@ jobs:
distro: '${{matrix.distro}}'
run: |
source .ci/docker.sh
RUN --server --debug --test --ccache "$CCACHE_SIZE" --parallel 4
RUN --server --debug --test --ccache "$CCACHE_SIZE" --parallel 2
- name: Build release package
id: build
id: package
if: matrix.package != 'skip'
shell: bash
env:
@@ -172,50 +163,73 @@ jobs:
run: |
source .ci/docker.sh
RUN --server --release --package "$type" --dir "$BUILD_DIR" \
--ccache "$CCACHE_SIZE" --parallel 4
--ccache "$CCACHE_SIZE" --parallel 2
.ci/name_build.sh
- name: Upload artifact
if: matrix.package != 'skip'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: ${{matrix.distro}}-package
path: ${{steps.build.outputs.path}}
path: ${{steps.package.outputs.path}}
if-no-files-found: error
- name: Upload to release
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
shell: bash
uses: actions/upload-release-asset@v1
env:
GH_TOKEN: ${{github.token}}
tag_name: ${{needs.configure.outputs.tag}}
asset_path: ${{steps.build.outputs.path}}
asset_name: ${{steps.build.outputs.name}}
run: gh release upload "$tag_name" "$asset_path#$asset_name"
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ${{steps.package.outputs.path}}
asset_name: ${{steps.package.outputs.name}}
asset_content_type: application/octet-stream
build-macos:
strategy:
fail-fast: false
matrix:
include:
- target: 12_Monterey_and_13_Ventura
os: macos-12
xcode: "14.0.1"
type: Release
make_package: 1
- target: 14_Sonoma
os: macos-14
xcode: "15.4"
type: Release
make_package: 1
- target: 14_Sonoma_Debug
os: macos-14
xcode: "15.4"
- target: Debug # tests only
os: macos-latest
xcode: 12.5.1
qt_version: 6
type: Debug
do_tests: 1
name: macOS${{matrix.target}}
- target: 10.14_Mojave
os: macos-10.15 # runs on Catalina
xcode: 10.3 # allows compatibility with macOS 10.14
qt_version: 5
type: Release
# do_tests: 1 # tests do not work on qt5?
make_package: 1
- target: 10.15_Catalina
os: macos-10.15
xcode: 12.4
qt_version: 6
type: Release
do_tests: 1
make_package: 1
- target: 11_Big_Sur
os: macos-11
xcode: 13.2
qt_version: 6
type: Release
do_tests: 1
make_package: 1
# - target: 12_Monterey
# os: macos-12
# xcode: 13.3
# qt_version: 6
# type: Release
# do_tests: 1
# make_package: 1
name: macOS ${{matrix.target}}
needs: configure
runs-on: ${{matrix.os}}
continue-on-error: ${{matrix.allow-failure == 'yes'}}
@@ -225,126 +239,140 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Install dependencies using Homebrew
- name: Install dependencies using homebrew
shell: bash
# cmake cannot find the mysql connector
# neither of these works: mariadb-connector-c mysql-connector-c++
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
qt_version: 'qt@${{matrix.qt_version}}'
run: |
brew update
brew install protobuf qt --force-bottle
brew install protobuf
brew install "$qt_version" --force-bottle
- name: Build on Xcode ${{matrix.xcode}}
shell: bash
id: build
env:
BUILDTYPE: '${{matrix.type}}'
MAKE_TEST: 1
MAKE_TEST: '${{matrix.do_tests}}'
MAKE_PACKAGE: '${{matrix.make_package}}'
PACKAGE_SUFFIX: '-macOS-${{matrix.target}}'
# macOS runner actually have only 3 cores
# See https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
# set QTDIR to find qt5, qt6 can be found without this
QTDIR: '/usr/local/opt/qt5'
# Mac machines actually have 3 cores
run: .ci/compile.sh --server --parallel 3
- name: Upload artifact
if: matrix.make_package
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: macOS-${{matrix.target}}-dmg
path: ${{steps.build.outputs.path}}
if-no-files-found: error
- name: Upload to release
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
shell: bash
if: matrix.make_package && needs.configure.outputs.tag != null
uses: actions/upload-release-asset@v1
env:
GH_TOKEN: ${{github.token}}
tag_name: ${{needs.configure.outputs.tag}}
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ${{steps.build.outputs.path}}
asset_name: ${{steps.build.outputs.name}}
run: gh release upload "$tag_name" "$asset_path#$asset_name"
asset_content_type: application/octet-stream
build-windows:
strategy:
fail-fast: false
matrix:
include:
- target: 7
- target: Win-32bit
bit: 32
arch: x86
cmake_generator_platform: Win32
qt_version: 5.15.*
qt_arch: msvc2019
qt_tools: "tools_openssl_x86"
- target: Win7+-64bit
bit: 64
arch: x64
cmake_generator_platform: x64
qt_version: 5.15.*
qt_arch: msvc2019_64
qt_tools: "tools_opensslv3_x64"
qt_tools: "tools_openssl_x64"
- target: 10
qt_version: 6.5.*
- target: Win10+-64bit
bit: 64
arch: x64
cmake_generator_platform: x64
qt_version: 6.3.*
qt_arch: msvc2019_64
qt_tools: "tools_opensslv3_x64"
qt_tools: "tools_openssl_x64"
qt_modules: "qtmultimedia qtwebsockets"
name: Windows ${{matrix.target}}
name: ${{matrix.target}}
needs: configure
runs-on: windows-2022
runs-on: windows-2019
env:
CMAKE_GENERATOR: 'Visual Studio 17 2022'
CMAKE_GENERATOR: 'Visual Studio 16 2019'
steps:
- name: Add msbuild to PATH
id: add-msbuild
uses: microsoft/setup-msbuild@v2
with:
msbuild-architecture: x64
uses: microsoft/setup-msbuild@v1.1
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install Qt ${{matrix.qt_version}}
- name: Install Qt ${{matrix.qt_version}} for ${{matrix.target}}
uses: jurplel/install-qt-action@v3
with:
cache: true
setup-python: false
version: ${{matrix.qt_version}}
arch: win64_${{matrix.qt_arch}}
arch: win${{matrix.bit}}_${{matrix.qt_arch}}
tools: ${{matrix.qt_tools}}
modules: ${{matrix.qt_modules}}
- name: Run vcpkg
uses: lukka/run-vcpkg@v11
uses: lukka/run-vcpkg@v10.6
with:
runVcpkgInstall: true
doNotCache: false
appendedCacheKey: ${{matrix.bit}}-bit
env:
VCPKG_DEFAULT_TRIPLET: 'x64-windows'
VCPKG_DEFAULT_TRIPLET: '${{matrix.arch}}-windows'
VCPKG_DISABLE_METRICS: 1
- name: Build Cockatrice
id: build
shell: bash
env:
PACKAGE_SUFFIX: '-Win${{matrix.target}}'
PACKAGE_SUFFIX: '-${{matrix.target}}'
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
CMAKE_GENERATOR_PLATFORM: 'x64'
QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win64_${{matrix.qt_arch}}'
# No need for --parallel flag, MTT is added in the compile script to let cmake/msbuild manage core count,
# project and process parallelism: https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
run: .ci/compile.sh --server --release --test --package
CMAKE_GENERATOR_PLATFORM: '${{matrix.cmake_generator_platform}}'
QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win${{matrix.bit}}_${{matrix.qt_arch}}'
run: .ci/compile.sh --server --release --test --package --parallel 2
- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: Windows${{matrix.target}}-installer
name: ${{matrix.target}}-installer
path: ${{steps.build.outputs.path}}
if-no-files-found: error
- name: Upload to release
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
shell: bash
if: needs.configure.outputs.tag != null
uses: actions/upload-release-asset@v1
env:
GH_TOKEN: ${{github.token}}
tag_name: ${{needs.configure.outputs.tag}}
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ${{steps.build.outputs.path}}
asset_name: ${{steps.build.outputs.name}}
run: gh release upload "$tag_name" "$asset_path#$asset_name"
asset_content_type: application/octet-stream

View File

@@ -6,7 +6,6 @@ on:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
jobs:
format:
@@ -14,7 +13,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 20 # should be enough to find merge base

View File

@@ -1,72 +0,0 @@
name: Update Translations
on:
workflow_dispatch:
schedule:
# runs in the middle of each month starting a quarter (UTC) = two weeks after new strings are built
- cron: '0 0 15 1,4,7,10 *'
pull_request:
paths:
- '.github/workflows/translations-pull.yml'
jobs:
translations:
# Do not run the scheduled workflow on forks
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
name: Pull languages
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Pull translated strings from Transifex
uses: transifex/cli-action@v2
with:
# used config file: https://github.com/Cockatrice/Cockatrice/blob/master/.tx/config
# https://github.com/transifex/cli#pulling-files-from-transifex
token: ${{ secrets.TX_TOKEN }}
args: pull --force --all
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v6
with:
add-paths: |
cockatrice/translations/*.ts
oracle/translations/*.ts
webclient/public/locales/*/translation.json
commit-message: Update translation files
# author is the owner of the commit
author: github-actions <github-actions@github.com>
branch: ci-update_translations
delete-branch: true
title: 'Update translations'
body: |
Pulled all translated strings from [Transifex][1].
---
*This PR is automatically generated and updated by the workflow at `.github/workflows/translations-pull.yml`. Review [action runs][2].*<br>
*After merging, all new languages and translations are available in the next build.*
[1]: https://app.transifex.com/cockatrice/cockatrice/
[2]: https://github.com/Cockatrice/Cockatrice/actions/workflows/translations-pull.yml?query=branch%3Amaster
labels: |
CI
Translation
draft: false
- name: PR Status
if: github.event_name != 'pull_request'
shell: bash
env:
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
if [[ "$STATUS" == "" ]]; then
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!" >> $GITHUB_STEP_SUMMARY
else
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!" >> $GITHUB_STEP_SUMMARY
fi
echo "URL: ${{ steps.create_pr.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY

View File

@@ -1,87 +0,0 @@
name: Update Translation Source
on:
workflow_dispatch:
schedule:
# runs at the start of each quarter (UTC)
- cron: '0 0 1 1,4,7,10 *'
pull_request:
paths:
- '.github/workflows/translations-push.yml'
jobs:
translations:
# Do not run the scheduled workflow on forks
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
name: Push strings
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Install lupdate
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
- name: Update Cockatrice translation source
id: cockatrice
shell: bash
env:
FILE: 'cockatrice/cockatrice_en@source.ts'
DIRS: 'cockatrice/src common'
run: .ci/update_translation_source_strings.sh
- name: Update Oracle translation source
id: oracle
shell: bash
env:
FILE: 'oracle/oracle_en@source.ts'
DIRS: 'oracle/src'
run: .ci/update_translation_source_strings.sh
- name: Render template
id: template
uses: chuhlomin/render-template@v1
with:
template: .ci/update_translation_source_strings_template.md
vars: |
cockatrice_output: ${{ steps.cockatrice.outputs.output }}
oracle_output: ${{ steps.oracle.outputs.output }}
commit: ${{ github.sha }}
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v6
with:
add-paths: |
cockatrice/cockatrice_en@source.ts
oracle/oracle_en@source.ts
commit-message: Update translation source strings
# author is the owner of the commit
author: github-actions <github-actions@github.com>
branch: ci-update_translation_source
delete-branch: true
title: 'Update source strings'
body: ${{ steps.template.outputs.result }}
labels: |
CI
Translation
draft: false
- name: PR Status
if: github.event_name != 'pull_request'
shell: bash
env:
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
if [[ "$STATUS" == "" ]]; then
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!" >> $GITHUB_STEP_SUMMARY
else
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!" >> $GITHUB_STEP_SUMMARY
fi
echo "URL: ${{ steps.create_pr.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY

66
.github/workflows/translations.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Update translation source
on:
workflow_dispatch:
schedule:
# runs once per month
- cron: '0 0 1 * *'
jobs:
translations:
# Do not run the scheduled workflow on forks
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
runs-on: ubuntu-latest
steps:
- name: Install lupdate
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
- name: Checkout repo
uses: actions/checkout@v3
- name: Update cockatrice translations
shell: bash
run: |
shopt -s globstar # globstar is needed for recursive **
lupdate -version
echo "reading the following source files:"
# note: there are three strings to translate in common right now
echo {cockatrice,common}/**/*.{cpp,h}
echo "$(echo {cockatrice,common}/**/*.{cpp,h} | wc -w) files total"
lupdate {cockatrice,common}/**/*.{cpp,h} -ts cockatrice/translations/cockatrice_en@source.ts
- name: Update oracle translations
shell: bash
run: |
shopt -s globstar # globstar is needed for recursive **
lupdate -version
echo "reading the following source files:"
echo oracle/**/*.{cpp,h}
echo "$(echo oracle/**/*.{cpp,h} | wc -w) files total"
lupdate oracle/**/*.{cpp,h} -ts oracle/translations/oracle_en@source.ts
- name: Check for updates
id: check
shell: bash
run: |
set +e # do not fail, just save the exit state
git diff --exit-code
echo "deploy=$?" >>"$GITHUB_OUTPUT"
- name: Commit changes
if: steps.check.outputs.deploy == '1'
shell: bash
working-directory: ${{env.OUTPUT_PATH}}
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add cockatrice/translations/cockatrice_en@source.ts oracle/translations/oracle_en@source.ts
git commit -m "Automated translation update ( $GITHUB_SHA )"
git push
deploy_commit=$(git rev-parse HEAD)
echo "Created commit: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$deploy_commit"

View File

@@ -33,10 +33,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v2
with:
node-version: ${{matrix.node_version}}
cache: 'npm'
@@ -50,3 +50,4 @@ jobs:
- name: Test app
run: npm run test

View File

@@ -17,10 +17,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v2
with:
cache: 'npm'
cache-dependency-path: 'webclient/package-lock.json'

2
.gitignore vendored
View File

@@ -11,5 +11,3 @@ preferences
compile_commands.json
.vs/
.vscode/
.cache
.gdb_history

View File

@@ -1,26 +1,13 @@
[main]
host = https://app.transifex.com
host = https://www.transifex.com
[o:cockatrice:p:cockatrice:r:cockatrice-cockatrice-en-source-ts--master]
resource_name = Cockatrice
source_lang = en
source_file = cockatrice/cockatrice_en@source.ts
[cockatrice.cockatrice-translations-cockatrice-en-source-ts--master]
file_filter = cockatrice/translations/cockatrice_<lang>.ts
type = QT
minimum_perc = 10
[o:cockatrice:p:cockatrice:r:oracle-oracle-en-source-ts--master]
resource_name = Oracle
source_file = cockatrice/translations/cockatrice_en@source.ts
source_lang = en
source_file = oracle/oracle_en@source.ts
[cockatrice.oracle-translations-oracle-en-source-ts--master]
file_filter = oracle/translations/oracle_<lang>.ts
type = QT
minimum_perc = 10
[o:cockatrice:p:cockatrice:r:webclient-src-i18n-default-json--master]
resource_name = Webclient
source_file = oracle/translations/oracle_en@source.ts
source_lang = en
source_file = webclient/src/i18n-default.json
file_filter = webclient/public/locales/<lang>/translation.json
type = KEYVALUEJSON
minimum_perc = 10

View File

@@ -74,11 +74,11 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
project("Cockatrice" VERSION 2.9.1)
project("Cockatrice" VERSION 2.8.1)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)
set(GIT_TAG_RELEASENAME "Rings of the Wild")
set(GIT_TAG_RELEASENAME "Prismatic Bridge")
endif()
# Use c++17 for all targets
@@ -141,7 +141,7 @@ endif()
# Define proper compilation flags
if(MSVC)
# Visual Studio: Maximum optimization, disable warning C4251, establish C++17 compatibility
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 /Zc:__cplusplus /std:c++17 /permissive- /W4")
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 /Zc:__cplusplus /std:c++17 /permissive-")
# Generate complete debugging information
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
elseif(CMAKE_COMPILER_IS_GNUCXX)
@@ -179,7 +179,7 @@ else()
# other: osx/llvm, bsd/llvm
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
if(WARNING_AS_ERROR)
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra -Werror -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra -Werror")
else()
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra")
endif()
@@ -216,26 +216,16 @@ include(FindQtRuntime)
set(CMAKE_AUTOMOC TRUE)
# Find other needed libraries
find_package(Protobuf CONFIG)
if(NOT Protobuf_FOUND)
find_package(Protobuf REQUIRED)
endif()
if(${Protobuf_VERSION} VERSION_LESS "3.21.0.0" AND NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
find_package(Protobuf REQUIRED)
if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
message(FATAL_ERROR "No protoc command found!")
else()
message(STATUS "Found Protobuf ${Protobuf_VERSION} at: ${Protobuf_LIBRARIES}")
endif()
#Find OpenSSL
if(WIN32)
find_package(OpenSSL REQUIRED)
if(OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIRS})
else()
message(
WARNING
"Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime."
)
endif()
find_package(Win32SslRuntime)
endif()
#Find VCredist
@@ -262,8 +252,6 @@ if(UNIX)
set(CPACK_DMG_VOLUME_NAME "${PROJECT_NAME}")
set(CPACK_SYSTEM_NAME "OSX")
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cockatrice/resources/appicon.icns")
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeDMGSetup.script")
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/dmgBackground.tif")
else()
# linux
if(CPACK_GENERATOR STREQUAL "RPM")

View File

@@ -40,7 +40,7 @@ Downloads are available for full releases and the current beta version in develo
- To be a Cockatrice Beta Tester, use this version. Find more information [here](https://github.com/Cockatrice/Cockatrice/wiki/Release-Channels)!
# Get Involved [![Discord](https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white)](https://discord.gg/3Z9yzmA)
# Get Involved [![Discord](https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white)](https://discord.gg/3Z9yzmA) [![Gitter Chat](https://img.shields.io/gitter/room/Cockatrice/Cockatrice)](https://gitter.im/Cockatrice/Cockatrice)
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with the project or fellow users of the app. The Cockatrice developers are also available on [Gitter](https://gitter.im/Cockatrice/Cockatrice). Come here to talk about the application, features, or just to hang out.<br>
For support regarding specific servers, please contact that server's admin or forum for support rather than asking here.<br>
@@ -65,9 +65,13 @@ Cockatrice uses the [Google Developer Documentation Style Guide](https://develop
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
# Translations [![Transifex Project](https://img.shields.io/badge/translate-on%20transifex-brightgreen)](https://transifex.com/cockatrice/cockatrice/)
# Translations [![Transifex Project](https://img.shields.io/badge/translate-on%20transifex-brightgreen)](https://www.transifex.com/projects/p/cockatrice/)
Cockatrice uses Transifex for translations. You can help us bring Cockatrice, Oracle and Webatrice to your language or just adjust single wordings right from within your browser by visiting our [Transifex project page](https://transifex.com/cockatrice/cockatrice/).<br>
Cockatrice uses Transifex for translations. You can help us bring Cockatrice and Oracle to your language or just edit single wordings right from within your browser by visiting our [Transifex project page](https://www.transifex.com/projects/p/cockatrice/).<br>
| Cockatrice | Oracle |
|:-:|:-:|
| [![Cockatrice Translation Status](https://www.transifex.com/projects/p/cockatrice/resource/cockatrice/chart/image_png/)](https://www.transifex.com/projects/p/cockatrice/) | [![Oracle Translation Status](https://www.transifex.com/projects/p/cockatrice/resource/oracle/chart/image_png/)](https://www.transifex.com/projects/p/cockatrice/) |
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about contributing!<br>

View File

@@ -1,55 +0,0 @@
on run argv
set image_name to item 1 of argv
tell application "Finder"
tell disk image_name
-- wait for the image to finish mounting
set open_attempts to 0
repeat while open_attempts < 4
try
open
delay 1
set open_attempts to 5
close
on error errStr number errorNumber
set open_attempts to open_attempts + 1
delay 10
end try
end repeat
delay 5
-- open the image the first time and save a DS_Store with just
-- background and icon setup
open
set current view of container window to icon view
set theViewOptions to the icon view options of container window
set background picture of theViewOptions to file ".background:background.tif"
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128
delay 5
close
-- next setup the position of the app and Applications symlink
-- plus hide all the window decoration
open
update without registering applications
tell container window
set sidebar width to 0
set statusbar visible to false
set toolbar visible to false
set the bounds to { 400, 100, 1400, 922 }
set position of item "Cockatrice.app" to { 139, 214 }
set position of item "Oracle.app" to { 139, 414 }
set position of item "Servatrice.app" to { 139, 614 }
set position of item "dbconverter.app" to { 1400, 1400 }
set position of item "Applications" to { 861, 414 }
end tell
update without registering applications
delay 5
close
end tell
delay 1
end tell
end run

View File

@@ -9,8 +9,7 @@ if(WIN32)
set(REDIST_ARCH x86)
endif()
# VS 2017 uses vcredist_ARCH.exe, VS 2022 uses vc_redist.ARCH.exe
set(REDIST_FILE_NAMES vcredist_${REDIST_ARCH}.exe vcredist.${REDIST_ARCH}.exe vc_redist.${REDIST_ARCH}.exe)
set(REDIST_FILE vc_redist.${REDIST_ARCH}.exe)
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
include(InstallRequiredSystemLibraries)
@@ -23,20 +22,18 @@ if(WIN32)
get_filename_component(_path ${_path} DIRECTORY)
get_filename_component(_path ${_path}/../../ ABSOLUTE)
foreach(redist_file ${REDIST_FILE_NAMES})
if(EXISTS "${_path}/${redist_file}")
set(VCREDISTRUNTIME_FOUND "YES")
set(VCREDISTRUNTIME_FILE ${_path}/${redist_file})
break()
endif()
endforeach()
if(EXISTS "${_path}/${REDIST_FILE}") # VS 2017
set(VCREDISTRUNTIME_FOUND "YES")
set(VCREDISTRUNTIME_FILE ${_path}/${REDIST_FILE})
endif()
endif()
if(VCREDISTRUNTIME_FOUND)
message(STATUS "Found VCredist ${VCREDISTRUNTIME_FILE}")
else()
message(
WARNING "Could not find VCredist package. It's not required for compiling, but needs to be available at runtime."
WARNING
"Could not find VCredist package in \"${_path}/${REDIST_FILE}\". It's not required for compiling, but needs to be available at runtime."
)
endif()
endif()

View File

@@ -0,0 +1,81 @@
# Find the OpenSSL runtime libraries (.dll) for Windows that
# will be needed by Qt in order to access https urls.
if(NOT DEFINED WIN32 OR NOT ${WIN32})
message(STATUS "Non-Windows device trying to execute FindWin32SslRuntime, skipping")
return()
endif()
if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64")
message(STATUS "Looking for OpenSSL for ${CMAKE_GENERATOR_PLATFORM}")
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
set(_OPENSSL_ROOT_PATHS
"$ENV{VCPKG_PACKAGES_DIR}/x64-windows/bin"
"C:/OpenSSL-Win64/bin"
"C:/OpenSSL-Win64"
"C:/Tools/vcpkg/installed/x64-windows/bin"
"${_programfiles}/OpenSSL-Win64"
"D:/a/Cockatrice/Qt/Tools/OpenSSL/Win_x64/bin"
expanduser
("~/Documents/Development/Qt/Tools/OpenSSL/Win_x64/bin")
)
unset(_programfiles)
elseif("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32")
message(STATUS "Looking for OpenSSL for ${CMAKE_GENERATOR_PLATFORM}")
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
set(_OPENSSL_ROOT_PATHS
"$ENV{VCPKG_PACKAGES_DIR}/x86-windows/bin"
"C:/OpenSSL-Win32/bin"
"C:/OpenSSL-Win32"
"C:/OpenSSL"
"C:/Tools/vcpkg/installed/x86-windows/bin"
"${_programfiles}/OpenSSL"
"${_programfiles}/OpenSSL-Win32"
"D:/a/Cockatrice/Qt/Tools/OpenSSL/Win_x86/bin"
expanduser
("~/Documents/Development/Qt/Tools/OpenSSL/Win_x86/bin")
)
unset(_programfiles)
endif()
message(STATUS "Looking for OpenSSL @ ${CMAKE_GENERATOR_PLATFORM} in ${_OPENSSL_ROOT_PATHS}")
if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64")
find_file(
WIN32SSLRUNTIME_LIBEAY
NAMES libcrypto-1_1-x64.dll libcrypto.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
find_file(
WIN32SSLRUNTIME_SSLEAY
NAMES libssl-1_1-x64.dll libssl.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
elseif("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32")
find_file(
WIN32SSLRUNTIME_LIBEAY
NAMES libcrypto-1_1.dll libcrypto.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
find_file(
WIN32SSLRUNTIME_SSLEAY
NAMES libssl-1_1.dll libssl.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
endif()
if(WIN32SSLRUNTIME_LIBEAY AND WIN32SSLRUNTIME_SSLEAY)
set(WIN32SSLRUNTIME_LIBRARIES "${WIN32SSLRUNTIME_LIBEAY}" "${WIN32SSLRUNTIME_SSLEAY}")
set(WIN32SSLRUNTIME_FOUND "YES")
message(STATUS "Found OpenSSL ${WIN32SSLRUNTIME_LIBRARIES}")
else()
set(WIN32SSLRUNTIME_FOUND "NO")
message(
WARNING
"Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime."
)
endif()
mark_as_advanced(WIN32SSLRUNTIME_LIBEAY WIN32SSLRUNTIME_SSLEAY)

View File

@@ -248,20 +248,20 @@ ${If} $PortableMode = 0
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "VersionMajor" "@CPACK_PACKAGE_VERSION_MAJOR@"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "VersionMinor" "@CPACK_PACKAGE_VERSION_MINOR@"
IfFileExists "$INSTDIR\vc_redist.x86.exe" VcRedist86Exists PastVcRedist86Check
IfFileExists "$INSTDIR\vcredist_x86.exe" VcRedist86Exists PastVcRedist86Check
VcRedist86Exists:
ExecWait '"$INSTDIR\vc_redist.x86.exe" /passive /norestart'
ExecWait '"$INSTDIR\vcredist_x86.exe" /passive /norestart'
DetailPrint "Wait to ensure unlock of vc_redist file after installation..."
Sleep 3000
Delete "$INSTDIR\vc_redist.x86.exe"
Delete "$INSTDIR\vcredist_x86.exe"
PastVcRedist86Check:
IfFileExists "$INSTDIR\vc_redist.x64.exe" VcRedist64Exists PastVcRedist64Check
IfFileExists "$INSTDIR\vcredist_x64.exe" VcRedist64Exists PastVcRedist64Check
VcRedist64Exists:
ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart'
ExecWait '"$INSTDIR\vcredist_x64.exe" /passive /norestart'
DetailPrint "Sleep to ensure unlock of vc_redist file after installation..."
Sleep 3000
Delete "$INSTDIR\vc_redist.x64.exe"
Delete "$INSTDIR\vcredist_x64.exe"
PastVcRedist64Check:
${Else}

Binary file not shown.

19
cmake/expanduser.cmake Normal file
View File

@@ -0,0 +1,19 @@
# expands ~ to user home directory
#
# usage:
# expanduser("~/code" x)
function(expanduser in outvar)
if(CMAKE_VERSION VERSION_LESS 3.21)
get_filename_component(out ${in} ABSOLUTE)
else()
file(REAL_PATH ${in} out EXPAND_TILDE)
endif()
set(${outvar}
${out}
PARENT_SCOPE
)
endfunction(expanduser)

View File

@@ -48,7 +48,6 @@ set(cockatrice_SOURCES
src/dlg_load_remote_deck.cpp
src/dlg_manage_sets.cpp
src/dlg_register.cpp
src/dlg_roll_dice.cpp
src/dlg_settings.cpp
src/dlg_tip_of_the_day.cpp
src/dlg_update.cpp
@@ -312,9 +311,15 @@ if(WIN32)
PATTERN "audio/qtaudio_wasapi.dll"
PATTERN "audio/qtaudio_windows.dll"
PATTERN "iconengines/qsvgicon.dll"
PATTERN "imageformats/*.dll"
PATTERN "mediaservice/dsengine.dll"
PATTERN "mediaservice/wmfengine.dll"
PATTERN "imageformats/qgif.dll"
PATTERN "imageformats/qicns.dll"
PATTERN "imageformats/qico.dll"
PATTERN "imageformats/qjpeg.dll"
PATTERN "imageformats/qsvg.dll"
PATTERN "imageformats/qtga.dll"
PATTERN "imageformats/qtiff.dll"
PATTERN "imageformats/qwbmp.dll"
PATTERN "imageformats/qwebp.dll"
PATTERN "platforms/qdirect2d.dll"
PATTERN "platforms/qminimal.dll"
PATTERN "platforms/qoffscreen.dll"
@@ -350,8 +355,8 @@ Data = Resources\")
COMPONENT Runtime
)
if(OPENSSL_FOUND)
install(FILES ${OPENSSL_INCLUDE_DIRS} DESTINATION ./)
if(WIN32SSLRUNTIME_FOUND)
install(FILES ${WIN32SSLRUNTIME_LIBRARIES} DESTINATION ./)
endif()
endif()

View File

@@ -351,10 +351,10 @@
<file>resources/tips/images/cockatrice_wiki.png</file>
<file>resources/tips/images/coin_flip.png</file>
<file>resources/tips/images/counter_expression.png</file>
<file>resources/tips/images/discord.png</file>
<file>resources/tips/images/face_down.png</file>
<file>resources/tips/images/filter_games.png</file>
<file>resources/tips/images/github_logo.png</file>
<file>resources/tips/images/gitter.png</file>
<file>resources/tips/images/setpt.png</file>
<file>resources/tips/images/shortcuts.png</file>
<file>resources/tips/images/themes.png</file>

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,7 +1,6 @@
## Search Syntax Help
## Syntax Help
-----
The search bar recognizes a set of special commands similar to some other card databases.<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.
The search bar recognizes a set of special commands similar to some other card databases. Here is a list with examples. Each entry can be clicked to test the query and has a small explanation. Note that all searches are case insensitive.
<dl>
<dt>Name:</dt>
<dd>[birds of paradise](#birds of paradise) <small>(Any card name containing the words birds, of, and paradise)</small></dd>
@@ -47,7 +46,8 @@ In this list of examples below, each entry has an explanation and can be clicked
<dt><u>E</u>dition:</dt>
<dd>[set:lea](#set:lea) <small>(Cards that appear in Alpha, which has the set code LEA)</small></dd>
<dd>[e:lea or e:leb](#e:lea or e:leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
<dd>[e:lea,leb](#e:lea,leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
<dd><a href="#e:lea,leb -(e:lea e:leb)">e:lea,leb -(e:lea e:leb)</a> <small>(Cards that appear in Alpha or Beta but not in both editions)</small></dd>
<dt>Negate:</dt>
<dd>[c:wu -c:m](#c:wu -c:m) <small>(Any card that is white or blue, but not multicolored)</small></dd>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -7,9 +7,9 @@
</tip>
<tip>
<title>Suggesting New Tips</title>
<text>You can suggest new Tips of the Day by reaching out to the development team on &lt;a href="https://discord.gg/3Z9yzmA"&gt;Discord&lt;/a&gt;!</text>
<image>discord.png</image>
<date>2023-10-18</date>
<text>You can suggest new Tips of the Day by reaching out to the development team on &lt;a href="https://gitter.im/cockatrice/cockatrice"&gt;Gitter&lt;/a&gt;!</text>
<image>gitter.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Reporting Bugs</title>

View File

@@ -20,8 +20,13 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
parentDrag->addChildDrag(this);
setZValue(2000000007 + hotSpot.x() * 1000000 + hotSpot.y() * 1000 + 1000);
} else {
hotSpot = QPointF{qBound(0.0, hotSpot.x(), static_cast<qreal>(CARD_WIDTH - 1)),
qBound(0.0, hotSpot.y(), static_cast<qreal>(CARD_HEIGHT - 1))};
if ((hotSpot.x() < 0) || (hotSpot.y() < 0)) {
qDebug() << "CardDragItem: coordinate overflow: x =" << hotSpot.x() << ", y =" << hotSpot.y();
hotSpot = QPointF();
} else if ((hotSpot.x() > CARD_WIDTH) || (hotSpot.y() > CARD_HEIGHT)) {
qDebug() << "CardDragItem: coordinate overflow: x =" << hotSpot.x() << ", y =" << hotSpot.y();
hotSpot = QPointF(CARD_WIDTH, CARD_HEIGHT);
}
setCursor(Qt::ClosedHandCursor);
setZValue(2000000007);
}
@@ -40,19 +45,12 @@ AbstractCardDragItem::~AbstractCardDragItem()
delete childDrags[i];
}
QPainterPath AbstractCardDragItem::shape() const
{
QPainterPath shape;
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
return shape;
}
void AbstractCardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
item->paint(painter, option, widget);
// adds a mask to the card so it looks like the card hasnt been placed yet
painter->fillPath(shape(), GHOST_MASK);
painter->fillRect(boundingRect(), GHOST_MASK);
}
void AbstractCardDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)

View File

@@ -21,18 +21,17 @@ public:
{
Type = typeCardDrag
};
int type() const override
int type() const
{
return Type;
}
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
~AbstractCardDragItem();
QRectF boundingRect() const override
QRectF boundingRect() const
{
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
}
QPainterPath shape() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
AbstractCardItem *getItem() const
{
return item;
@@ -45,7 +44,7 @@ public:
virtual void updatePosition(const QPointF &cursorScenePos) = 0;
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
};
#endif

View File

@@ -34,13 +34,6 @@ QRectF AbstractCardItem::boundingRect() const
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
}
QPainterPath AbstractCardItem::shape() const
{
QPainterPath shape;
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
return shape;
}
void AbstractCardItem::pixmapUpdated()
{
update();
@@ -120,14 +113,24 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
if (paintImage) {
painter->save();
painter->setClipPath(shape());
painter->drawPixmap(boundingRect(), translatedPixmap, QRectF({0, 0}, translatedPixmap.size()));
transformPainter(painter, translatedSize, angle);
painter->drawPixmap(QPointF(1, 1), translatedPixmap);
painter->restore();
} else {
painter->setBrush(bgColor);
painter->drawPath(shape());
}
QPen pen(Qt::black);
pen.setJoinStyle(Qt::MiterJoin);
const int penWidth = 2;
pen.setWidth(penWidth);
painter->setPen(pen);
if (!angle)
painter->drawRect(QRectF(0, 0, CARD_WIDTH - 1, CARD_HEIGHT - penWidth));
else
painter->drawRect(QRectF(1, 1, CARD_WIDTH - 2, CARD_HEIGHT - 1.5));
if (translatedPixmap.isNull() || SettingsCache::instance().getDisplayCardNames() || facedown) {
painter->save();
transformPainter(painter, translatedSize, angle);
@@ -155,7 +158,9 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
QSizeF translatedSize = getTranslatedSize(painter);
paintPicture(painter, translatedSize, tapAngle);
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
transformPainter(painter, translatedSize, tapAngle);
if (isSelected() || isHovered) {
QPen pen;
@@ -163,12 +168,15 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
pen.setColor(Qt::yellow);
if (isSelected())
pen.setColor(Qt::red);
pen.setWidth(0); // Cosmetic pen
const int penWidth = 1;
pen.setWidth(penWidth);
painter->setPen(pen);
painter->drawPath(shape());
painter->drawRect(QRectF(0, 0, translatedSize.width() + penWidth, translatedSize.height() - penWidth));
}
painter->restore();
painter->restore();
}
void AbstractCardItem::setName(const QString &_name)

View File

@@ -44,7 +44,7 @@ public:
{
Type = typeCard
};
int type() const override
int type() const
{
return Type;
}
@@ -53,11 +53,10 @@ public:
int _id = -1,
QGraphicsItem *parent = nullptr);
~AbstractCardItem();
QRectF boundingRect() const override;
QPainterPath shape() const override;
QRectF boundingRect() const;
QSizeF getTranslatedSize(QPainter *painter) const;
void paintPicture(QPainter *painter, const QSizeF &translatedSize, int angle);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
CardInfoPtr getInfo() const
{
return info;
@@ -104,9 +103,9 @@ public:
protected:
void transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle);
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
void cacheBgColor();
};

View File

@@ -1,5 +1,6 @@
#include "abstractclient.h"
#include "client_metatypes.h"
#include "featureset.h"
#include "get_pb_extension.h"
#include "pb/commands.pb.h"

View File

@@ -266,14 +266,9 @@ CardInfoPtr CardInfo::newInstance(const QString &_name,
QString CardInfo::getCorrectedName() const
{
// remove all the characters reserved in windows file paths,
// other oses only disallow a subset of these so it covers all
static const QRegularExpression rmrx(R"(( // |[*<>:"\\?\x00-\x08\x10-\x1f]))");
static const QRegularExpression spacerx(R"([/\x09-\x0f])");
static const QString space(' ');
QString result = name;
// Fire // Ice, Circle of Protection: Red, "Ach! Hans, Run!", Who/What/When/Where/Why, Question Elemental?
return result.remove(rmrx).replace(spacerx, space);
return result.remove(" // ").remove(':').remove('"').remove('?').replace('/', ' ');
}
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
@@ -592,9 +587,9 @@ void CardDatabase::refreshCachedReverseRelatedCards()
continue;
}
auto *newCardRelation = new CardRelation(
card->getName(), cardRelation->getAttachType(), cardRelation->getIsCreateAllExclusion(),
cardRelation->getIsVariable(), cardRelation->getDefaultCount(), cardRelation->getIsPersistent());
auto *newCardRelation = new CardRelation(card->getName(), cardRelation->getDoesAttach(),
cardRelation->getIsCreateAllExclusion(),
cardRelation->getIsVariable(), cardRelation->getDefaultCount());
cards.value(targetCard)->addReverseRelatedCards2Me(newCardRelation);
}
}
@@ -612,22 +607,22 @@ QStringList CardDatabase::getAllMainCardTypes() const
void CardDatabase::checkUnknownSets()
{
auto _sets = getSetList();
SetList sets = getSetList();
if (_sets.getEnabledSetsNum()) {
if (sets.getEnabledSetsNum()) {
// if some sets are first found on this run, ask the user
int numUnknownSets = _sets.getUnknownSetsNum();
QStringList unknownSetNames = _sets.getUnknownSetsNames();
int numUnknownSets = sets.getUnknownSetsNum();
QStringList unknownSetNames = sets.getUnknownSetsNames();
if (numUnknownSets > 0) {
emit cardDatabaseNewSetsFound(numUnknownSets, unknownSetNames);
} else {
_sets.markAllAsKnown();
sets.markAllAsKnown();
}
} else {
// No set enabled. Probably this is the first time running trice
_sets.guessSortKeys();
_sets.sortByKey();
_sets.enableAll();
sets.guessSortKeys();
sets.sortByKey();
sets.enableAll();
notifyEnabledSetsChanged();
emit cardDatabaseAllNewSetsEnabled();
@@ -636,14 +631,14 @@ void CardDatabase::checkUnknownSets()
void CardDatabase::enableAllUnknownSets()
{
auto _sets = getSetList();
_sets.enableAllUnknown();
SetList sets = getSetList();
sets.enableAllUnknown();
}
void CardDatabase::markAllSetsAsKnown()
{
auto _sets = getSetList();
_sets.markAllAsKnown();
SetList sets = getSetList();
sets.markAllAsKnown();
}
void CardDatabase::notifyEnabledSetsChanged()
@@ -677,12 +672,12 @@ bool CardDatabase::saveCustomTokensToFile()
}
CardRelation::CardRelation(const QString &_name,
AttachType _attachType,
bool _doesAttach,
bool _isCreateAllExclusion,
bool _isVariableCount,
int _defaultCount,
bool _isPersistent)
: name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion),
: name(_name), doesAttach(_doesAttach), isCreateAllExclusion(_isCreateAllExclusion),
isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent)
{
}

View File

@@ -452,17 +452,9 @@ signals:
class CardRelation : public QObject
{
Q_OBJECT
public:
enum AttachType
{
DoesNotAttach = 0,
AttachTo = 1,
TransformInto = 2,
};
private:
QString name;
AttachType attachType;
bool doesAttach;
bool isCreateAllExclusion;
bool isVariableCount;
int defaultCount;
@@ -470,7 +462,7 @@ private:
public:
explicit CardRelation(const QString &_name = QString(),
AttachType _attachType = DoesNotAttach,
bool _doesAttach = false,
bool _isCreateAllExclusion = false,
bool _isVariableCount = false,
int _defaultCount = 1,
@@ -480,32 +472,13 @@ public:
{
return name;
}
AttachType getAttachType() const
{
return attachType;
}
bool getDoesAttach() const
{
return attachType != DoesNotAttach;
}
bool getDoesTransform() const
{
return attachType == TransformInto;
}
QString getAttachTypeAsString() const
{
switch (attachType) {
case AttachTo:
return "attach";
case TransformInto:
return "transform";
default:
return "";
}
return doesAttach;
}
bool getCanCreateAnother() const
{
return !getDoesAttach();
return !doesAttach;
}
bool getIsCreateAllExclusion() const
{

View File

@@ -326,12 +326,12 @@ void CardDatabaseDisplayModel::clearFilterAll()
invalidateFilter();
}
void CardDatabaseDisplayModel::setFilterTree(FilterTree *_filterTree)
void CardDatabaseDisplayModel::setFilterTree(FilterTree *filterTree)
{
if (this->filterTree != nullptr)
disconnect(this->filterTree, nullptr, this, nullptr);
this->filterTree = _filterTree;
this->filterTree = filterTree;
connect(this->filterTree, SIGNAL(changed()), this, SLOT(filterTreeChanged()));
invalidate();
}

View File

@@ -82,7 +82,7 @@ private:
public:
explicit CardDatabaseDisplayModel(QObject *parent = nullptr);
void setFilterTree(FilterTree *_filterTree);
void setFilterTree(FilterTree *filterTree);
void setIsToken(FilterBool _isToken)
{
isToken = _isToken;

View File

@@ -155,7 +155,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
QVariantHash properties = QVariantHash();
QString colors = QString("");
QList<CardRelation *> relatedCards, reverseRelatedCards;
auto _sets = CardInfoPerSetMap();
CardInfoPerSetMap sets = CardInfoPerSetMap();
int tableRow = 0;
bool cipt = false;
bool isToken = false;
@@ -221,10 +221,10 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
if (attrs.hasAttribute("rarity")) {
setInfo.setProperty("rarity", attrs.value("rarity").toString());
}
_sets.insert(setName, setInfo);
sets.insert(setName, setInfo);
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {
CardRelation::AttachType attach = CardRelation::DoesNotAttach;
bool attach = false;
bool exclude = false;
bool variable = false;
int count = 1;
@@ -246,7 +246,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
if (attrs.hasAttribute("attach")) {
attach = CardRelation::AttachTo;
attach = true;
}
if (attrs.hasAttribute("exclude")) {
@@ -268,7 +268,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
properties.insert("colors", colors);
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
reverseRelatedCards, _sets, cipt, tableRow, upsideDown);
reverseRelatedCards, sets, cipt, tableRow, upsideDown);
emit addCard(newCard);
}
}
@@ -412,7 +412,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml;
}
bool CockatriceXml3Parser::saveToFile(SetNameMap _sets,
bool CockatriceXml3Parser::saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl,
@@ -439,9 +439,9 @@ bool CockatriceXml3Parser::saveToFile(SetNameMap _sets,
xml.writeTextElement("sourceVersion", sourceVersion);
xml.writeEndElement();
if (_sets.count() > 0) {
if (sets.count() > 0) {
xml.writeStartElement("sets");
for (CardSetPtr set : _sets) {
for (CardSetPtr set : sets) {
xml << set;
}
xml.writeEndElement();
@@ -459,4 +459,4 @@ bool CockatriceXml3Parser::saveToFile(SetNameMap _sets,
xml.writeEndDocument();
return true;
}
}

View File

@@ -14,7 +14,7 @@ public:
~CockatriceXml3Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap _sets,
bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",

View File

@@ -134,7 +134,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
QString text = QString("");
QVariantHash properties = QVariantHash();
QList<CardRelation *> relatedCards, reverseRelatedCards;
auto _sets = CardInfoPerSetMap();
CardInfoPerSetMap sets = CardInfoPerSetMap();
int tableRow = 0;
bool cipt = false;
bool isToken = false;
@@ -178,11 +178,11 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
attrName = "picurl";
setInfo.setProperty(attrName, attr.value().toString());
}
_sets.insert(setName, setInfo);
sets.insert(setName, setInfo);
}
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {
CardRelation::AttachType attachType = CardRelation::DoesNotAttach;
bool attach = false;
bool exclude = false;
bool variable = false;
bool persistent = false;
@@ -205,8 +205,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
if (attrs.hasAttribute("attach")) {
attachType = attrs.value("attach").toString() == "transform" ? CardRelation::TransformInto
: CardRelation::AttachTo;
attach = true;
}
if (attrs.hasAttribute("exclude")) {
@@ -217,7 +216,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
persistent = true;
}
auto *relation = new CardRelation(cardName, attachType, exclude, variable, count, persistent);
auto *relation = new CardRelation(cardName, attach, exclude, variable, count, persistent);
if (xmlName == "reverse-related") {
reverseRelatedCards << relation;
} else {
@@ -231,7 +230,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
reverseRelatedCards, _sets, cipt, tableRow, upsideDown);
reverseRelatedCards, sets, cipt, tableRow, upsideDown);
emit addCard(newCard);
}
}
@@ -295,7 +294,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
for (auto i : related) {
xml.writeStartElement("related");
if (i->getDoesAttach()) {
xml.writeAttribute("attach", i->getAttachTypeAsString());
xml.writeAttribute("attach", "attach");
}
if (i->getIsCreateAllExclusion()) {
xml.writeAttribute("exclude", "exclude");
@@ -319,7 +318,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
for (auto i : reverseRelated) {
xml.writeStartElement("reverse-related");
if (i->getDoesAttach()) {
xml.writeAttribute("attach", i->getAttachTypeAsString());
xml.writeAttribute("attach", "attach");
}
if (i->getIsCreateAllExclusion()) {
@@ -356,7 +355,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml;
}
bool CockatriceXml4Parser::saveToFile(SetNameMap _sets,
bool CockatriceXml4Parser::saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl,
@@ -383,9 +382,9 @@ bool CockatriceXml4Parser::saveToFile(SetNameMap _sets,
xml.writeTextElement("sourceVersion", sourceVersion);
xml.writeEndElement();
if (_sets.count() > 0) {
if (sets.count() > 0) {
xml.writeStartElement("sets");
for (CardSetPtr set : _sets) {
for (CardSetPtr set : sets) {
xml << set;
}
xml.writeEndElement();

View File

@@ -14,7 +14,7 @@ public:
~CockatriceXml4Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap _sets,
bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",

View File

@@ -24,7 +24,7 @@ void CardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
AbstractCardDragItem::paint(painter, option, widget);
if (occupied)
painter->fillPath(shape(), QColor(200, 0, 0, 100));
painter->fillRect(boundingRect(), QColor(200, 0, 0, 100));
}
void CardDragItem::updatePosition(const QPointF &cursorScenePos)
@@ -53,20 +53,8 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
QPointF zonePos = currentZone->scenePos();
QPointF cursorPosInZone = cursorScenePos - zonePos;
// If we are on a Table, we center the card around the cursor, because we
// snap it into place and no longer see it being dragged.
//
// For other zones (where we do display the card under the cursor), we use
// the hotspot to feel like the card was dragged at the corresponding
// position.
TableZone *tableZone = qobject_cast<TableZone *>(cursorZone);
QPointF closestGridPoint;
if (tableZone)
closestGridPoint = tableZone->closestGridPoint(cursorPosInZone);
else
closestGridPoint = cursorPosInZone - hotSpot;
QPointF cardTopLeft = cursorPosInZone - hotSpot;
QPointF closestGridPoint = cursorZone->closestGridPoint(cardTopLeft);
QPointF newPos = zonePos + closestGridPoint;
if (newPos != pos()) {
@@ -95,7 +83,7 @@ void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
QList<CardDragItem *> dragItemList;
CardZone *startZone = static_cast<CardItem *>(item)->getZone();
if (currentZone && !(static_cast<CardItem *>(item)->getAttachedTo() && (startZone == currentZone)) && !occupied) {
if (currentZone && !(static_cast<CardItem *>(item)->getAttachedTo() && (startZone == currentZone))) {
dragItemList.append(this);
for (int i = 0; i < childDrags.size(); i++) {
CardDragItem *c = static_cast<CardDragItem *>(childDrags[i]);

View File

@@ -4,7 +4,8 @@
#include "main.h"
#include "pictureloader.h"
#include <QStylePainter>
#include <QPainter>
#include <QStyle>
#include <QWidget>
CardInfoPicture::CardInfoPicture(QWidget *parent) : QWidget(parent), info(nullptr), pixmapDirty(true)
@@ -54,13 +55,6 @@ void CardInfoPicture::paintEvent(QPaintEvent *)
if (pixmapDirty)
loadPixmap();
QSize scaledSize = resizedPixmap.size().scaled(size(), Qt::KeepAspectRatio);
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
qreal radius = 0.05 * scaledSize.width();
QStylePainter painter(this);
QPainterPath shape;
shape.addRoundedRect(QRect(topLeft, scaledSize), radius, radius);
painter.setClipPath(shape);
painter.drawItemPixmap(QRect(topLeft, scaledSize), Qt::AlignCenter, resizedPixmap);
QPainter painter(this);
style()->drawItemPixmap(&painter, rect(), Qt::AlignHCenter, resizedPixmap);
}

View File

@@ -97,10 +97,10 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QMapIterator<int, int> counterIterator(counters);
while (counterIterator.hasNext()) {
counterIterator.next();
QColor _color;
_color.setHsv(counterIterator.key() * 60, 150, 255);
QColor color;
color.setHsv(counterIterator.key() * 60, 150, 255);
paintNumberEllipse(counterIterator.value(), 14, _color, i, counters.size(), painter);
paintNumberEllipse(counterIterator.value(), 14, color, i, counters.size(), painter);
++i;
}
@@ -141,19 +141,21 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
}
if (getBeingPointedAt()) {
painter->fillPath(shape(), QBrush(QColor(255, 0, 0, 100)));
painter->fillRect(boundingRect(), QBrush(QColor(255, 0, 0, 100)));
}
if (doesntUntap) {
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
transformPainter(painter, translatedSize, tapAngle);
QPen pen;
pen.setColor(Qt::magenta);
pen.setWidth(0); // Cosmetic pen
const int penWidth = 1;
pen.setWidth(penWidth);
painter->setPen(pen);
painter->drawPath(shape());
painter->drawRect(QRectF(0, 0, translatedSize.width() + penWidth, translatedSize.height() - penWidth));
painter->restore();
}
@@ -233,25 +235,25 @@ void CardItem::resetState()
update();
}
void CardItem::processCardInfo(const ServerInfo_Card &_info)
void CardItem::processCardInfo(const ServerInfo_Card &info)
{
counters.clear();
const int counterListSize = _info.counter_list_size();
const int counterListSize = info.counter_list_size();
for (int i = 0; i < counterListSize; ++i) {
const ServerInfo_CardCounter &counterInfo = _info.counter_list(i);
const ServerInfo_CardCounter &counterInfo = info.counter_list(i);
counters.insert(counterInfo.id(), counterInfo.value());
}
setId(_info.id());
setName(QString::fromStdString(_info.name()));
setAttacking(_info.attacking());
setFaceDown(_info.face_down());
setPT(QString::fromStdString(_info.pt()));
setAnnotation(QString::fromStdString(_info.annotation()));
setColor(QString::fromStdString(_info.color()));
setTapped(_info.tapped());
setDestroyOnZoneChange(_info.destroy_on_zone_change());
setDoesntUntap(_info.doesnt_untap());
setId(info.id());
setName(QString::fromStdString(info.name()));
setAttacking(info.attacking());
setFaceDown(info.face_down());
setPT(QString::fromStdString(info.pt()));
setAnnotation(QString::fromStdString(info.annotation()));
setColor(QString::fromStdString(info.color()));
setTapped(info.tapped());
setDestroyOnZoneChange(info.destroy_on_zone_change());
setDoesntUntap(info.doesnt_untap());
}
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown)
@@ -348,9 +350,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
// Use the buttonDownPos to align the hot spot with the position when
// the user originally clicked
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), facedown || forceFaceDown);
createDragItem(id, event->pos(), event->scenePos(), facedown || forceFaceDown);
dragItem->grabMouse();
int childIndex = 0;

View File

@@ -138,7 +138,7 @@ public:
return attachedCards;
}
void resetState();
void processCardInfo(const ServerInfo_Card &_info);
void processCardInfo(const ServerInfo_Card &info);
QMenu *getCardMenu() const
{

View File

@@ -470,23 +470,15 @@ void ChatView::showSystemPopup(const QString &userName)
QColor ChatView::getCustomMentionColor()
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
QColor customColor = QColor::fromString("#" + SettingsCache::instance().getChatMentionColor());
#else
QColor customColor;
customColor.setNamedColor("#" + SettingsCache::instance().getChatMentionColor());
#endif
return customColor.isValid() ? customColor : DEFAULT_MENTION_COLOR;
}
QColor ChatView::getCustomHighlightColor()
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
QColor customColor = QColor::fromString("#" + SettingsCache::instance().getChatMentionColor());
#else
QColor customColor;
customColor.setNamedColor("#" + SettingsCache::instance().getChatMentionColor());
#endif
customColor.setNamedColor("#" + SettingsCache::instance().getChatHighlightColor());
return customColor.isValid() ? customColor : DEFAULT_MENTION_COLOR;
}

View File

@@ -65,8 +65,8 @@ private:
QTextCursor prepareBlock(bool same = false);
void appendCardTag(QTextCursor &cursor, const QString &cardName);
void appendUrlTag(QTextCursor &cursor, QString url);
static QColor getCustomMentionColor();
static QColor getCustomHighlightColor();
QColor getCustomMentionColor();
QColor getCustomHighlightColor();
void showSystemPopup(const QString &userName);
bool isModeratorSendingGlobal(QFlags<ServerInfo_User::UserLevelFlag> userLevelFlag, QString message);
void checkTag(QTextCursor &cursor, QString &message);

View File

@@ -0,0 +1,29 @@
#ifndef CLIENT_METATYPES_H
#define CLIENT_METATYPES_H
#include <QMetaType>
Q_DECLARE_METATYPE(QVariant)
Q_DECLARE_METATYPE(CommandContainer)
Q_DECLARE_METATYPE(Response)
Q_DECLARE_METATYPE(Response::ResponseCode)
Q_DECLARE_METATYPE(ClientStatus)
Q_DECLARE_METATYPE(RoomEvent)
Q_DECLARE_METATYPE(GameEventContainer)
Q_DECLARE_METATYPE(Event_ServerIdentification)
Q_DECLARE_METATYPE(Event_ConnectionClosed)
Q_DECLARE_METATYPE(Event_ServerShutdown)
Q_DECLARE_METATYPE(Event_AddToList)
Q_DECLARE_METATYPE(Event_RemoveFromList)
Q_DECLARE_METATYPE(Event_UserJoined)
Q_DECLARE_METATYPE(Event_UserLeft)
Q_DECLARE_METATYPE(Event_ServerMessage)
Q_DECLARE_METATYPE(Event_ListRooms)
Q_DECLARE_METATYPE(Event_GameJoined)
Q_DECLARE_METATYPE(Event_UserMessage)
Q_DECLARE_METATYPE(ServerInfo_User)
Q_DECLARE_METATYPE(QList<ServerInfo_User>)
Q_DECLARE_METATYPE(Event_ReplayAdded)
Q_DECLARE_METATYPE(QList<QString>)
#endif

View File

@@ -289,7 +289,7 @@ QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneNam
return currentZoneName;
}
QString DeckLoader::getCompleteCardName(const QString &cardName) const
QString DeckLoader::getCompleteCardName(const QString cardName) const
{
if (db) {
CardInfoPtr temp = db->guessCard(cardName);

View File

@@ -57,8 +57,8 @@ protected:
const InnerDecklistNode *zoneNode,
QList<DecklistCardNode *> cards,
bool addComments = true);
[[nodiscard]] QString getCardZoneFromName(QString cardName, QString currentZoneName) override;
[[nodiscard]] QString getCompleteCardName(const QString &cardName) const override;
virtual QString getCardZoneFromName(QString cardName, QString currentZoneName);
virtual QString getCompleteCardName(const QString cardName) const;
};
#endif

View File

@@ -89,8 +89,7 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
pen.setJoinStyle(Qt::MiterJoin);
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
painter->setPen(pen);
qreal cardRadius = 0.05 * (CARD_WIDTH - 3);
painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius);
painter->drawRect(QRectF(1, 1, CARD_WIDTH - 2, CARD_HEIGHT - 2.5));
painter->restore();
}

View File

@@ -1,7 +1,7 @@
#include "dlg_connect.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include "userconnection_information.h"
#include <QCheckBox>
@@ -245,22 +245,22 @@ void DlgConnect::updateDisplayInfo(const QString &saveName)
}
UserConnection_Information uci;
QStringList _data = uci.getServerInfo(saveName);
QStringList data = uci.getServerInfo(saveName);
bool savePasswordStatus = (_data.at(5) == "1");
bool savePasswordStatus = (data.at(5) == "1");
saveEdit->setText(_data.at(0));
hostEdit->setText(_data.at(1));
portEdit->setText(_data.at(2));
playernameEdit->setText(_data.at(3));
saveEdit->setText(data.at(0));
hostEdit->setText(data.at(1));
portEdit->setText(data.at(2));
playernameEdit->setText(data.at(3));
savePasswordCheckBox->setChecked(savePasswordStatus);
if (savePasswordStatus) {
passwordEdit->setText(_data.at(4));
passwordEdit->setText(data.at(4));
}
if (!_data.at(6).isEmpty()) {
QString formattedLink = "<a href=\"" + _data.at(6) + "\">" + _data.at(6) + "</a>";
if (!data.at(6).isEmpty()) {
QString formattedLink = "<a href=\"" + data.at(6) + "\">" + data.at(6) + "</a>";
serverContactLabel->setText(tr("Webpage") + ":");
serverContactLink->setText(formattedLink);
} else {

View File

@@ -5,7 +5,7 @@
#include "decklist.h"
#include "main.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QCloseEvent>

View File

@@ -3,8 +3,8 @@
#include "pb/serverinfo_game.pb.h"
#include "pending_command.h"
#include "settingscache.h"
#include "stringsizes.h"
#include "tab_room.h"
#include "trice_limits.h"
#include <QApplication>
#include <QCheckBox>
@@ -235,13 +235,13 @@ void DlgCreateGame::actOK()
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
QString _gameTypes = QString();
QString gameTypes = QString();
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
while (gameTypeCheckBoxIterator.hasNext()) {
gameTypeCheckBoxIterator.next();
if (gameTypeCheckBoxIterator.value()->isChecked()) {
cmd.add_game_type_ids(gameTypeCheckBoxIterator.key());
_gameTypes += gameTypeCheckBoxIterator.value()->text() + ", ";
gameTypes += gameTypeCheckBoxIterator.value()->text() + ", ";
}
}
@@ -256,7 +256,7 @@ void DlgCreateGame::actOK()
SettingsCache::instance().setSpectatorsCanTalk(spectatorsCanTalkCheckBox->isChecked());
SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked());
SettingsCache::instance().setGameTypes(_gameTypes);
SettingsCache::instance().setGameTypes(gameTypes);
}
PendingCommand *pend = room->prepareRoomCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(checkResponse(Response)));

View File

@@ -1,6 +1,6 @@
#include "dlg_edit_avatar.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QBuffer>
#include <QDebug>

View File

@@ -1,7 +1,7 @@
#include "dlg_edit_password.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QDialogButtonBox>
#include <QGridLayout>

View File

@@ -4,7 +4,7 @@
#include "carddatabasemodel.h"
#include "gettextwithmax.h"
#include "main.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QAction>
#include <QComboBox>

View File

@@ -1,7 +1,7 @@
#include "dlg_edit_user.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QDebug>
#include <QDialogButtonBox>

View File

@@ -1,7 +1,7 @@
#include "dlg_forgotpasswordchallenge.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>

View File

@@ -1,7 +1,7 @@
#include "dlg_forgotpasswordrequest.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>

View File

@@ -1,7 +1,7 @@
#include "dlg_forgotpasswordreset.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>

View File

@@ -4,7 +4,6 @@
#include "main.h"
#include "pictureloader.h"
#include "setsmodel.h"
#include "settingscache.h"
#include <QAction>
#include <QDebug>
@@ -85,6 +84,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
displayModel->setDynamicSortFilter(false);
view = new QTreeView;
view->setModel(displayModel);
view->setMinimumSize(QSize(500, 250));
view->setAlternatingRowColors(true);
view->setUniformRowHeights(true);
@@ -98,6 +98,10 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
view->setDropIndicatorShown(true);
view->setDragDropMode(QAbstractItemView::InternalMove);
view->header()->setSectionResizeMode(QHeaderView::Stretch);
view->header()->setSectionResizeMode(SetsModel::EnabledCol, QHeaderView::ResizeToContents);
view->header()->setSectionResizeMode(SetsModel::LongNameCol, QHeaderView::ResizeToContents);
view->sortByColumn(SetsModel::SortKeyCol, Qt::AscendingOrder);
view->setColumnHidden(SetsModel::SortKeyCol, true);
view->setColumnHidden(SetsModel::IsKnownCol, true);
@@ -166,7 +170,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
mainLayout = new QGridLayout;
mainLayout->addLayout(filterBox, 0, 1, 1, 2);
mainLayout->addWidget(setsEditToolBar, 1, 0, 4, 1);
mainLayout->addWidget(setsEditToolBar, 1, 0, 2, 1);
mainLayout->addWidget(view, 1, 1, 1, 2);
mainLayout->addWidget(enableAllButton, 2, 1);
mainLayout->addWidget(disableAllButton, 2, 2);
@@ -186,35 +190,13 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
setCentralWidget(centralWidget);
setWindowTitle(tr("Manage sets"));
setMinimumSize(800, 500);
auto &geometry = SettingsCache::instance().getSetsDialogGeometry();
if (!geometry.isEmpty()) {
restoreGeometry(geometry);
}
auto &headerState = SettingsCache::instance().layouts().getSetsDialogHeaderState();
if (!headerState.isEmpty()) {
view->header()->restoreState(headerState);
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
} else {
view->header()->resizeSections(QHeaderView::ResizeToContents);
}
connect(view->header(), &QHeaderView::geometriesChanged, this, &WndSets::saveHeaderState);
resize(800, 500);
}
WndSets::~WndSets()
{
}
void WndSets::closeEvent(QCloseEvent * /*ev*/)
{
SettingsCache::instance().setSetsDialogGeometry(saveGeometry());
}
void WndSets::saveHeaderState()
{
SettingsCache::instance().layouts().setSetsDialogHeaderState(view->header()->saveState());
}
void WndSets::rebuildMainLayout(int actionToTake)
{
if (mainLayout == nullptr)

View File

@@ -40,8 +40,6 @@ private:
QHBoxLayout *filterBox;
int sortIndex;
Qt::SortOrder sortOrder;
void closeEvent(QCloseEvent *ev) override;
void saveHeaderState();
void rebuildMainLayout(int actionToTake);
bool setOrderIsSorted;
enum

View File

@@ -2,7 +2,7 @@
#include "pb/serverinfo_user.pb.h"
#include "settingscache.h"
#include "trice_limits.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>

View File

@@ -1,52 +0,0 @@
#include "dlg_roll_dice.h"
#include "trice_limits.h"
#include <QDialogButtonBox>
#include <QLabel>
#include <QSpinBox>
#include <QVBoxLayout>
#include <QWidget>
DlgRollDice::DlgRollDice(QWidget *parent) : QDialog(parent)
{
numberOfSidesLabel = new QLabel(tr("Number of sides:"));
numberOfSidesEdit = new QSpinBox(this);
numberOfSidesEdit->setValue(DEFAULT_NUMBER_SIDES_DIE);
numberOfSidesEdit->setRange(MINIMUM_DIE_SIDES, MAXIMUM_DIE_SIDES);
numberOfSidesEdit->setFocus();
numberOfSidesLabel->setBuddy(numberOfSidesEdit);
numberOfDiceLabel = new QLabel(tr("Number of dice:"));
numberOfDiceEdit = new QSpinBox(this);
numberOfDiceEdit->setValue(DEFAULT_NUMBER_DICE_TO_ROLL);
numberOfDiceEdit->setRange(MINIMUM_DICE_TO_ROLL, MAXIMUM_DICE_TO_ROLL);
numberOfDiceLabel->setBuddy(numberOfDiceEdit);
auto *grid = new QGridLayout;
grid->addWidget(numberOfSidesLabel, 0, 0);
grid->addWidget(numberOfSidesEdit, 0, 1);
grid->addWidget(numberOfDiceLabel, 1, 0);
grid->addWidget(numberOfDiceEdit, 1, 1);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
auto *mainLayout = new QVBoxLayout;
mainLayout->addItem(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Roll Dice"));
}
uint DlgRollDice::getDieSideCount() const
{
return numberOfSidesEdit->text().toUInt();
}
uint DlgRollDice::getDiceToRollCount() const
{
return numberOfDiceEdit->text().toUInt();
}

View File

@@ -1,26 +0,0 @@
#ifndef DLG_ROLL_DICE_H
#define DLG_ROLL_DICE_H
#include <QDialog>
#include <QDialogButtonBox>
#include <QLabel>
#include <QSpinBox>
class DlgRollDice : public QDialog
{
Q_OBJECT
static constexpr uint DEFAULT_NUMBER_SIDES_DIE = 20;
static constexpr uint DEFAULT_NUMBER_DICE_TO_ROLL = 1;
QLabel *numberOfSidesLabel, *numberOfDiceLabel;
QSpinBox *numberOfSidesEdit, *numberOfDiceEdit;
QDialogButtonBox *buttonBox;
public:
explicit DlgRollDice(QWidget *parent = nullptr);
[[nodiscard]] uint getDieSideCount() const;
[[nodiscard]] uint getDiceToRollCount() const;
};
#endif // DLG_ROLL_DICE_H

View File

@@ -3,7 +3,6 @@
#include "carddatabase.h"
#include "gettextwithmax.h"
#include "main.h"
#include "pictureloader.h"
#include "releasechannel.h"
#include "sequenceEdit/sequenceedit.h"
#include "settingscache.h"
@@ -69,9 +68,18 @@ GeneralSettingsPage::GeneralSettingsPage()
updateNotificationCheckBox.setChecked(settings.getNotifyAboutUpdates());
newVersionOracleCheckBox.setChecked(settings.getNotifyAboutNewVersion());
// pixmap cache
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
// 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size)
pixmapCacheEdit.setMaximum(PIXMAPCACHE_SIZE_MAX);
pixmapCacheEdit.setSingleStep(64);
pixmapCacheEdit.setValue(settings.getPixmapCacheSize());
pixmapCacheEdit.setSuffix(" MB");
showTipsOnStartup.setChecked(settings.getShowTipsOnStartup());
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &settings, SLOT(setPixmapCacheSize(int)));
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), &settings, SLOT(setUpdateReleaseChannel(int)));
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutUpdate(int)));
connect(&newVersionOracleCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutNewVersion(int)));
@@ -82,6 +90,8 @@ GeneralSettingsPage::GeneralSettingsPage()
personalGrid->addWidget(&languageBox, 0, 1);
personalGrid->addWidget(&updateReleaseChannelLabel, 1, 0);
personalGrid->addWidget(&updateReleaseChannelBox, 1, 1);
personalGrid->addWidget(&pixmapCacheLabel, 2, 0);
personalGrid->addWidget(&pixmapCacheEdit, 2, 1);
personalGrid->addWidget(&updateNotificationCheckBox, 3, 0, 1, 2);
personalGrid->addWidget(&newVersionOracleCheckBox, 4, 0, 1, 2);
personalGrid->addWidget(&showTipsOnStartup, 5, 0, 1, 2);
@@ -291,6 +301,7 @@ void GeneralSettingsPage::retranslateUi()
cardDatabasePathLabel.setText(tr("Card database:"));
customCardDatabasePathLabel.setText(tr("Custom database directory:"));
tokenDatabasePathLabel.setText(tr("Token database:"));
pixmapCacheLabel.setText(tr("Picture cache size:"));
updateReleaseChannelLabel.setText(tr("Update channel"));
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
@@ -299,7 +310,6 @@ void GeneralSettingsPage::retranslateUi()
AppearanceSettingsPage::AppearanceSettingsPage()
{
SettingsCache &settings = SettingsCache::instance();
QString themeName = SettingsCache::instance().getThemeName();
QStringList themeDirs = themeManager->getAvailableThemes().keys();
@@ -320,31 +330,27 @@ AppearanceSettingsPage::AppearanceSettingsPage()
themeGroupBox = new QGroupBox;
themeGroupBox->setLayout(themeGrid);
displayCardNamesCheckBox.setChecked(settings.getDisplayCardNames());
connect(&displayCardNamesCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setDisplayCardNames(int)));
displayCardNamesCheckBox.setChecked(SettingsCache::instance().getDisplayCardNames());
connect(&displayCardNamesCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(),
SLOT(setDisplayCardNames(int)));
cardScalingCheckBox.setChecked(settings.getScaleCards());
connect(&cardScalingCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setCardScaling(int)));
verticalCardOverlapPercentBox.setValue(settings.getStackCardOverlapPercent());
verticalCardOverlapPercentBox.setRange(0, 80);
connect(&verticalCardOverlapPercentBox, SIGNAL(valueChanged(int)), &settings,
SLOT(setStackCardOverlapPercent(int)));
cardScalingCheckBox.setChecked(SettingsCache::instance().getScaleCards());
connect(&cardScalingCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(), SLOT(setCardScaling(int)));
auto *cardsGrid = new QGridLayout;
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
cardsGrid->addWidget(&cardScalingCheckBox, 1, 0, 1, 2);
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 2, 0, 1, 1);
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 2, 1, 1, 1);
cardsGroupBox = new QGroupBox;
cardsGroupBox->setLayout(cardsGrid);
horizontalHandCheckBox.setChecked(settings.getHorizontalHand());
connect(&horizontalHandCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setHorizontalHand(int)));
horizontalHandCheckBox.setChecked(SettingsCache::instance().getHorizontalHand());
connect(&horizontalHandCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(),
SLOT(setHorizontalHand(int)));
leftJustifiedHandCheckBox.setChecked(settings.getLeftJustified());
connect(&leftJustifiedHandCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setLeftJustified(int)));
leftJustifiedHandCheckBox.setChecked(SettingsCache::instance().getLeftJustified());
connect(&leftJustifiedHandCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(),
SLOT(setLeftJustified(int)));
auto *handGrid = new QGridLayout;
handGrid->addWidget(&horizontalHandCheckBox, 0, 0, 1, 2);
@@ -353,18 +359,18 @@ AppearanceSettingsPage::AppearanceSettingsPage()
handGroupBox = new QGroupBox;
handGroupBox->setLayout(handGrid);
invertVerticalCoordinateCheckBox.setChecked(settings.getInvertVerticalCoordinate());
connect(&invertVerticalCoordinateCheckBox, SIGNAL(stateChanged(int)), &settings,
invertVerticalCoordinateCheckBox.setChecked(SettingsCache::instance().getInvertVerticalCoordinate());
connect(&invertVerticalCoordinateCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(),
SLOT(setInvertVerticalCoordinate(int)));
minPlayersForMultiColumnLayoutEdit.setMinimum(2);
minPlayersForMultiColumnLayoutEdit.setValue(settings.getMinPlayersForMultiColumnLayout());
connect(&minPlayersForMultiColumnLayoutEdit, SIGNAL(valueChanged(int)), &settings,
minPlayersForMultiColumnLayoutEdit.setValue(SettingsCache::instance().getMinPlayersForMultiColumnLayout());
connect(&minPlayersForMultiColumnLayoutEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(),
SLOT(setMinPlayersForMultiColumnLayout(int)));
minPlayersForMultiColumnLayoutLabel.setBuddy(&minPlayersForMultiColumnLayoutEdit);
connect(&maxFontSizeForCardsEdit, SIGNAL(valueChanged(int)), &settings, SLOT(setMaxFontSize(int)));
maxFontSizeForCardsEdit.setValue(settings.getMaxFontSize());
connect(&maxFontSizeForCardsEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(), SLOT(setMaxFontSize(int)));
maxFontSizeForCardsEdit.setValue(SettingsCache::instance().getMaxFontSize());
maxFontSizeForCardsLabel.setBuddy(&maxFontSizeForCardsEdit);
maxFontSizeForCardsEdit.setMinimum(9);
maxFontSizeForCardsEdit.setMaximum(100);
@@ -418,8 +424,6 @@ void AppearanceSettingsPage::retranslateUi()
cardsGroupBox->setTitle(tr("Card rendering"));
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
verticalCardOverlapPercentLabel.setText(
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));
handGroupBox->setTitle(tr("Hand layout"));
horizontalHandCheckBox.setText(tr("Display hand horizontally (wastes space)"));
@@ -587,38 +591,12 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
messageListLayout->addWidget(messageToolBar);
messageListLayout->addWidget(urlList);
// pixmap cache
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
// 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size)
pixmapCacheEdit.setMaximum(PIXMAPCACHE_SIZE_MAX);
pixmapCacheEdit.setSingleStep(64);
pixmapCacheEdit.setValue(SettingsCache::instance().getPixmapCacheSize());
pixmapCacheEdit.setSuffix(" MB");
networkCacheEdit.setMinimum(NETWORK_CACHE_SIZE_MIN);
networkCacheEdit.setMaximum(NETWORK_CACHE_SIZE_MAX);
networkCacheEdit.setSingleStep(1);
networkCacheEdit.setValue(SettingsCache::instance().getNetworkCacheSizeInMB());
networkCacheEdit.setSuffix(" MB");
auto networkCacheLayout = new QHBoxLayout;
networkCacheLayout->addStretch();
networkCacheLayout->addWidget(&networkCacheLabel);
networkCacheLayout->addWidget(&networkCacheEdit);
auto pixmapCacheLayout = new QHBoxLayout;
pixmapCacheLayout->addStretch();
pixmapCacheLayout->addWidget(&pixmapCacheLabel);
pixmapCacheLayout->addWidget(&pixmapCacheEdit);
// Top Layout
lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0);
lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1);
lpGeneralGrid->addLayout(messageListLayout, 1, 0, 1, 2);
lpGeneralGrid->addLayout(networkCacheLayout, 2, 0, 1, 2);
lpGeneralGrid->addLayout(pixmapCacheLayout, 3, 0, 1, 2);
lpGeneralGrid->addWidget(&urlLinkLabel, 4, 0);
lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 4, 1);
lpGeneralGrid->addWidget(&urlLinkLabel, 2, 0);
lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 2, 1);
// Spoiler Layout
lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0);
@@ -633,9 +611,6 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), &SettingsCache::instance(),
SLOT(setDownloadSpoilerStatus(bool)));
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSpoilersEnabled(bool)));
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(), SLOT(setPixmapCacheSize(int)));
connect(&networkCacheEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(),
SLOT(setNetworkCacheSizeInMB(int)));
mpGeneralGroupBox = new QGroupBox;
mpGeneralGroupBox->setLayout(lpGeneralGrid);
@@ -660,11 +635,6 @@ void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked()
void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
{
PictureLoader::clearNetworkCache();
// These are not used anymore, but we don't delete them automatically, so
// we should do it here lest we leave pictures hanging around on users'
// machines.
QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics/";
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
bool outerSuccessRemove = true;
@@ -692,7 +662,6 @@ void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
}
if (outerSuccessRemove) {
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
QDir(SettingsCache::instance().getPicsPath()).rmdir("downloadedPics");
} else {
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
}
@@ -816,10 +785,6 @@ void DeckEditorSettingsPage::retranslateUi()
urlLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL")));
clearDownloadedPicsButton.setText(tr("Delete Downloaded Images"));
resetDownloadURLs.setText(tr("Reset Download URLs"));
networkCacheLabel.setText(tr("Downloaded images directory size:"));
networkCacheEdit.setToolTip(tr("On-disk cache for downloaded pictures"));
pixmapCacheLabel.setText(tr("Picture cache size:"));
pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen"));
}
MessagesSettingsPage::MessagesSettingsPage()
@@ -944,12 +909,8 @@ MessagesSettingsPage::MessagesSettingsPage()
void MessagesSettingsPage::updateColor(const QString &value)
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
QColor colorToSet = QColor::fromString("#" + value);
#else
QColor colorToSet;
colorToSet.setNamedColor("#" + value);
#endif
if (colorToSet.isValid()) {
SettingsCache::instance().setChatMentionColor(value);
updateMentionPreview();
@@ -958,12 +919,8 @@ void MessagesSettingsPage::updateColor(const QString &value)
void MessagesSettingsPage::updateHighlightColor(const QString &value)
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
QColor colorToSet = QColor::fromString("#" + value);
#else
QColor colorToSet;
colorToSet.setNamedColor("#" + value);
#endif
if (colorToSet.isValid()) {
SettingsCache::instance().setChatHighlightColor(value);
updateHighlightPreview();
@@ -1161,28 +1118,28 @@ ShortcutSettingsPage::ShortcutSettingsPage()
btnClearAll->setIcon(QPixmap("theme:icons/clearsearch"));
// layout
auto *_editLayout = new QGridLayout;
_editLayout->addWidget(currentActionGroupLabel, 0, 0);
_editLayout->addWidget(currentActionGroupName, 0, 1);
_editLayout->addWidget(currentActionLabel, 1, 0);
_editLayout->addWidget(currentActionName, 1, 1);
_editLayout->addWidget(currentShortcutLabel, 2, 0);
_editLayout->addWidget(editTextBox, 2, 1);
auto *editLayout = new QGridLayout;
editLayout->addWidget(currentActionGroupLabel, 0, 0);
editLayout->addWidget(currentActionGroupName, 0, 1);
editLayout->addWidget(currentActionLabel, 1, 0);
editLayout->addWidget(currentActionName, 1, 1);
editLayout->addWidget(currentShortcutLabel, 2, 0);
editLayout->addWidget(editTextBox, 2, 1);
editShortcutGroupBox = new QGroupBox;
editShortcutGroupBox->setLayout(_editLayout);
editShortcutGroupBox->setLayout(editLayout);
auto *_buttonsLayout = new QHBoxLayout;
_buttonsLayout->addWidget(faqLabel);
_buttonsLayout->addWidget(btnResetAll);
_buttonsLayout->addWidget(btnClearAll);
auto *buttonsLayout = new QHBoxLayout;
buttonsLayout->addWidget(faqLabel);
buttonsLayout->addWidget(btnResetAll);
buttonsLayout->addWidget(btnClearAll);
auto *_mainLayout = new QVBoxLayout;
_mainLayout->addWidget(shortcutsTable);
_mainLayout->addWidget(editShortcutGroupBox);
_mainLayout->addLayout(_buttonsLayout);
auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(shortcutsTable);
mainLayout->addWidget(editShortcutGroupBox);
mainLayout->addLayout(buttonsLayout);
setLayout(_mainLayout);
setLayout(mainLayout);
connect(btnResetAll, SIGNAL(clicked()), this, SLOT(resetShortcuts()));
connect(btnClearAll, SIGNAL(clicked()), this, SLOT(clearShortcuts()));
@@ -1288,8 +1245,8 @@ void ShortcutSettingsPage::retranslateUi()
currentShortcutLabel->setText(tr("Shortcut:"));
editTextBox->retranslateUi();
faqLabel->setText(QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_SHORTCUTS).arg(tr("How to set custom shortcuts")));
btnResetAll->setText(tr("Restore all default shortcuts"));
btnClearAll->setText(tr("Clear all shortcuts"));
btnResetAll->setText("Restore all default shortcuts");
btnClearAll->setText("Clear all shortcuts");
}
DlgSettings::DlgSettings(QWidget *parent) : QDialog(parent)

View File

@@ -58,6 +58,7 @@ private:
QLineEdit *tokenDatabasePathEdit;
QPushButton *resetAllPathsButton;
QLabel *allPathsResetLabel;
QSpinBox pixmapCacheEdit;
QGroupBox *personalGroupBox;
QGroupBox *pathsGroupBox;
QComboBox languageBox;
@@ -65,6 +66,7 @@ private:
QCheckBox newVersionOracleCheckBox;
QComboBox updateReleaseChannelBox;
QLabel languageLabel;
QLabel pixmapCacheLabel;
QLabel deckPathLabel;
QLabel replaysPathLabel;
QLabel picsPathLabel;
@@ -90,8 +92,6 @@ private:
QLabel maxFontSizeForCardsLabel;
QCheckBox displayCardNamesCheckBox;
QCheckBox cardScalingCheckBox;
QLabel verticalCardOverlapPercentLabel;
QSpinBox verticalCardOverlapPercentBox;
QCheckBox horizontalHandCheckBox;
QCheckBox leftJustifiedHandCheckBox;
QCheckBox invertVerticalCoordinateCheckBox;
@@ -168,10 +168,6 @@ private:
QLabel infoOnSpoilersLabel;
QPushButton *mpSpoilerPathButton;
QPushButton *updateNowButton;
QLabel networkCacheLabel;
QSpinBox networkCacheEdit;
QSpinBox pixmapCacheEdit;
QLabel pixmapCacheLabel;
};
class MessagesSettingsPage : public AbstractSettingsPage

View File

@@ -154,7 +154,7 @@ void DlgTipOfTheDay::updateTip(int tipId)
imageLabel->setPixmap(image->scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
date->setText("<i>Tip added on: " + tip.getDate().toString("yyyy-MM-dd") + "</i>");
date->setText("<i>Tip added on: " + tip.getDate().toString("yyyy.MM.dd") + "</i>");
tipNumber->setText("Tip " + QString::number(tipId + 1) + " / " + QString::number(tipDatabase->rowCount()));

View File

@@ -3,7 +3,6 @@
#include "../../common/lib/peglib.h"
#include <QByteArray>
#include <QDebug>
#include <QString>
#include <functional>
@@ -42,10 +41,9 @@ ColorQuery <- [cC] 'olor'? <[iI]?> <[:!]> ColorEx*
FieldQuery <- String [:] RegexString / String ws? NumericExpression
NonDoubleQuoteUnlessEscaped <- !["]. / '\"'.
NonSingleQuoteUnlessEscaped <- ![']. / "\'".
UnescapedStringListPart <- !['":<>=! ].
String <- UnescapedStringListPart+ / ["] <NonDoubleQuoteUnlessEscaped*> ["] / ['] <NonSingleQuoteUnlessEscaped*> [']
NonQuote <- !["].
UnescapedStringListPart <- ![":<>=! ].
String <- UnescapedStringListPart+ / ["] <NonQuote*> ["]
StringValue <- String / [(] StringList [)]
StringList <- StringListString (ws? [,] ws? StringListString)*
StringListString <- UnescapedStringListPart+
@@ -57,7 +55,7 @@ CompactStringSet <- StringListString ([,+] StringListString)+
NumericExpression <- NumericOperator ws? NumericValue
NumericOperator <- [=:] / <[><!][=]?>
NumericValue <- [0-9]+
NumericValue <- [0-9]+
)");
@@ -243,12 +241,7 @@ static void setupParserRules()
search["RegexString"] = [](const peg::SemanticValues &sv) -> StringMatcher {
auto target = sv[0].get<QString>();
return [=](const QString &s) {
auto sanitizedTarget = QString(target);
sanitizedTarget.replace("\\\"", "\"");
sanitizedTarget.replace("\\'", "'");
return s.QString::contains(sanitizedTarget, Qt::CaseInsensitive);
};
return [=](const QString &s) { return s.QString::contains(target, Qt::CaseInsensitive); };
};
search["OracleQuery"] = [](const peg::SemanticValues &sv) -> Filter {
@@ -341,12 +334,6 @@ static void setupParserRules()
};
}
FilterString::FilterString()
{
result = [](CardData) -> bool { return false; };
_error = "Not initialized";
}
FilterString::FilterString(const QString &expr)
{
QByteArray ba = expr.simplified().toUtf8();
@@ -365,7 +352,7 @@ FilterString::FilterString(const QString &expr)
};
if (!search.parse(ba.data(), result)) {
qDebug() << "Filter string error" << _error;
std::cout << "Error!" << _error.toStdString() << std::endl;
result = [](CardData) -> bool { return false; };
}
}

View File

@@ -24,7 +24,6 @@ typedef AstBase<EmptyType> Ast;
class FilterString
{
public:
FilterString();
explicit FilterString(const QString &exp);
bool check(const CardData &card)
{

View File

@@ -198,19 +198,9 @@ void GameSelector::actCreate()
void GameSelector::checkResponse(const Response &response)
{
// NB: We re-enable buttons for the currently selected game, which may not
// be the same game as the one for which we are processing a response.
// This could lead to situations where we join a game, select a different
// game, join the new game, then receive the response for the original
// join, which would re-activate the buttons for the second game too soon.
// However, that is better than doing things the other ways, because then
// the response to the first game could lock us out of join/join as
// spectator for the second game!
//
// Ideally we should have a way to figure out if the current game is the
// same as the one we are getting a response for, but it's probably not
// worth the trouble.
enableButtons();
if (createButton)
createButton->setEnabled(true);
joinButton->setEnabled(true);
switch (response.response_code()) {
case Response::RespNotInRoom:
@@ -239,6 +229,9 @@ void GameSelector::checkResponse(const Response &response)
break;
default:;
}
if (response.response_code() != Response::RespSpectatorsNotAllowed)
spectateButton->setEnabled(true);
}
void GameSelector::actJoin()
@@ -277,39 +270,12 @@ void GameSelector::actJoin()
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(checkResponse(Response)));
r->sendRoomCommand(pend);
disableButtons();
}
void GameSelector::disableButtons()
{
if (createButton)
createButton->setEnabled(false);
joinButton->setEnabled(false);
spectateButton->setEnabled(false);
}
void GameSelector::enableButtons()
{
if (createButton)
createButton->setEnabled(true);
// Enable buttons for the currently selected game
enableButtonsForIndex(gameListView->currentIndex());
}
void GameSelector::enableButtonsForIndex(const QModelIndex &current)
{
if (!current.isValid())
return;
const ServerInfo_Game &game = gameListModel->getGame(current.data(Qt::UserRole).toInt());
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
spectateButton->setEnabled(game.spectators_allowed() || overrideRestrictions);
joinButton->setEnabled(game.player_count() < game.max_players() || overrideRestrictions);
}
void GameSelector::retranslateUi()
{
filterButton->setText(tr("&Filter games"));
@@ -330,7 +296,14 @@ void GameSelector::processGameInfo(const ServerInfo_Game &info)
void GameSelector::actSelectedGameChanged(const QModelIndex &current, const QModelIndex & /* previous */)
{
enableButtonsForIndex(current);
if (!current.isValid())
return;
const ServerInfo_Game &game = gameListModel->getGame(current.data(Qt::UserRole).toInt());
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
spectateButton->setEnabled(game.spectators_allowed() || overrideRestrictions);
joinButton->setEnabled(game.player_count() < game.max_players() || overrideRestrictions);
}
void GameSelector::updateTitle()

View File

@@ -49,9 +49,6 @@ private:
GameTypeMap gameTypeMap;
void updateTitle();
void disableButtons();
void enableButtons();
void enableButtonsForIndex(const QModelIndex &current);
public:
GameSelector(AbstractClient *_client,

View File

@@ -2,7 +2,7 @@
#ifndef GETTEXTWITHMAX_H
#define GETTEXTWITHMAX_H
#include "trice_limits.h"
#include "stringsizes.h"
#include <QInputDialog>

View File

@@ -114,18 +114,23 @@ void HandZone::reorganizeCards()
}
} else {
qreal totalWidth = boundingRect().width();
qreal totalHeight = boundingRect().height();
qreal cardWidth = cards.at(0)->boundingRect().width();
qreal cardHeight = cards.at(0)->boundingRect().height();
qreal xspace = 5;
qreal x1 = xspace;
qreal x2 = totalWidth - xspace - cardWidth;
for (int i = 0; i < cardCount; i++) {
CardItem *card = cards.at(i);
CardItem *c = cards.at(i);
qreal x = (i % 2) ? x2 : x1;
qreal y =
divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
card->setPos(x, y);
card->setRealZValue(i);
// If the total height of the cards is smaller than the available height,
// the cards do not need to overlap and are displayed in the center of the area.
if (cardHeight * cardCount > totalHeight)
c->setPos(x, ((qreal)i) * (totalHeight - cardHeight) / (cardCount - 1));
else
c->setPos(x, ((qreal)i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2);
c->setRealZValue(i);
}
}
}

View File

@@ -481,8 +481,7 @@ void MessageLogWidget::logRevealCards(Player *player,
QString cardName,
Player *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer)
int amount)
{
// getFromStr uses cardname.empty() to check if it should contain the start zone, it's not actually used
QPair<QString, QString> temp = getFromStr(zone, amount == 1 ? cardName : QString::number(amount), cardId, false);
@@ -508,17 +507,10 @@ void MessageLogWidget::logRevealCards(Player *player,
}
if (cardId == -1) {
if (otherPlayer) {
if (isLentToAnotherPlayer) {
appendHtmlServerMessage(tr("%1 lends %2 to %3.")
.arg(sanitizeHtml(player->getName()))
.arg(zone->getTranslatedName(true, CaseRevealZone))
.arg(sanitizeHtml(otherPlayer->getName())));
} else {
appendHtmlServerMessage(tr("%1 reveals %2 to %3.")
.arg(sanitizeHtml(player->getName()))
.arg(zone->getTranslatedName(true, CaseRevealZone))
.arg(sanitizeHtml(otherPlayer->getName())));
}
appendHtmlServerMessage(tr("%1 reveals %2 to %3.")
.arg(sanitizeHtml(player->getName()))
.arg(zone->getTranslatedName(true, CaseRevealZone))
.arg(sanitizeHtml(otherPlayer->getName())));
} else {
appendHtmlServerMessage(tr("%1 reveals %2.")
.arg(sanitizeHtml(player->getName()))
@@ -566,39 +558,18 @@ void MessageLogWidget::logReverseTurn(Player *player, bool reversed)
.arg(reversed ? tr("reversed") : tr("normal")));
}
void MessageLogWidget::logRollDie(Player *player, int sides, const QList<uint> &rolls)
void MessageLogWidget::logRollDie(Player *player, int sides, int roll)
{
if (rolls.length() == 1) {
const auto roll = rolls.at(0);
if (sides == 2) {
QString coinOptions[2] = {tr("Heads") + " (1)", tr("Tails") + " (2)"};
appendHtmlServerMessage(tr("%1 flipped a coin. It landed as %2.")
.arg(sanitizeHtml(player->getName()))
.arg("<font class=\"blue\">" + coinOptions[roll - 1] + "</font>"));
} else {
appendHtmlServerMessage(tr("%1 rolls a %2 with a %3-sided die.")
.arg(sanitizeHtml(player->getName()))
.arg("<font class=\"blue\">" + QString::number(roll) + "</font>")
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>"));
}
if (sides == 2) {
QString coinOptions[2] = {tr("Heads") + " (1)", tr("Tails") + " (2)"};
appendHtmlServerMessage(tr("%1 flipped a coin. It landed as %2.")
.arg(sanitizeHtml(player->getName()))
.arg("<font class=\"blue\">" + coinOptions[roll - 1] + "</font>"));
} else {
if (sides == 2) {
appendHtmlServerMessage(tr("%1 flips %2 coins. There are %3 heads and %4 tails.")
.arg(sanitizeHtml(player->getName()))
.arg("<font class=\"blue\">" + QString::number(rolls.length()) + "</font>")
.arg("<font class=\"blue\">" + QString::number(rolls.count(1)) + "</font>")
.arg("<font class=\"blue\">" + QString::number(rolls.count(2)) + "</font>"));
} else {
QStringList rollsStrings;
for (const auto &roll : rolls) {
rollsStrings.append(QString::number(roll));
}
appendHtmlServerMessage(tr("%1 rolls a %2-sided dice %3 times: %4.")
.arg(sanitizeHtml(player->getName()))
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>")
.arg("<font class=\"blue\">" + QString::number(rolls.length()) + "</font>")
.arg("<font class=\"blue\">" + rollsStrings.join(", ") + "</font>"));
}
appendHtmlServerMessage(tr("%1 rolls a %2 with a %3-sided die.")
.arg(sanitizeHtml(player->getName()))
.arg("<font class=\"blue\">" + QString::number(roll) + "</font>")
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>"));
}
soundEngine->playSound("roll_dice");
}
@@ -825,8 +796,7 @@ void MessageLogWidget::connectToPlayer(Player *player)
connect(player, SIGNAL(logSay(Player *, QString)), this, SLOT(logSay(Player *, QString)));
connect(player, &Player::logShuffle, this, &MessageLogWidget::logShuffle);
connect(player, SIGNAL(logRollDie(Player *, int, const QList<uint> &)), this,
SLOT(logRollDie(Player *, int, const QList<uint> &)));
connect(player, SIGNAL(logRollDie(Player *, int, int)), this, SLOT(logRollDie(Player *, int, int)));
connect(player, SIGNAL(logCreateArrow(Player *, Player *, QString, Player *, QString, bool)), this,
SLOT(logCreateArrow(Player *, Player *, QString, Player *, QString, bool)));
connect(player, SIGNAL(logCreateToken(Player *, QString, QString)), this,
@@ -853,8 +823,8 @@ void MessageLogWidget::connectToPlayer(Player *player)
connect(player, SIGNAL(logDumpZone(Player *, CardZone *, int)), this, SLOT(logDumpZone(Player *, CardZone *, int)));
connect(player, SIGNAL(logDrawCards(Player *, int, bool)), this, SLOT(logDrawCards(Player *, int, bool)));
connect(player, SIGNAL(logUndoDraw(Player *, QString)), this, SLOT(logUndoDraw(Player *, QString)));
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int, bool)), this,
SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int, bool)));
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)), this,
SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)));
connect(player, SIGNAL(logAlwaysRevealTopCard(Player *, CardZone *, bool)), this,
SLOT(logAlwaysRevealTopCard(Player *, CardZone *, bool)));
connect(player, SIGNAL(logAlwaysLookAtTopCard(Player *, CardZone *, bool)), this,

View File

@@ -77,10 +77,9 @@ public slots:
QString cardName,
Player *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer);
int amount);
void logReverseTurn(Player *player, bool reversed);
void logRollDie(Player *player, int sides, const QList<uint> &rolls);
void logRollDie(Player *player, int sides, int roll);
void logSay(Player *player, QString message);
void logSetActivePhase(int phase);
void logSetActivePlayer(Player *player);

View File

@@ -6,16 +6,13 @@
#include "thememanager.h"
#include <QApplication>
#include <QBuffer>
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QImageReader>
#include <QMovie>
#include <QNetworkAccessManager>
#include <QNetworkDiskCache>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QPainter>
@@ -119,21 +116,6 @@ PictureLoaderWorker::PictureLoaderWorker()
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
networkManager = new QNetworkAccessManager(this);
// We need a timeout to ensure requests don't hang indefinitely in case of
// cache corruption, see related Qt bug: https://bugreports.qt.io/browse/QTBUG-111397
// Use Qt's default timeout (30s, as of 2023-02-22)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
networkManager->setTransferTimeout();
#endif
auto cache = new QNetworkDiskCache(this);
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
// Note: the settings is in MB, but QNetworkDiskCache uses bytes
connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, cache,
[cache](int newSizeInMB) { cache->setMaximumCacheSize(1024L * 1024L * static_cast<qint64>(newSizeInMB)); });
networkManager->setCache(cache);
// Use a ManualRedirectPolicy since we keep track of redirects in picDownloadFinished
// We can't use NoLessSafeRedirectPolicy because it is not applied with AlwaysCache
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
pictureLoaderThread = new QThread;
@@ -167,19 +149,37 @@ void PictureLoaderWorker::processLoadQueue()
QString cardName = cardBeingLoaded.getCard()->getName();
QString correctedCardName = cardBeingLoaded.getCard()->getCorrectedName();
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Trying to load picture";
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Trying to load picture";
if (cardImageExistsOnDisk(setName, correctedCardName)) {
continue;
}
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: No custom picture, trying to download";
cardsToDownload.append(cardBeingLoaded);
cardBeingLoaded.clear();
if (!downloadRunning) {
startNextPicDownload();
if (picDownload) {
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Picture not found on disk, trying to download";
cardsToDownload.append(cardBeingLoaded);
cardBeingLoaded.clear();
if (!downloadRunning) {
startNextPicDownload();
}
} else {
if (cardBeingLoaded.nextSet()) {
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Picture NOT found and download disabled, moving to next "
"set (new set: "
<< setName << " card: " << cardName << ")";
mutex.lock();
loadQueue.prepend(cardBeingLoaded);
cardBeingLoaded.clear();
mutex.unlock();
} else {
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Picture NOT found, download disabled, no more sets to "
"try: BAILING OUT (old set: "
<< setName << " card: " << cardName << ")";
imageLoaded(cardBeingLoaded.getCard(), QImage());
}
}
}
}
@@ -206,33 +206,31 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
if (!setName.isEmpty()) {
picsPaths << picsPath + "/" + setName + "/" + correctedCardname
// We no longer store downloaded images there, but don't just ignore
// stuff that old versions have put there.
<< picsPath + "/downloadedPics/" + setName + "/" + correctedCardname;
}
// Iterates through the list of paths, searching for images with the desired
// name with any QImageReader-supported
// extension
for (const auto &_picsPath : picsPaths) {
imgReader.setFileName(_picsPath);
for (const auto &picsPath : picsPaths) {
imgReader.setFileName(picsPath);
if (imgReader.read(&image)) {
qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture found on disk.";
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image);
return true;
}
imgReader.setFileName(_picsPath + ".full");
imgReader.setFileName(picsPath + ".full");
if (imgReader.read(&image)) {
qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture.full found on disk.";
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture.full found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image);
return true;
}
imgReader.setFileName(_picsPath + ".xlhq");
imgReader.setFileName(picsPath + ".xlhq");
if (imgReader.read(&image)) {
qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture.xlhq found on disk.";
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture.xlhq found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image);
return true;
}
@@ -241,79 +239,6 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
return false;
}
static int parse(const QString &urlTemplate,
const QString &propType,
const QString &cardName,
const QString &setName,
std::function<QString(const QString &)> getProperty,
QMap<QString, QString> &transformMap)
{
static const QRegularExpression rxFillWith("^(.+)_fill_with_(.+)$");
static const QRegularExpression rxSubStr("^(.+)_substr_(\\d+)_(\\d+)$");
const QRegularExpression rxCardProp("!" + propType + ":([^!]+)!");
auto matches = rxCardProp.globalMatch(urlTemplate);
while (matches.hasNext()) {
auto match = matches.next();
QString templatePropertyName = match.captured(1);
auto fillMatch = rxFillWith.match(templatePropertyName);
QString cardPropertyName;
QString fillWith;
int subStrPos = 0;
int subStrLen = -1;
if (fillMatch.hasMatch()) {
cardPropertyName = fillMatch.captured(1);
fillWith = fillMatch.captured(2);
} else {
fillWith = QString();
auto subStrMatch = rxSubStr.match(templatePropertyName);
if (subStrMatch.hasMatch()) {
cardPropertyName = subStrMatch.captured(1);
subStrPos = subStrMatch.captured(2).toInt();
subStrLen = subStrMatch.captured(3).toInt();
} else {
cardPropertyName = templatePropertyName;
}
}
QString propertyValue = getProperty(cardPropertyName);
if (propertyValue.isEmpty()) {
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Requested "
<< propType << "property (" << cardPropertyName << ") for Url template (" << urlTemplate
<< ") is not available";
return 1;
} else {
int propLength = propertyValue.length();
if (subStrLen > 0 && subStrPos + subStrLen > propLength) {
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Requested "
<< propType << " property (" << cardPropertyName << ") for Url template ("
<< urlTemplate << ") is smaller than substr specification (" << subStrPos << " + "
<< subStrLen << " > " << propLength << ")";
return 1;
} else {
propertyValue = propertyValue.mid(subStrPos, subStrLen);
propLength = subStrLen;
}
if (!fillWith.isEmpty()) {
int fillLength = fillWith.length();
if (fillLength < propLength) {
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Requested "
<< propType << " property (" << cardPropertyName << ") for Url template ("
<< urlTemplate << ") is longer than fill specification (" << fillWith << ")";
return 1;
} else {
propertyValue = fillWith.left(fillLength - propLength) + propertyValue;
}
}
transformMap["!" + propType + ":" + templatePropertyName + "!"] = propertyValue;
}
}
return 0;
}
QString PictureToLoad::transformUrl(const QString &urlTemplate) const
{
/* This function takes Url templates and substitutes actual card details
@@ -321,23 +246,56 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
for downloading images. If information is requested by the template that is
not populated for this specific card/set combination, an empty string is returned.*/
static const QRegularExpression rxCardProp("!prop:([^!]+)!");
static const QRegularExpression rxFillWith("^(.+)_fill_with_(.+)$");
static const QRegularExpression rxSetProp("!set:([^!]+)!");
QString transformedUrl = urlTemplate;
CardSetPtr set = getCurrentSet();
QMap<QString, QString> transformMap = QMap<QString, QString>();
QString setName = getSetName();
// name
QString cardName = card->getName();
transformMap["!name!"] = cardName;
transformMap["!name!"] = card->getName();
transformMap["!name_lower!"] = card->getName().toLower();
transformMap["!corrected_name!"] = card->getCorrectedName();
transformMap["!corrected_name_lower!"] = card->getCorrectedName().toLower();
// card properties
if (parse(
urlTemplate, "prop", cardName, setName, [&](const QString &name) { return card->getProperty(name); },
transformMap)) {
return QString();
auto matches = rxCardProp.globalMatch(transformedUrl);
while (matches.hasNext()) {
auto match = matches.next();
QString propertyName = match.captured(1);
auto fillMatch = rxFillWith.match(propertyName);
QString fillPropertyName;
QString fillWith;
if (fillMatch.hasMatch()) {
fillPropertyName = fillMatch.captured(1);
fillWith = fillMatch.captured(2);
} else {
fillPropertyName = propertyName;
fillWith = QString();
}
QString propertyValue = card->getProperty(fillPropertyName);
if (propertyValue.isEmpty()) {
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested property (" << fillPropertyName << ") for Url template (" << urlTemplate
<< ") is not available";
return QString();
} else {
if (!fillWith.isEmpty()) {
int fillLength = fillWith.length();
int propLength = propertyValue.length();
if (fillLength < propLength) {
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested property (" << fillPropertyName << ") for Url template (" << urlTemplate
<< ") is longer than fill specification (" << fillWith << ")";
return QString();
} else {
propertyValue = fillWith.left(fillLength - propLength) + propertyValue;
}
}
transformMap["!prop:" + propertyName + "!"] = propertyValue;
}
}
if (set) {
@@ -346,10 +304,41 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
transformMap["!setname!"] = set->getLongName();
transformMap["!setname_lower!"] = set->getLongName().toLower();
if (parse(
urlTemplate, "set", cardName, setName,
[&](const QString &name) { return card->getSetProperty(set->getShortName(), name); }, transformMap)) {
return QString();
auto matches = rxSetProp.globalMatch(transformedUrl);
while (matches.hasNext()) {
auto match = matches.next();
QString propertyName = match.captured(1);
auto fillMatch = rxFillWith.match(propertyName);
QString fillPropertyName;
QString fillWith;
if (fillMatch.hasMatch()) {
fillPropertyName = fillMatch.captured(1);
fillWith = fillMatch.captured(2);
} else {
fillPropertyName = propertyName;
fillWith = QString();
}
QString propertyValue = card->getSetProperty(set->getShortName(), fillPropertyName);
if (propertyValue.isEmpty()) {
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested set property (" << fillPropertyName << ") for Url template (" << urlTemplate
<< ") is not available";
return QString();
} else {
if (!fillWith.isEmpty()) {
int fillLength = fillWith.length();
int propLength = propertyValue.length();
if (fillLength < propLength) {
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested set property (" << fillPropertyName << ") for Url template ("
<< urlTemplate << ") is longer than fill specification (" << fillWith << ")";
return QString();
} else {
propertyValue = fillWith.left(fillLength - propLength) + propertyValue;
}
}
transformMap["!set:" + propertyName + "!"] = propertyValue;
}
}
}
@@ -357,7 +346,6 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
transformMap["!sflang!"] = QString(QCoreApplication::translate(
"PictureLoader", "en", "code for scryfall's language property, not available for all languages"));
QString transformedUrl = urlTemplate;
for (const QString &prop : transformMap.keys()) {
if (transformedUrl.contains(prop)) {
if (!transformMap[prop].isEmpty()) {
@@ -367,9 +355,9 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
* populated in this card, so it should return an empty string,
* indicating an invalid Url.
*/
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Requested information (" << prop << ") for Url template (" << urlTemplate
<< ") is not available";
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested information (" << prop << ") for Url template (" << urlTemplate
<< ") is not available";
return QString();
}
}
@@ -397,10 +385,11 @@ void PictureLoaderWorker::startNextPicDownload()
picDownloadFailed();
} else {
QUrl url(picUrl);
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Trying to fetch picture from url "
<< url.toDisplayString();
makeRequest(url);
QNetworkRequest req(url);
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]: Trying to download picture from url:" << url.toDisplayString();
networkManager->get(req);
}
}
@@ -415,10 +404,10 @@ void PictureLoaderWorker::picDownloadFailed()
loadQueue.prepend(cardBeingDownloaded);
mutex.unlock();
} else {
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Picture NOT found, "
<< (picDownload ? "download failed" : "downloads disabled")
<< ", no more url combinations to try: BAILING OUT";
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]: Picture NOT found, download failed, no more url combinations "
"to try: BAILING OUT";
imageLoaded(cardBeingDownloaded.getCard(), QImage());
cardBeingDownloaded.clear();
}
@@ -431,53 +420,20 @@ bool PictureLoaderWorker::imageIsBlackListed(const QByteArray &picData)
return md5Blacklist.contains(md5sum);
}
QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url)
{
QNetworkRequest req(url);
if (!picDownload) {
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
}
return networkManager->get(req);
}
void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
{
bool isFromCache = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
if (reply->error()) {
if (isFromCache) {
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]: Removing corrupted cache file for url " << reply->url().toDisplayString()
<< " and retrying (" << reply->errorString() << ")";
networkManager->cache()->remove(reply->url());
makeRequest(reply->url());
} else {
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]: " << (picDownload ? "Download" : "Cache search") << " failed for url "
<< reply->url().toDisplayString() << " (" << reply->errorString() << ")";
picDownloadFailed();
startNextPicDownload();
}
reply->deleteLater();
return;
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Download failed:" << reply->errorString();
}
// List of status codes from https://doc.qt.io/qt-6/qnetworkreply.html#redirected
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 ||
statusCode == 308) {
QUrl redirectUrl = reply->header(QNetworkRequest::LocationHeader).toUrl();
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: following "
<< (isFromCache ? "cached redirect" : "redirect") << " to " << redirectUrl.toDisplayString();
makeRequest(redirectUrl);
reply->deleteLater();
if (statusCode == 301 || statusCode == 302) {
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QNetworkRequest req(redirectUrl);
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: following redirect:" << req.url().toString();
networkManager->get(req);
return;
}
@@ -485,10 +441,10 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
const QByteArray &picData = reply->peek(reply->size());
if (imageIsBlackListed(picData)) {
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]: Picture found, but blacklisted, will consider it as not found";
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]:Picture downloaded, but blacklisted, will consider it as "
"not found";
picDownloadFailed();
reply->deleteLater();
startNextPicDownload();
@@ -500,39 +456,41 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
imgReader.setDevice(reply);
bool logSuccessMessage = false;
static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h
auto replyHeader = reply->peek(riffHeaderSize);
if (replyHeader.startsWith("RIFF") && replyHeader.endsWith("WEBP")) {
auto imgBuf = QBuffer(this);
imgBuf.setData(reply->readAll());
auto movie = QMovie(&imgBuf);
movie.start();
movie.stop();
imageLoaded(cardBeingDownloaded.getCard(), movie.currentImage());
logSuccessMessage = true;
} else if (imgReader.read(&testImage)) {
imageLoaded(cardBeingDownloaded.getCard(), testImage);
logSuccessMessage = true;
} else {
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Possible "
<< (isFromCache ? "cached" : "downloaded") << " picture at "
<< reply->url().toDisplayString() << " could not be loaded: " << reply->errorString();
picDownloadFailed();
// the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the
// QImageReader buffer
QString extension = "." + imgReader.format();
if (extension == ".jpeg") {
extension = ".jpg";
}
if (logSuccessMessage) {
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Image successfully "
<< (isFromCache ? "loaded from cached" : "downloaded from") << " url "
<< reply->url().toDisplayString();
if (imgReader.read(&testImage)) {
QString setName = cardBeingDownloaded.getSetName();
if (!setName.isEmpty()) {
if (!QDir().mkpath(picsPath + "/downloadedPics/" + setName)) {
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName()
<< "]: " << picsPath + "/downloadedPics/" + setName + " could not be created.";
return;
}
QFile newPic(picsPath + "/downloadedPics/" + setName + "/" +
cardBeingDownloaded.getCard()->getCorrectedName() + extension);
if (!newPic.open(QIODevice::WriteOnly)) {
return;
}
newPic.write(picData);
newPic.close();
}
imageLoaded(cardBeingDownloaded.getCard(), testImage);
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Image successfully downloaded from "
<< reply->request().url().toDisplayString();
} else {
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Possible picture at "
<< reply->request().url().toDisplayString() << " could not be loaded";
picDownloadFailed();
}
reply->deleteLater();
@@ -575,11 +533,6 @@ void PictureLoaderWorker::picsPathChanged()
customPicsPath = SettingsCache::instance().getCustomPicsPath();
}
void PictureLoaderWorker::clearNetworkCache()
{
networkManager->cache()->clear();
}
PictureLoader::PictureLoader() : QObject(nullptr)
{
worker = new PictureLoaderWorker;
@@ -621,7 +574,7 @@ void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
QPixmap bigPixmap;
if (QPixmapCache::find(key, &bigPixmap)) {
QScreen *screen = qApp->primaryScreen();
qreal dpr = screen->devicePixelRatio();
int dpr = screen->devicePixelRatio();
pixmap = bigPixmap.scaled(size * dpr, Qt::KeepAspectRatio, Qt::SmoothTransformation);
pixmap.setDevicePixelRatio(dpr);
QPixmapCache::insert(sizeKey, pixmap);
@@ -660,11 +613,6 @@ void PictureLoader::clearPixmapCache()
QPixmapCache::clear();
}
void PictureLoader::clearNetworkCache()
{
getInstance().worker->clearNetworkCache();
}
void PictureLoader::cacheCardPixmaps(QList<CardInfoPtr> cards)
{
QPixmap tmp;

View File

@@ -73,7 +73,6 @@ public:
~PictureLoaderWorker() override;
void enqueueImageLoad(CardInfoPtr card);
void clearNetworkCache();
private:
static QStringList md5Blacklist;
@@ -88,9 +87,8 @@ private:
PictureToLoad cardBeingDownloaded;
bool picDownload, downloadRunning, loadQueueRunning;
void startNextPicDownload();
bool cardImageExistsOnDisk(QString &setName, QString &correctedCardName);
bool cardImageExistsOnDisk(QString &, QString &);
bool imageIsBlackListed(const QByteArray &);
QNetworkReply *makeRequest(const QUrl &url);
private slots:
void picDownloadFinished(QNetworkReply *reply);
void picDownloadFailed();
@@ -99,7 +97,6 @@ private slots:
void picsPathChanged();
public slots:
void processLoadQueue();
signals:
void startLoadQueue();
void imageLoaded(CardInfoPtr card, const QImage &image);
@@ -130,14 +127,9 @@ public:
static void clearPixmapCache(CardInfoPtr card);
static void clearPixmapCache();
static void cacheCardPixmaps(QList<CardInfoPtr> cards);
public slots:
static void clearNetworkCache();
private slots:
void picDownloadChanged();
void picsPathChanged();
public slots:
void imageLoaded(CardInfoPtr card, const QImage &image);
};

View File

@@ -28,20 +28,13 @@ QRectF PileZone::boundingRect() const
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
}
QPainterPath PileZone::shape() const
{
QPainterPath shape;
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
return shape;
}
void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
painter->drawPath(shape());
if (!cards.isEmpty())
cards.at(0)->paintPicture(painter, cards.at(0)->getTranslatedSize(painter), 90);
painter->drawRect(QRectF(0.5, 0.5, CARD_WIDTH - 1, CARD_HEIGHT - 1));
painter->translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2);
painter->rotate(-90);
painter->translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2);

View File

@@ -18,18 +18,17 @@ public:
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent = nullptr);
QRectF boundingRect() const override;
QPainterPath shape() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void reorganizeCards() override;
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void reorganizeCards();
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void addCardImpl(CardItem *card, int x, int y) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void addCardImpl(CardItem *card, int x, int y);
};
#endif

View File

@@ -9,7 +9,6 @@
#include "counter_general.h"
#include "deck_loader.h"
#include "dlg_create_token.h"
#include "dlg_roll_dice.h"
#include "gamescene.h"
#include "gettextwithmax.h"
#include "handcounter.h"
@@ -58,24 +57,20 @@
#include "playertarget.h"
#include "settingscache.h"
#include "stackzone.h"
#include "stringsizes.h"
#include "tab_game.h"
#include "tablezone.h"
#include "thememanager.h"
#include "trice_limits.h"
#include "zoneviewwidget.h"
#include "zoneviewzone.h"
#include <QDebug>
#include <QMenu>
#include <QMessageBox>
#include <QMetaType>
#include <QPainter>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
// milliseconds in between triggers of the move top cards until action
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
PlayerArea::PlayerArea(QGraphicsItem *parentItem) : QObject(), QGraphicsItem(parentItem)
{
setCacheMode(DeviceCoordinateCache);
@@ -111,9 +106,9 @@ void PlayerArea::setPlayerZoneId(int _playerZoneId)
}
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, TabGame *_parent)
: QObject(_parent), game(_parent), movingCardsUntil(false), shortcutsActive(false), lastTokenDestroy(true),
lastTokenTableRow(0), id(_id), active(false), local(_local), judge(_judge), mirrored(false), handVisible(false),
conceded(false), zoneId(0), dialogSemaphore(false), deck(nullptr)
: QObject(_parent), game(_parent), shortcutsActive(false), lastTokenDestroy(true), lastTokenTableRow(0), id(_id),
active(false), local(_local), judge(_judge), mirrored(false), handVisible(false), conceded(false), zoneId(0),
dialogSemaphore(false), deck(nullptr)
{
userInfo = new ServerInfo_User;
userInfo->CopyFrom(info);
@@ -127,12 +122,12 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0;
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
auto *_deck = new PileZone(this, "deck", true, false, playerArea);
PileZone *deck = new PileZone(this, "deck", true, false, playerArea);
QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
_deck->setPos(base);
deck->setPos(base);
qreal h = _deck->boundingRect().width() + 5;
qreal h = deck->boundingRect().width() + 5;
auto *handCounter = new HandCounter(playerArea);
handCounter->setPos(base + QPointF(0, h + 10));
@@ -152,7 +147,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
stack = new StackZone(this, (int)table->boundingRect().height(), this);
hand = new HandZone(this, _local || _judge || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()),
hand = new HandZone(this, _local || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()),
(int)table->boundingRect().height(), this);
connect(hand, SIGNAL(cardCountChanged()), handCounter, SLOT(updateNumber()));
connect(handCounter, SIGNAL(showContextMenu(const QPoint &)), hand, SLOT(showContextMenu(const QPoint &)));
@@ -258,8 +253,6 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
connect(aMoveTopCardsToGraveyard, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToGrave()));
aMoveTopCardsToExile = new QAction(this);
connect(aMoveTopCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToExile()));
aMoveTopCardsUntil = new QAction(this);
connect(aMoveTopCardsUntil, SIGNAL(triggered()), this, SLOT(actMoveTopCardsUntil()));
aMoveTopCardToBottom = new QAction(this);
connect(aMoveTopCardToBottom, SIGNAL(triggered()), this, SLOT(actMoveTopCardToBottom()));
@@ -314,7 +307,6 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
libraryMenu->addAction(aViewTopCards);
libraryMenu->addSeparator();
playerLists.append(mRevealLibrary = libraryMenu->addMenu(QString()));
singlePlayerLists.append(mLendLibrary = libraryMenu->addMenu(QString()));
playerLists.append(mRevealTopCard = libraryMenu->addMenu(QString()));
libraryMenu->addAction(aAlwaysRevealTopCard);
libraryMenu->addAction(aAlwaysLookAtTopCard);
@@ -323,7 +315,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
bottomLibraryMenu = libraryMenu->addTearOffMenu(QString());
libraryMenu->addSeparator();
libraryMenu->addAction(aOpenDeckInDeckEditor);
_deck->setMenu(libraryMenu, aDrawCard);
deck->setMenu(libraryMenu, aDrawCard);
topLibraryMenu->addAction(aMoveTopToPlay);
topLibraryMenu->addAction(aMoveTopToPlayFaceDown);
@@ -333,7 +325,6 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
topLibraryMenu->addAction(aMoveTopCardToExile);
topLibraryMenu->addAction(aMoveTopCardsToExile);
topLibraryMenu->addAction(aMoveTopCardsUntil);
bottomLibraryMenu->addAction(aDrawBottomCard);
bottomLibraryMenu->addAction(aDrawBottomCards);
@@ -537,11 +528,6 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
addPlayer(player);
}
moveTopCardTimer = new QTimer(this);
moveTopCardTimer->setInterval(MOVE_TOP_CARD_UNTIL_INTERVAL);
moveTopCardTimer->setSingleShot(true);
connect(moveTopCardTimer, &QTimer::timeout, [this]() { actMoveTopCardToPlay(); });
rearrangeZones();
retranslateUi();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
@@ -583,20 +569,10 @@ void Player::addPlayer(Player *player)
}
for (auto &playerList : playerLists) {
addPlayerToList(playerList, player);
QAction *newAction = playerList->addAction(player->getName());
newAction->setData(player->getId());
connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered()));
}
for (auto &playerList : singlePlayerLists) {
addPlayerToList(playerList, player);
}
playersInfo.append(qMakePair(player->getName(), player->getId()));
}
void Player::addPlayerToList(QMenu *playerList, Player *player)
{
QAction *newAction = playerList->addAction(player->getName());
newAction->setData(player->getId());
connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered()));
}
void Player::removePlayer(Player *player)
@@ -606,29 +582,13 @@ void Player::removePlayer(Player *player)
}
for (auto &playerList : playerLists) {
removePlayerFromList(playerList, player);
QList<QAction *> actionList = playerList->actions();
for (auto &j : actionList)
if (j->data().toInt() == player->getId()) {
playerList->removeAction(j);
j->deleteLater();
}
}
for (auto &playerList : singlePlayerLists) {
removePlayerFromList(playerList, player);
}
for (auto it = playersInfo.begin(); it != playersInfo.end();) {
if (it->second == player->getId()) {
it = playersInfo.erase(it);
} else {
++it;
}
}
}
void Player::removePlayerFromList(QMenu *playerList, Player *player)
{
QList<QAction *> actionList = playerList->actions();
for (auto &j : actionList)
if (j->data().toInt() == player->getId()) {
playerList->removeAction(j);
j->deleteLater();
}
}
void Player::playerListActionTriggered()
@@ -642,9 +602,8 @@ void Player::playerListActionTriggered()
cmd.set_player_id(otherPlayerId);
}
if (menu == mRevealLibrary || menu == mLendLibrary) {
if (menu == mRevealLibrary) {
cmd.set_zone_name("deck");
cmd.set_grant_write_access(menu == mLendLibrary);
} else if (menu == mRevealTopCard) {
int deckSize = zones.value("deck")->getCards().size();
bool ok;
@@ -655,14 +614,14 @@ void Player::playerListActionTriggered()
cmd.set_zone_name("deck");
cmd.set_top_cards(number);
// backward compatibility: servers before #1051 only permits to reveal the first card
cmd.add_card_id(0);
cmd.set_card_id(0);
}
} else if (menu == mRevealHand) {
cmd.set_zone_name("hand");
} else if (menu == mRevealRandomHandCard) {
cmd.set_zone_name("hand");
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
cmd.set_card_id(RANDOM_CARD_FROM_ZONE);
} else {
return;
}
@@ -770,7 +729,6 @@ void Player::retranslateUi()
aViewHand->setText(tr("&View hand"));
aViewTopCards->setText(tr("View &top cards of library..."));
mRevealLibrary->setTitle(tr("Reveal &library to..."));
mLendLibrary->setTitle(tr("Lend library to..."));
mRevealTopCard->setTitle(tr("Reveal &top cards to..."));
topLibraryMenu->setTitle(tr("&Top of library..."));
bottomLibraryMenu->setTitle(tr("&Bottom of library..."));
@@ -786,12 +744,11 @@ void Player::retranslateUi()
aMoveTopToPlay->setText(tr("&Play top card"));
aMoveTopToPlayFaceDown->setText(tr("Play top card &face down"));
aMoveTopCardToBottom->setText(tr("Put top card on &bottom"));
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
aMoveTopCardToBottom->setText(tr("Put top card on &bottom"));
aDrawBottomCard->setText(tr("&Draw bottom card"));
aDrawBottomCards->setText(tr("D&raw bottom cards..."));
@@ -875,7 +832,7 @@ void Player::retranslateUi()
aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(counterColors[i]));
}
aMoveToTopLibrary->setText(tr("&Top of library in random order"));
aMoveToTopLibrary->setText(tr("&Top of library"));
aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library..."));
aMoveToBottomLibrary->setText(tr("&Bottom of library in random order"));
aMoveToHand->setText(tr("&Hand"));
@@ -971,7 +928,6 @@ void Player::setShortcutsActive()
aMoveTopCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToGraveyard"));
aMoveTopCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToExile"));
aMoveTopCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToExile"));
aMoveTopCardsUntil->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsUntil"));
aMoveTopCardToBottom->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToBottom"));
aDrawBottomCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCard"));
aDrawBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCards"));
@@ -1012,7 +968,6 @@ void Player::setShortcutsInactive()
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
aMoveTopCardToExile->setShortcut(QKeySequence());
aMoveTopCardsToExile->setShortcut(QKeySequence());
aMoveTopCardsUntil->setShortcut(QKeySequence());
aDrawBottomCard->setShortcut(QKeySequence());
aDrawBottomCards->setShortcut(QKeySequence());
aMoveBottomToPlay->setShortcut(QKeySequence());
@@ -1045,16 +1000,6 @@ void Player::initSayMenu()
}
}
void Player::initContextualPlayersMenu(QMenu *menu)
{
menu->addAction(tr("&All players"))->setData(-1);
menu->addSeparator();
for (const auto &playerInfo : playersInfo) {
menu->addAction(playerInfo.first)->setData(playerInfo.second);
}
}
void Player::setDeck(const DeckLoader &_deck)
{
deck = new DeckLoader(_deck);
@@ -1141,7 +1086,7 @@ void Player::actRevealRandomGraveyardCard()
cmd.set_player_id(otherPlayerId);
}
cmd.set_zone_name("grave");
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
cmd.set_card_id(RANDOM_CARD_FROM_ZONE);
sendGameCommand(cmd);
}
@@ -1326,47 +1271,6 @@ void Player::actMoveTopCardsToExile()
sendGameCommand(cmd);
}
void Player::actMoveTopCardsUntil()
{
moveTopCardTimer->stop();
movingCardsUntil = false;
QString expr = previousMovingCardsUntilExpr;
for (;;) {
bool ok;
expr = QInputDialog::getText(game, "Put top cards on stack until", "Card name (or search expressions)", {},
expr, &ok);
if (!ok) {
return;
}
movingCardsUntilFilter = FilterString(expr);
if (movingCardsUntilFilter.valid()) {
break;
} else {
auto button = QMessageBox::warning(game, "Invalid filter", movingCardsUntilFilter.error());
if (button != QMessageBox::Ok) {
return;
}
}
}
previousMovingCardsUntilExpr = expr;
if (zones.value("deck")->getCards().empty()) {
movingCardsUntil = false;
} else {
movingCardsUntil = true;
actMoveTopCardToPlay();
}
}
void Player::moveOneCardUntil(const CardInfoPtr card)
{
moveTopCardTimer->stop();
if (zones.value("deck")->getCards().empty() || card.isNull() || movingCardsUntilFilter.check(card)) {
movingCardsUntil = false;
} else {
moveTopCardTimer->start();
}
}
void Player::actMoveTopCardToBottom()
{
if (zones.value("deck")->getCards().empty()) {
@@ -1621,15 +1525,15 @@ void Player::actUntapAll()
void Player::actRollDie()
{
DlgRollDice dlg(game);
if (!dlg.exec()) {
return;
bool ok;
int sides = QInputDialog::getInt(game, tr("Roll die"), tr("Number of sides:"), defaultNumberDieRoll, minDieRoll,
maxDieRoll, 1, &ok);
if (ok) {
defaultNumberDieRoll = sides;
Command_RollDie cmd;
cmd.set_sides(static_cast<google::protobuf::uint32>(sides));
sendGameCommand(cmd);
}
Command_RollDie cmd;
cmd.set_sides(dlg.getDieSideCount());
cmd.set_count(dlg.getDiceToRollCount());
sendGameCommand(cmd);
}
void Player::actCreateToken()
@@ -1753,7 +1657,7 @@ void Player::actCreateAllRelatedCards()
dbName = cardRelationAll->getName();
bool persistent = cardRelationAll->getIsPersistent();
for (int i = 0; i < cardRelationAll->getDefaultCount(); ++i) {
createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent);
createCard(sourceCard, dbName, false, persistent);
}
++tokensTypesCreated;
if (tokensTypesCreated == 1) {
@@ -1768,7 +1672,7 @@ void Player::actCreateAllRelatedCards()
dbName = cardRelationNotExcluded->getName();
bool persistent = cardRelationNotExcluded->getIsPersistent();
for (int i = 0; i < cardRelationNotExcluded->getDefaultCount(); ++i) {
createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent);
createCard(sourceCard, dbName, false, persistent);
}
++tokensTypesCreated;
if (tokensTypesCreated == 1) {
@@ -1807,22 +1711,23 @@ bool Player::createRelatedFromRelation(const CardItem *sourceCard, const CardRel
return false;
}
for (int i = 0; i < count; ++i) {
createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent);
createCard(sourceCard, dbName, false, persistent);
}
} else if (cardRelation->getDefaultCount() > 1) {
for (int i = 0; i < cardRelation->getDefaultCount(); ++i) {
createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent);
createCard(sourceCard, dbName, false, persistent);
}
} else {
createCard(sourceCard, dbName, cardRelation->getAttachType(), persistent);
if (cardRelation->getDoesAttach()) {
createAttachedCard(sourceCard, dbName, persistent);
} else {
createCard(sourceCard, dbName, false, persistent);
}
}
return true;
}
void Player::createCard(const CardItem *sourceCard,
const QString &dbCardName,
CardRelation::AttachType attachType,
bool persistent)
void Player::createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach, bool persistent)
{
CardInfoPtr cardInfo = db->getCard(dbCardName);
@@ -1861,24 +1766,18 @@ void Player::createCard(const CardItem *sourceCard,
cmd.set_x(gridPoint.x());
cmd.set_y(gridPoint.y());
switch (attachType) {
case CardRelation::DoesNotAttach:
break;
case CardRelation::AttachTo:
cmd.set_target_card_id(sourceCard->getId());
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
break;
case CardRelation::TransformInto:
cmd.set_target_card_id(sourceCard->getId());
cmd.set_target_mode(Command_CreateToken::TRANSFORM_INTO);
break;
if (attach) {
cmd.set_target_card_id(sourceCard->getId());
}
sendGameCommand(cmd);
}
void Player::createAttachedCard(const CardItem *sourceCard, const QString &dbCardName, bool persistent)
{
createCard(sourceCard, dbCardName, true, persistent);
}
void Player::actSayMessage()
{
auto *a = qobject_cast<QAction *>(sender());
@@ -1982,21 +1881,7 @@ void Player::eventShuffle(const Event_Shuffle &event)
void Player::eventRollDie(const Event_RollDie &event)
{
if (!event.values().empty()) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QList<uint> rolls(event.values().begin(), event.values().end());
#else
QList<uint> rolls;
for (const auto &value : event.values()) {
rolls.append(value);
}
#endif
std::sort(rolls.begin(), rolls.end());
emit logRollDie(this, static_cast<int>(event.sides()), rolls);
} else if (event.value()) {
// Backwards compatibility for old clients
emit logRollDie(this, static_cast<int>(event.sides()), {event.value()});
}
emit logRollDie(this, event.sides(), event.value());
}
void Player::eventCreateArrow(const Event_CreateArrow &event)
@@ -2131,8 +2016,7 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &
if (!startPlayer) {
return;
}
QString startZoneString = QString::fromStdString(event.start_zone());
CardZone *startZone = startPlayer->getZones().value(startZoneString, 0);
CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(event.start_zone()), 0);
Player *targetPlayer = game->getPlayers().value(event.target_player_id());
if (!targetPlayer) {
return;
@@ -2224,10 +2108,6 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &
}
}
updateCardMenu(card);
if (movingCardsUntil && startZoneString == "deck" && targetZone->getName() == "stack") {
moveOneCardUntil(card->getInfo());
}
}
void Player::eventFlipCard(const Event_FlipCard &event)
@@ -2316,27 +2196,27 @@ void Player::eventAttachCard(const Event_AttachCard &event)
void Player::eventDrawCards(const Event_DrawCards &event)
{
CardZone *_deck = zones.value("deck");
CardZone *_hand = zones.value("hand");
CardZone *deck = zones.value("deck");
CardZone *hand = zones.value("hand");
const int listSize = event.cards_size();
if (listSize) {
for (int i = 0; i < listSize; ++i) {
const ServerInfo_Card &cardInfo = event.cards(i);
CardItem *card = _deck->takeCard(0, cardInfo.id());
CardItem *card = deck->takeCard(0, cardInfo.id());
card->setName(QString::fromStdString(cardInfo.name()));
_hand->addCard(card, false, -1);
hand->addCard(card, false, -1);
}
} else {
const int number = event.number();
for (int i = 0; i < number; ++i) {
_hand->addCard(_deck->takeCard(0, -1), false, -1);
hand->addCard(deck->takeCard(0, -1), false, -1);
}
}
_hand->reorganizeCards();
_deck->reorganizeCards();
emit logDrawCards(this, event.number(), _deck->getCards().size() == 0);
hand->reorganizeCards();
deck->reorganizeCards();
emit logDrawCards(this, event.number(), deck->getCards().size() == 0);
}
void Player::eventRevealCards(const Event_RevealCards &event)
@@ -2377,10 +2257,9 @@ void Player::eventRevealCards(const Event_RevealCards &event)
} else {
bool showZoneView = true;
QString cardName;
auto cardId = event.card_id_size() == 0 ? -1 : event.card_id(0);
if (cardList.size() == 1) {
cardName = QString::fromStdString(cardList.first()->name());
if ((cardId == 0) && dynamic_cast<PileZone *>(zone)) {
if ((event.card_id() == 0) && dynamic_cast<PileZone *>(zone)) {
zone->getCards().first()->setName(cardName);
zone->update();
showZoneView = false;
@@ -2390,9 +2269,8 @@ void Player::eventRevealCards(const Event_RevealCards &event)
static_cast<GameScene *>(scene())->addRevealedZoneView(this, zone, cardList, event.grant_write_access());
}
emit logRevealCards(this, zone, cardId, cardName, otherPlayer, false,
event.has_number_of_cards() ? event.number_of_cards() : cardList.size(),
event.grant_write_access());
emit logRevealCards(this, zone, event.card_id(), cardName, otherPlayer, false,
event.has_number_of_cards() ? event.number_of_cards() : cardList.size());
}
}
@@ -2602,7 +2480,7 @@ void Player::playCard(CardItem *card, bool faceDown, bool tapped)
} else if (!faceDown &&
((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) {
cmd.set_target_zone("stack");
cmd.set_x(-1);
cmd.set_x(0);
cmd.set_y(0);
} else {
tableRow = faceDown ? 2 : info->getTableRow();
@@ -2948,7 +2826,7 @@ void Player::cardMenuAction()
case cmPeek: {
auto *cmd = new Command_RevealCards;
cmd->set_zone_name(card->getZone()->getName().toStdString());
cmd->add_card_id(card->getId());
cmd->set_card_id(card->getId());
cmd->set_player_id(id);
commandList.append(cmd);
break;
@@ -2988,16 +2866,6 @@ void Player::cardMenuAction()
cmd->set_target_zone("deck");
cmd->set_x(0);
cmd->set_y(0);
if (idList.card_size() > 1) {
auto *scmd = new Command_Shuffle;
scmd->set_zone_name("deck");
scmd->set_start(0);
scmd->set_end(idList.card_size());
// Server process events backwards, so...
commandList.append(scmd);
}
commandList.append(cmd);
break;
}
@@ -3202,16 +3070,16 @@ void Player::actSetPT()
if (!empty) {
const auto oldpt = parsePT(card->getPT());
int ptIter = 0;
for (const auto &_item : ptList) {
for (const auto &item : ptList) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (_item.typeId() == QMetaType::Type::Int) {
if (item.typeId() == QMetaType::Type::Int) {
#else
if (_item.type() == QVariant::Int) {
if (item.type() == QVariant::Int) {
#endif
int oldItem = ptIter < oldpt.size() ? oldpt.at(ptIter).toInt() : 0;
newpt += '/' + QString::number(oldItem + _item.toInt());
newpt += '/' + QString::number(oldItem + item.toInt());
} else {
newpt += '/' + _item.toString();
newpt += '/' + item.toString();
}
++ptIter;
}
@@ -3281,16 +3149,6 @@ void Player::actFlowT()
actIncPT(-1, 1);
}
void AnnotationDialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return && event->modifiers() & Qt::ControlModifier) {
event->accept();
accept();
return;
}
QInputDialog::keyPressEvent(event);
}
void Player::actSetAnnotation()
{
QString oldAnnotation;
@@ -3302,18 +3160,15 @@ void Player::actSetAnnotation()
}
}
bool ok;
dialogSemaphore = true;
AnnotationDialog *dialog = new AnnotationDialog(game);
dialog->setOptions(QInputDialog::UsePlainTextEditForTextInput);
dialog->setWindowTitle(tr("Set annotation"));
dialog->setLabelText(tr("Please enter the new annotation:"));
dialog->setTextValue(oldAnnotation);
bool ok = dialog->exec();
QString annotation = QInputDialog::getMultiLineText(game, tr("Set annotation"),
tr("Please enter the new annotation:"), oldAnnotation, &ok)
.left(MAX_NAME_LENGTH);
dialogSemaphore = false;
if (clearCardsToDelete() || !ok) {
return;
}
QString annotation = dialog->textValue().left(MAX_NAME_LENGTH);
QList<const ::google::protobuf::Message *> commandList;
for (const auto &item : sel) {
@@ -3449,27 +3304,6 @@ void Player::actPlayFacedown()
playCard(game->getActiveCard(), true, false);
}
void Player::actReveal(QAction *action)
{
const int otherPlayerId = action->data().toInt();
Command_RevealCards cmd;
if (otherPlayerId != -1) {
cmd.set_player_id(otherPlayerId);
}
QList<QGraphicsItem *> sel = scene()->selectedItems();
while (!sel.isEmpty()) {
const auto *card = qgraphicsitem_cast<CardItem *>(sel.takeFirst());
if (!cmd.has_zone_name()) {
cmd.set_zone_name(card->getZone()->getName().toStdString());
}
cmd.add_card_id(card->getId());
}
sendGameCommand(cmd);
}
void Player::refreshShortcuts()
{
if (shortcutsActive) {
@@ -3595,11 +3429,6 @@ void Player::updateCardMenu(const CardItem *card)
// Card is in hand or a custom zone specified by server
cardMenu->addAction(aPlay);
cardMenu->addAction(aPlayFacedown);
QMenu *revealMenu = cardMenu->addMenu(tr("Re&veal to..."));
initContextualPlayersMenu(revealMenu);
connect(revealMenu, &QMenu::triggered, this, &Player::actReveal);
cardMenu->addMenu(moveMenu);
addRelatedCardView(card, cardMenu);
}
@@ -3674,7 +3503,6 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
CardInfoPtr relatedCard = db->getCard(cardRelation->getName());
if (relatedCard == nullptr)
continue;
QString relatedCardName;
if (relatedCard->getPowTough().size() > 0) {
relatedCardName = relatedCard->getPowTough() + " " + relatedCard->getName(); // "n/n name"
@@ -3684,8 +3512,7 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
QString text = tr("Token: ");
if (cardRelation->getDoesAttach()) {
text +=
tr(cardRelation->getDoesTransform() ? "Transform into " : "Attach to ") + "\"" + relatedCardName + "\"";
text += tr("Attach to ") + "\"" + relatedCardName + "\"";
} else if (cardRelation->getIsVariable()) {
text += "X " + relatedCardName;
} else if (cardRelation->getDefaultCount() != 1) {

View File

@@ -3,7 +3,6 @@
#include "abstractgraphicsitem.h"
#include "carddatabase.h"
#include "filter_string.h"
#include "pb/card_attributes.pb.h"
#include "pb/game_event.pb.h"
#include "tearoffmenu.h"
@@ -11,7 +10,6 @@
#include <QInputDialog>
#include <QMap>
#include <QPoint>
#include <QTimer>
namespace google
{
@@ -114,7 +112,7 @@ signals:
// Log events
void logSay(Player *player, QString message);
void logShuffle(Player *player, CardZone *zone, int start, int end);
void logRollDie(Player *player, int sides, const QList<uint> &rolls);
void logRollDie(Player *player, int sides, int roll);
void logCreateArrow(Player *player,
Player *startPlayer,
QString startCard,
@@ -142,8 +140,7 @@ signals:
QString cardName,
Player *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer = false);
int amount);
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
void logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal);
@@ -165,7 +162,6 @@ public slots:
void actMoveTopCardToExile();
void actMoveTopCardsToGrave();
void actMoveTopCardsToExile();
void actMoveTopCardsUntil();
void actMoveTopCardToBottom();
void actDrawBottomCard();
void actDrawBottomCards();
@@ -221,29 +217,26 @@ private slots:
void actPlay();
void actHide();
void actPlayFacedown();
void actReveal(QAction *action);
void refreshShortcuts();
private:
TabGame *game;
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mLendLibrary, *mRevealTopCard,
*mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard;
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mRevealTopCard, *mRevealHand,
*mRevealRandomHandCard, *mRevealRandomGraveyardCard;
TearOffMenu *moveGraveMenu, *moveRfgMenu, *graveMenu, *moveHandMenu, *handMenu, *libraryMenu, *topLibraryMenu,
*bottomLibraryMenu, *rfgMenu, *playerMenu;
QList<QMenu *> playerLists;
QList<QMenu *> singlePlayerLists;
QList<QAction *> allPlayersActions;
QList<QPair<QString, int>> playersInfo;
QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, *aMoveHandToGrave, *aMoveHandToRfg,
*aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary,
*aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, *aViewHand, *aViewLibrary, *aViewTopCards,
*aAlwaysRevealTopCard, *aAlwaysLookAtTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard,
*aMoveTopCardToExile, *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardsUntil,
*aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw,
*aMulligan, *aShuffle, *aMoveTopToPlay, *aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken,
*aCreateAnotherToken, *aCardMenu, *aMoveBottomToPlay, *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop,
*aMoveBottomCardToGraveyard, *aMoveBottomCardToExile, *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile,
*aDrawBottomCard, *aDrawBottomCards;
*aMoveTopCardToExile, *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard,
*aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlay,
*aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, *aCardMenu,
*aMoveBottomToPlay, *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, *aMoveBottomCardToGraveyard,
*aMoveBottomCardToExile, *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, *aDrawBottomCard,
*aDrawBottomCards;
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT,
@@ -251,16 +244,13 @@ private:
*aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile,
*aMoveToXfromTopOfLibrary;
bool movingCardsUntil;
QTimer *moveTopCardTimer;
QString previousMovingCardsUntilExpr = {};
FilterString movingCardsUntilFilter;
bool shortcutsActive;
int defaultNumberTopCards = 1;
int defaultNumberTopCardsToPlaceBelow = 1;
int defaultNumberBottomCards = 1;
int defaultNumberDieRoll = 20;
static constexpr int minDieRoll = 2;
static constexpr int maxDieRoll = 1000000;
QString lastTokenName, lastTokenColor, lastTokenPT, lastTokenAnnotation;
bool lastTokenDestroy;
int lastTokenTableRow;
@@ -295,14 +285,10 @@ private:
bool allCards);
void addRelatedCardActions(const CardItem *card, QMenu *cardMenu);
void addRelatedCardView(const CardItem *card, QMenu *cardMenu);
void createCard(const CardItem *sourceCard,
const QString &dbCardName,
CardRelation::AttachType attach = CardRelation::DoesNotAttach,
bool persistent = false);
void
createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach = false, bool persistent = false);
void createAttachedCard(const CardItem *sourceCard, const QString &dbCardName, bool persistent = false);
bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation);
void moveOneCardUntil(const CardInfoPtr card);
void addPlayerToList(QMenu *playerList, Player *player);
static void removePlayerFromList(QMenu *playerList, Player *player);
QRectF bRect;
@@ -311,7 +297,6 @@ private:
void rearrangeCounters();
void initSayMenu();
void initContextualPlayersMenu(QMenu *menu);
// void eventConnectionStateChanged(const Event_ConnectionStateChanged &event);
void eventGameSay(const Event_GameSay &event);
@@ -479,15 +464,4 @@ public:
void setLastToken(CardInfoPtr cardInfo);
};
class AnnotationDialog : public QInputDialog
{
Q_OBJECT
void keyPressEvent(QKeyEvent *e) override;
public:
AnnotationDialog(QWidget *parent) : QInputDialog(parent)
{
}
};
#endif

View File

@@ -42,7 +42,7 @@ void ReleaseChannel::checkForUpdates()
}
// Different release channel checking functions for different operating systems
#if defined(Q_OS_MACOS)
#if defined(Q_OS_OSX)
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
{
static QRegularExpression version_regex("macOS-(\\d+)\\.(\\d+)");

View File

@@ -32,7 +32,6 @@ RemoteClient::RemoteClient(QObject *parent)
{
clearNewClientFeatures();
maxTimeout = SettingsCache::instance().getTimeOut();
int keepalive = SettingsCache::instance().getKeepAlive();
timer = new QTimer(this);
timer->setInterval(keepalive * 1000);

View File

@@ -89,7 +89,7 @@ private slots:
void submitForgotPasswordChallengeResponse(const Response &response);
private:
int maxTimeout;
static const int maxTimeout = 5;
int timeRunning, lastDataReceived;
QByteArray inputBuffer;
bool messageInProgress;

Some files were not shown because too many files have changed in this diff Show More