mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-15 23:12:14 -07:00
Merge branch 'master' into game-time-part2-checkbox
This commit is contained in:
commit
dee3d6998f
87 changed files with 3472 additions and 2613 deletions
127
.github/CONTRIBUTING.md
vendored
127
.github/CONTRIBUTING.md
vendored
|
|
@ -7,32 +7,33 @@
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
# Contributing to Cockatrice #
|
# Contributing to Cockatrice #
|
||||||
First off, thanks for taking the time to contribute to our project! 🎉 ❤ ️✨
|
|
||||||
|
|
||||||
The following is a set of guidelines for contributing to Cockatrice. These are
|
First off, thanks for taking the time and considering to lend a helping hand to our project! 🎉 ❤ ️✨
|
||||||
mostly guidelines, not rules. Use your best judgment, and feel free to propose
|
|
||||||
changes to this document in a pull request.
|
> [!NOTE]
|
||||||
|
> The following is a set of guidelines for contributing to Cockatrice.
|
||||||
|
> These are mostly guidelines, not rules. Use your best judgment, and feel free to
|
||||||
|
> propose changes to this document in a pull request.
|
||||||
|
>
|
||||||
|
> [](
|
||||||
|
> https://discord.gg/3Z9yzmA)
|
||||||
|
> If you'd like to ask questions, get advice, or just want to say "Hi",
|
||||||
|
> the Cockatrice Development Team uses [Discord](https://discord.gg/ZASRzKu)
|
||||||
|
> for communications and you can reach out in the `#dev` channel.
|
||||||
|
|
||||||
|
|
||||||
# Recommended Setups #
|
# Recommended Setups #
|
||||||
|
|
||||||
For those developers who like the Linux or MacOS environment, many of our
|
For those developers on **Linux** or **macOS** environment, many of our
|
||||||
developers like working with a nifty program called [CLion](
|
developers like working with a nifty program called [CLion](
|
||||||
https://www.jetbrains.com/clion/). The program's a great asset and one of the
|
https://www.jetbrains.com/clion/). The program is a great asset and one of the
|
||||||
best tools you'll find on these systems, but you're welcomed to use any IDE
|
best tools you'll find on these systems.
|
||||||
you most enjoy.
|
|
||||||
|
|
||||||
Developers who like Windows development tend to find [Visual Studio](
|
Developers on **Windows** systems tend to find [Visual Studio](
|
||||||
https://www.visualstudio.com/) the best tool for the job.
|
https://www.visualstudio.com/) the best tool for the job.
|
||||||
|
|
||||||
[](https://discord.gg/ZASRzKu)
|
But you're welcomed to use any IDE you enjoy most of course!
|
||||||
[](https://gitter.im/Cockatrice/Cockatrice)
|
|
||||||
|
|
||||||
If you'd like to ask questions, get advice, or just want to say hi,
|
|
||||||
the Cockatrice Development Team uses [Discord](https://discord.gg/ZASRzKu)
|
|
||||||
for communications in the #dev channel. If you're not into Discord, we also
|
|
||||||
have a [Gitter](https://gitter.im/Cockatrice/Cockatrice) channel available,
|
|
||||||
albeit slightly less active.
|
|
||||||
|
|
||||||
|
|
||||||
# Code Style Guide #
|
# Code Style Guide #
|
||||||
|
|
@ -64,7 +65,7 @@ information on our formatting guidelines.
|
||||||
|
|
||||||
### Compatibility ###
|
### Compatibility ###
|
||||||
|
|
||||||
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>.
|
Cockatrice is currently compiled on all platforms using <kbd>C++20</kbd>.
|
||||||
You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free
|
You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free
|
||||||
to help convert it over!
|
to help convert it over!
|
||||||
|
|
||||||
|
|
@ -78,11 +79,12 @@ or other appropriate conversion.
|
||||||
### Formatting ###
|
### Formatting ###
|
||||||
|
|
||||||
The handy tool `clang-format` can format your code for you, it is available for
|
The handy tool `clang-format` can format your code for you, it is available for
|
||||||
almost any environment. A special `.clang-format` configuration file is
|
almost any environment. A special [`.clang-format`](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/blob/master/.clang-format) configuration file is
|
||||||
included in the project and is used to format your code.
|
included in the project and is used to format your code.
|
||||||
|
|
||||||
We've also included a bash script, `format.sh`, that will use clang-format to
|
We've also included a bash script, `format.sh`, that will use clang-format to
|
||||||
format all files in your pr in one go. Use `./format.sh --help` to show a full
|
format all files in your PR in one go. Use `./format.sh --help` to show a full
|
||||||
help page.
|
help page.
|
||||||
|
|
||||||
To run clang-format on a single source file simply use the command
|
To run clang-format on a single source file simply use the command
|
||||||
|
|
@ -90,10 +92,10 @@ To run clang-format on a single source file simply use the command
|
||||||
clang-format with a specific version number appended,
|
clang-format with a specific version number appended,
|
||||||
`find /usr/bin -name clang-format*` should find it for you)
|
`find /usr/bin -name clang-format*` should find it for you)
|
||||||
|
|
||||||
See [the clang-format documentation](
|
See the [clang-format documentation](
|
||||||
https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
|
https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
|
||||||
|
|
||||||
#### Header files ####
|
#### Header Files ####
|
||||||
|
|
||||||
Use header files with the extension `.h` and source files with the extension
|
Use header files with the extension `.h` and source files with the extension
|
||||||
`.cpp`.
|
`.cpp`.
|
||||||
|
|
@ -234,7 +236,7 @@ mutating objects.)
|
||||||
When pointers can't be avoided, try to use a smart pointer of some sort, such
|
When pointers can't be avoided, try to use a smart pointer of some sort, such
|
||||||
as `QScopedPointer`, or, less preferably, `QSharedPointer`.
|
as `QScopedPointer`, or, less preferably, `QSharedPointer`.
|
||||||
|
|
||||||
### Database migrations ###
|
### Database Migrations ###
|
||||||
|
|
||||||
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
||||||
Everytime the schema gets modified, some other steps are due:
|
Everytime the schema gets modified, some other steps are due:
|
||||||
|
|
@ -255,7 +257,7 @@ Ensure that the migration produces the expected effects; e.g. if you add a
|
||||||
new column, make sure the migration places it in the same order as
|
new column, make sure the migration places it in the same order as
|
||||||
servatrice.sql.
|
servatrice.sql.
|
||||||
|
|
||||||
### Protocol buffer ###
|
### Protocol Buffer ###
|
||||||
|
|
||||||
Cockatrice and Servatrice exchange data using binary messages. The syntax of
|
Cockatrice and Servatrice exchange data using binary messages. The syntax of
|
||||||
these messages is defined in the `proto` files in the `common/pb` folder. These
|
these messages is defined in the `proto` files in the `common/pb` folder. These
|
||||||
|
|
@ -268,6 +270,7 @@ new clients incompatible to the old server and vice versa.
|
||||||
You can find more information on how we use Protobuf on [our wiki!](
|
You can find more information on how we use Protobuf on [our wiki!](
|
||||||
https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
||||||
|
|
||||||
|
|
||||||
# Reviewing Pull Requests #
|
# Reviewing Pull Requests #
|
||||||
|
|
||||||
After you have finished your changes to the project you should put them on a
|
After you have finished your changes to the project you should put them on a
|
||||||
|
|
@ -286,6 +289,7 @@ all changes have been approved your pull request will be squashed into a single
|
||||||
commit and merged into the master branch by a team member. Your change will then
|
commit and merged into the master branch by a team member. Your change will then
|
||||||
be included in the next release 👍
|
be included in the next release 👍
|
||||||
|
|
||||||
|
|
||||||
# Translations #
|
# Translations #
|
||||||
|
|
||||||
Basic workflow for translations:
|
Basic workflow for translations:
|
||||||
|
|
@ -294,16 +298,16 @@ Basic workflow for translations:
|
||||||
3. Maintainer verifies and merges the change;
|
3. Maintainer verifies and merges the change;
|
||||||
4. Transifex picks up the new files from GitHub automatically;
|
4. Transifex picks up the new files from GitHub automatically;
|
||||||
5. Translators translate the new untranslated strings on Transifex;
|
5. Translators translate the new untranslated strings on Transifex;
|
||||||
6. Before a release, a maintainer fetches the updated translations from Transifex.
|
6. Before a release, a maintainer fetches the newest translations from Transifex.
|
||||||
|
|
||||||
### Using Translations (for developers) ###
|
### Using Translations (for developers) ###
|
||||||
|
|
||||||
All user interface strings inside Cockatrice's source code must be written
|
All user interface strings inside Cockatrice's source code must be written
|
||||||
in English (US).
|
in English (US).
|
||||||
Translations to other languages are managed using [Transifex](
|
Translations to other languages are managed using [Transifex](
|
||||||
https://www.transifex.com/projects/p/cockatrice/).
|
https://transifex.com/cockatrice/cockatrice/).
|
||||||
|
|
||||||
Adding a new string to translate is as easy as adding the string in the
|
Adding a new string for translation 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.
|
and translated as needed.
|
||||||
For example, setting the text of a label in the way that the string
|
For example, setting the text of a label in the way that the string
|
||||||
|
|
@ -315,9 +319,9 @@ nameLabel.setText(tr("My name is:"));
|
||||||
To translate a string that would have plural forms you can add the amount to
|
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++
|
```c++
|
||||||
QString message = tr("Everyone draws %n cards", "pop up message", amount);
|
QString message = tr("Everyone draws %n cards", "english hint for translators", amount);
|
||||||
```
|
```
|
||||||
See [QT's wiki on translations](
|
See [Qt's wiki on translations](
|
||||||
https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
|
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
|
If you're about to propose a change that adds or modifies any translatable
|
||||||
|
|
@ -325,7 +329,7 @@ string in the code, you don't need to take care of adding the new strings to
|
||||||
the translation files.<br>
|
the translation files.<br>
|
||||||
We have an automated process to update our language source files on a schedule
|
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>
|
and provide the translators on Transifex with the new contents.<br>
|
||||||
Maintainers can also manually trigger this on demand.
|
Maintainers can also manually trigger this workflow on demand via GitHub Actions.
|
||||||
|
|
||||||
### Maintaining Translations (for maintainers) ###
|
### Maintaining Translations (for maintainers) ###
|
||||||
|
|
||||||
|
|
@ -389,27 +393,27 @@ Now you are ready to commit your changes and open a PR.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
Once the changes get merged, Transifex will pick up the modified files
|
Once the changes get merged, Transifex will pick up the modified files
|
||||||
automatically (checked every few hours) and update their online editor where
|
automatically (checked every few hours) and update the web editor where
|
||||||
translators will be able to translate the new strings right in the browser.
|
translators will be able to translate the new strings right in the browser.
|
||||||
|
|
||||||
### Releasing Translations (for maintainers) ###
|
### Releasing Translations (for maintainers) ###
|
||||||
|
|
||||||
Before rushing out a new release, a maintainer should fetch the most up to date
|
Before publishing a new release, a maintainer should fetch the most up to date
|
||||||
translations from Transifex and commit them into the Cockatrice source code.
|
translations from Transifex and commit them into the Cockatrice source code.
|
||||||
This can be done manually from the Transifex web interface, but it's quite time
|
We utilize the official GitHub integration to push all languages that are 100%
|
||||||
consuming.
|
translated from Transifex to our GitHub repo automatically.
|
||||||
|
On top, it runs on a quarterly schedule to update changes for incomplete languages.
|
||||||
As an alternative, you can install the Transifex CLI:
|
A synchronisation/update can also be triggered manually from the Transifex web interface
|
||||||
|
and a translation treshold can be set.
|
||||||
http://docs.transifex.com/developer/client/
|
|
||||||
|
|
||||||
|
As an alternative, you can install the [Transifex CLI](https://developers.transifex.com/docs/cli).
|
||||||
You'll then be able to use a git-like cli command to push and pull translations
|
You'll then be able to use a git-like cli command to push and pull translations
|
||||||
from Transifex to the source code and vice versa.
|
from Transifex to the source code and vice versa.
|
||||||
|
|
||||||
### Adding Translations (for translators) ###
|
### Adding Translations (for translators) ###
|
||||||
|
|
||||||
As a translator you can help translate the new strings on [Transifex](
|
As a translator, you can help to translate new strings on [Transifex](
|
||||||
https://www.transifex.com/projects/p/cockatrice/).
|
https://www.transifex.com/projects/p/cockatrice/) to your native language.
|
||||||
Please have a look at the specific [FAQ for translators](
|
Please have a look at the specific [FAQ for translators](
|
||||||
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
||||||
|
|
||||||
|
|
@ -419,9 +423,9 @@ https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
||||||
### Publishing A New Release ###
|
### Publishing A New Release ###
|
||||||
|
|
||||||
We use [GitHub Releases](https://github.com/Cockatrice/Cockatrice/releases) to
|
We use [GitHub Releases](https://github.com/Cockatrice/Cockatrice/releases) to
|
||||||
publish new stable versions and betas.
|
publish new stable versions and beta releases.
|
||||||
Whenever a git tag is pushed to the repository github will create a draft
|
Whenever a git tag is pushed to the repository, GitHub will create a draft
|
||||||
release and upload binaries automatically.
|
release and upload binaries from our CI automatically.
|
||||||
|
|
||||||
To create a tag, simply do the following:
|
To create a tag, simply do the following:
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -433,18 +437,16 @@ git push $UPSTREAM $TAG_NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
You should define the variables as such:
|
You should define the variables as such:
|
||||||
```
|
- `$UPSTREAM`: the remote for `git@github.com:Cockatrice/Cockatrice.git`
|
||||||
`$UPSTREAM` - the remote for git@github.com:Cockatrice/Cockatrice.git
|
- `$TAG_NAME` should be formatted as:
|
||||||
`$TAG_NAME` should be formatted as:
|
|
||||||
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
|
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
|
||||||
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
|
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
|
||||||
With *MAJ.MIN.PATCH* being the NEXT release version!
|
With <kbd>MAJ</kbd>.<kbd>MIN</kbd>.<kbd>PATCH</kbd> being the NEXT release version!
|
||||||
```
|
|
||||||
|
|
||||||
This will cause a tagged release to be established on the GitHub repository,
|
This will cause a tagged release to be established on the GitHub repository,
|
||||||
with the binaries being added to the release whenever they are ready.
|
with the binaries being added to the release whenever they are done building in CI.
|
||||||
The release is initially a draft, where the path notes can be edited and after
|
The release is initially a draft, where the release notes can be edited and after
|
||||||
all is good and ready it can be published on GitHub.
|
all is checked and ready, it can be published as GitHub release.
|
||||||
If you use a SemVer tag including "beta", the release that will be created at
|
If you use a SemVer tag including "beta", the release that will be created at
|
||||||
GitHub will be marked as a "Pre-release" automatically.
|
GitHub will be marked as a "Pre-release" automatically.
|
||||||
The target of the `.../latest` URL will not be changed in that case, it always
|
The target of the `.../latest` URL will not be changed in that case, it always
|
||||||
|
|
@ -457,7 +459,7 @@ revoke the tag by doing the following:
|
||||||
git push --delete upstream $TAG_NAME
|
git push --delete upstream $TAG_NAME
|
||||||
git tag -d $TAG_NAME
|
git tag -d $TAG_NAME
|
||||||
```
|
```
|
||||||
You can also do this on GitHub, you'll also want to delete the new release.
|
You can also do this on GitHub, you'll also want to delete the false release.
|
||||||
|
|
||||||
In the first lines of [CMakeLists.txt](
|
In the first lines of [CMakeLists.txt](
|
||||||
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
||||||
|
|
@ -468,25 +470,24 @@ coming from the tag title, it's good practice to increment the ones at CMake
|
||||||
after every full release to stress that master is ahead of the last stable
|
after every full release to stress that master is ahead of the last stable
|
||||||
release.
|
release.
|
||||||
The preferred flow of operation is:
|
The preferred flow of operation is:
|
||||||
* Just before a release, make sure the version number in CMakeLists.txt is set
|
- Just before a release, make sure the version number in CMakeLists.txt is set
|
||||||
to the same release version you are about to tag.
|
to the same release version you are about to tag.
|
||||||
* This is also the time to change the pretty name in CMakeLists.txt called
|
- This is also the time to change the pretty name in CMakeLists.txt called
|
||||||
GIT_TAG_RELEASENAME and commit and push these changes.
|
`GIT_TAG_RELEASENAME` and commit and push these changes.
|
||||||
* Tag the release following the previously described syntax in order to get it
|
- Tag the release following the previously described syntax in order to get it
|
||||||
correctly built and deployed by CI.
|
correctly built and deployed by CI.
|
||||||
* Wait for the configure step to create the release and update the patch
|
- Wait for the configuration step to create the release and update the patch
|
||||||
notes.
|
notes.
|
||||||
* Check on the github actions page for build progress which should be the top
|
- Check on the GitHub Actions page for build progress which should be the top
|
||||||
listed [here](
|
listed [here](
|
||||||
https://github.com/Cockatrice/Cockatrice/actions?query=event%3Apush+-branch%3Amaster
|
https://github.com/Cockatrice/Cockatrice/actions?query=event%3Apush+-branch%3Amaster
|
||||||
).
|
).
|
||||||
* When the build has been completed you can verify all uploaded files on the
|
- When the build has been completed, you can verify if all uploaded files on the
|
||||||
release are in order and hit the publish button.
|
draft release are included and hit the publish button.
|
||||||
* After the release is complete, update the CMake version number again to the
|
- After the release is complete, update the CMake version number again to the
|
||||||
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
|
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
|
||||||
one.
|
one.
|
||||||
|
|
||||||
When releasing a new stable version, all previous beta releases (and tags)
|
When releasing a new stable version, all previous beta releases (and tags)
|
||||||
should be deleted. This is needed for Cockatrice to update users of the "Beta"
|
should be deleted as well.
|
||||||
release channel correctly to the latest stable version as well.
|
|
||||||
This can be done the same way as revoking tags, mentioned above.
|
This can be done the same way as revoking tags, mentioned above.
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,6 @@ RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=
|
||||||
|
|
||||||
WORKDIR /home/servatrice
|
WORKDIR /home/servatrice
|
||||||
|
|
||||||
EXPOSE 4747 4748
|
EXPOSE 4748
|
||||||
|
|
||||||
ENTRYPOINT [ "servatrice", "--log-to-console" ]
|
ENTRYPOINT [ "servatrice", "--log-to-console" ]
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,9 @@ First, create an image from the Dockerfile<br>
|
||||||
`cd /path/to/Cockatrice-Repo/`
|
`cd /path/to/Cockatrice-Repo/`
|
||||||
`docker build -t servatrice .`<br>
|
`docker build -t servatrice .`<br>
|
||||||
And then run it<br>
|
And then run it<br>
|
||||||
`docker run -i -p 4747:4747/tcp -t servatrice:latest`<br>
|
`docker run -i -p 4748:4748 -t servatrice:latest`<br>
|
||||||
|
|
||||||
>Note: Running this command exposes the TCP port 4747 of the docker container<br>
|
>Note: Running this command exposes the port 4748 of the docker container<br>
|
||||||
to permit connections to the server.
|
to permit connections to the server.
|
||||||
|
|
||||||
Find more information on how to use Servatrice with Docker in our [wiki](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
|
Find more information on how to use Servatrice with Docker in our [wiki](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
|
||||||
|
|
@ -145,7 +145,7 @@ docker-compose build # Build the Servatrice image using the same Dockerfile a
|
||||||
docker-compose up # Setup and run both the MySQL server and Servatrice.
|
docker-compose up # Setup and run both the MySQL server and Servatrice.
|
||||||
```
|
```
|
||||||
|
|
||||||
>Note: Similar to the above Docker setup, this will expose TCP ports 4747 and 4748.
|
>Note: Similar to the above Docker setup, this will expose port 4748.
|
||||||
|
|
||||||
>Note: The first time running the docker-compose setup, the MySQL server will take a little time to run the initial setup scripts. Due to this, the Servatrice instance may fail the first few attempts to connect to the database. Servatrice is set to `restart: always` in the docker-compose.yml, which will allow it to continue attempting to start up. Once the MySQL scripts have completed, Servatrice should then connect automatically on the next attempt.
|
>Note: The first time running the docker-compose setup, the MySQL server will take a little time to run the initial setup scripts. Due to this, the Servatrice instance may fail the first few attempts to connect to the database. Servatrice is set to `restart: always` in the docker-compose.yml, which will allow it to continue attempting to start up. Once the MySQL scripts have completed, Servatrice should then connect automatically on the next attempt.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,206 +4,9 @@
|
||||||
|
|
||||||
project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||||
|
|
||||||
set(cockatrice_SOURCES
|
file(GLOB_RECURSE cockatrice_CPP_FILES CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp)
|
||||||
src/game/cards/abstract_card_drag_item.cpp
|
|
||||||
src/game/cards/abstract_card_item.cpp
|
set(cockatrice_SOURCES ${cockatrice_CPP_FILES} ${VERSION_STRING_CPP})
|
||||||
src/client/game_logic/abstract_client.cpp
|
|
||||||
src/game/board/abstract_counter.cpp
|
|
||||||
src/game/board/abstract_graphics_item.cpp
|
|
||||||
src/game/board/arrow_item.cpp
|
|
||||||
src/game/board/arrow_target.cpp
|
|
||||||
src/client/ui/widgets/general/display/banner_widget.cpp
|
|
||||||
src/game/cards/card_database.cpp
|
|
||||||
src/game/cards/card_database_manager.cpp
|
|
||||||
src/game/cards/card_database_model.cpp
|
|
||||||
src/game/cards/card_database_parser/card_database_parser.cpp
|
|
||||||
src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
|
||||||
src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
|
||||||
src/game/cards/card_drag_item.cpp
|
|
||||||
src/game/filters/filter_card.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_frame_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_picture_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_text_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_display_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_size_widget.cpp
|
|
||||||
src/game/cards/card_item.cpp
|
|
||||||
src/game/cards/card_list.cpp
|
|
||||||
src/game/zones/card_zone.cpp
|
|
||||||
src/server/chat_view/chat_view.cpp
|
|
||||||
src/game/board/counter_general.cpp
|
|
||||||
src/deck/custom_line_edit.cpp
|
|
||||||
src/deck/deck_loader.cpp
|
|
||||||
src/deck/deck_list_model.cpp
|
|
||||||
src/deck/deck_stats_interface.cpp
|
|
||||||
src/dialogs/dlg_connect.cpp
|
|
||||||
src/dialogs/dlg_convert_deck_to_cod_format.cpp
|
|
||||||
src/dialogs/dlg_create_token.cpp
|
|
||||||
src/dialogs/dlg_create_game.cpp
|
|
||||||
src/dialogs/dlg_edit_avatar.cpp
|
|
||||||
src/dialogs/dlg_edit_password.cpp
|
|
||||||
src/dialogs/dlg_edit_tokens.cpp
|
|
||||||
src/dialogs/dlg_edit_user.cpp
|
|
||||||
src/dialogs/dlg_filter_games.cpp
|
|
||||||
src/dialogs/dlg_forgot_password_challenge.cpp
|
|
||||||
src/dialogs/dlg_forgot_password_request.cpp
|
|
||||||
src/dialogs/dlg_forgot_password_reset.cpp
|
|
||||||
src/dialogs/dlg_load_deck_from_clipboard.cpp
|
|
||||||
src/dialogs/dlg_load_remote_deck.cpp
|
|
||||||
src/dialogs/dlg_manage_sets.cpp
|
|
||||||
src/dialogs/dlg_move_top_cards_until.cpp
|
|
||||||
src/dialogs/dlg_register.cpp
|
|
||||||
src/dialogs/dlg_roll_dice.cpp
|
|
||||||
src/dialogs/dlg_settings.cpp
|
|
||||||
src/dialogs/dlg_tip_of_the_day.cpp
|
|
||||||
src/dialogs/dlg_update.cpp
|
|
||||||
src/dialogs/dlg_view_log.cpp
|
|
||||||
src/dialogs/dlg_load_deck.cpp
|
|
||||||
src/game/deckview/deck_view.cpp
|
|
||||||
src/game/deckview/deck_view_container.cpp
|
|
||||||
src/game/filters/filter_string.cpp
|
|
||||||
src/game/filters/filter_builder.cpp
|
|
||||||
src/game/filters/filter_tree.cpp
|
|
||||||
src/game/filters/filter_tree_model.cpp
|
|
||||||
src/client/ui/layouts/flow_layout.cpp
|
|
||||||
src/client/ui/widgets/general/layout_containers/flow_widget.cpp
|
|
||||||
src/game/game_scene.cpp
|
|
||||||
src/game/game_selector.cpp
|
|
||||||
src/game/games_model.cpp
|
|
||||||
src/game/game_view.cpp
|
|
||||||
src/client/get_text_with_max.cpp
|
|
||||||
src/game/hand_counter.cpp
|
|
||||||
src/server/handle_public_servers.cpp
|
|
||||||
src/game/zones/hand_zone.cpp
|
|
||||||
src/client/game_logic/key_signals.cpp
|
|
||||||
src/client/ui/line_edit_completer.cpp
|
|
||||||
src/server/local_client.cpp
|
|
||||||
src/server/local_server.cpp
|
|
||||||
src/server/local_server_interface.cpp
|
|
||||||
src/utility/logger.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_picture_enlarged_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/additional_info/color_identity_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/additional_info/mana_cost_widget.cpp
|
|
||||||
src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
|
|
||||||
src/client/ui/widgets/general/display/banner_widget.cpp
|
|
||||||
src/client/ui/widgets/general/display/labeled_input.cpp
|
|
||||||
src/client/ui/widgets/general/display/dynamic_font_size_label.cpp
|
|
||||||
src/client/ui/widgets/general/display/dynamic_font_size_push_button.cpp
|
|
||||||
src/client/ui/widgets/general/display/shadow_background_label.cpp
|
|
||||||
src/main.cpp
|
|
||||||
src/server/message_log_widget.cpp
|
|
||||||
src/client/ui/layouts/overlap_layout.cpp
|
|
||||||
src/client/ui/widgets/general/layout_containers/overlap_widget.cpp
|
|
||||||
src/client/ui/widgets/general/layout_containers/overlap_control_widget.cpp
|
|
||||||
src/server/pending_command.cpp
|
|
||||||
src/game/phase.cpp
|
|
||||||
src/client/ui/phases_toolbar.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader.cpp
|
|
||||||
src/client/ui/picture_loader/picture_loader_worker.cpp
|
|
||||||
src/client/ui/picture_loader/picture_to_load.cpp
|
|
||||||
src/game/zones/pile_zone.cpp
|
|
||||||
src/client/ui/pixel_map_generator.cpp
|
|
||||||
src/game/player/player.cpp
|
|
||||||
src/game/player/player_list_widget.cpp
|
|
||||||
src/game/player/player_target.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/all_zones_card_amount_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/card_amount_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_display_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_search_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_selection_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/printing_selector_card_sorting_widget.cpp
|
|
||||||
src/client/ui/widgets/printing_selector/set_name_and_collectors_number_display_widget.cpp
|
|
||||||
src/client/ui/widgets/quick_settings/settings_button_widget.cpp
|
|
||||||
src/client/ui/widgets/quick_settings/settings_popup_widget.cpp
|
|
||||||
src/client/network/release_channel.cpp
|
|
||||||
src/client/network/client_update_checker.cpp
|
|
||||||
src/server/remote/remote_client.cpp
|
|
||||||
src/server/remote/remote_decklist_tree_widget.cpp
|
|
||||||
src/server/remote/remote_replay_list_tree_widget.cpp
|
|
||||||
src/client/network/replay_timeline_widget.cpp
|
|
||||||
src/game/zones/select_zone.cpp
|
|
||||||
src/utility/sequence_edit.cpp
|
|
||||||
src/client/network/sets_model.cpp
|
|
||||||
src/settings/card_database_settings.cpp
|
|
||||||
src/settings/download_settings.cpp
|
|
||||||
src/settings/game_filters_settings.cpp
|
|
||||||
src/settings/layouts_settings.cpp
|
|
||||||
src/settings/message_settings.cpp
|
|
||||||
src/settings/recents_settings.cpp
|
|
||||||
src/settings/servers_settings.cpp
|
|
||||||
src/settings/settings_manager.cpp
|
|
||||||
src/settings/cache_settings.cpp
|
|
||||||
src/settings/shortcuts_settings.cpp
|
|
||||||
src/settings/shortcut_treeview.cpp
|
|
||||||
src/settings/card_override_settings.cpp
|
|
||||||
src/settings/debug_settings.cpp
|
|
||||||
src/client/sound_engine.cpp
|
|
||||||
src/client/network/spoiler_background_updater.cpp
|
|
||||||
src/game/zones/stack_zone.cpp
|
|
||||||
src/client/tabs/tab.cpp
|
|
||||||
src/client/tabs/tab_account.cpp
|
|
||||||
src/client/tabs/tab_admin.cpp
|
|
||||||
src/client/tabs/abstract_tab_deck_editor.cpp
|
|
||||||
src/client/tabs/tab_deck_editor.cpp
|
|
||||||
src/client/tabs/tab_deck_storage.cpp
|
|
||||||
src/client/tabs/tab_game.cpp
|
|
||||||
src/client/tabs/tab_logs.cpp
|
|
||||||
src/client/tabs/tab_message.cpp
|
|
||||||
src/client/tabs/tab_replays.cpp
|
|
||||||
src/client/tabs/tab_room.cpp
|
|
||||||
src/client/tabs/tab_server.cpp
|
|
||||||
src/client/tabs/tab_supervisor.cpp
|
|
||||||
src/client/tabs/api/edhrec/tab_edhrec.cpp
|
|
||||||
src/client/tabs/api/edhrec/edhrec_commander_api_response_display_widget.cpp
|
|
||||||
src/client/tabs/api/edhrec/edhrec_commander_api_response_card_details_display_widget.cpp
|
|
||||||
src/client/tabs/api/edhrec/edhrec_commander_api_response_card_list_display_widget.cpp
|
|
||||||
src/client/tabs/api/edhrec/edhrec_commander_api_response_commander_details_display_widget.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_archidekt_links.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_average_deck_statistics.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_card_details.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_card_list.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_card_container.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_card_prices.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response_commander_details.cpp
|
|
||||||
src/client/tabs/api/edhrec/api_response/edhrec_commander_api_response.cpp
|
|
||||||
src/game/zones/table_zone.cpp
|
|
||||||
src/client/tapped_out_interface.cpp
|
|
||||||
src/client/ui/theme_manager.cpp
|
|
||||||
src/client/ui/tip_of_the_day.cpp
|
|
||||||
src/client/translate_counter_name.cpp
|
|
||||||
src/client/update_downloader.cpp
|
|
||||||
src/server/user/user_context_menu.cpp
|
|
||||||
src/server/user/user_info_connection.cpp
|
|
||||||
src/server/user/user_info_box.cpp
|
|
||||||
src/server/user/user_list_manager.cpp
|
|
||||||
src/server/user/user_list_widget.cpp
|
|
||||||
src/client/ui/window_main.cpp
|
|
||||||
src/game/zones/view_zone_widget.cpp
|
|
||||||
src/game/zones/view_zone.cpp
|
|
||||||
src/client/menus/deck_editor/deck_editor_menu.cpp
|
|
||||||
src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
|
||||||
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
|
|
||||||
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
|
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
|
||||||
${VERSION_STRING_CPP}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(sounds)
|
add_subdirectory(sounds)
|
||||||
add_subdirectory(themes)
|
add_subdirectory(themes)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -44,10 +44,9 @@
|
||||||
# cockatrice_xml.* = false
|
# cockatrice_xml.* = false
|
||||||
# cockatrice_xml.xml_3_parser = false
|
# cockatrice_xml.xml_3_parser = false
|
||||||
# cockatrice_xml.xml_4_parser = false
|
# cockatrice_xml.xml_4_parser = false
|
||||||
|
# card_info = false
|
||||||
# card_list = false
|
# card_list = false
|
||||||
|
|
||||||
# stack_zone = false
|
|
||||||
|
|
||||||
flow_layout.debug = false
|
flow_layout.debug = false
|
||||||
flow_widget.debug = false
|
flow_widget.debug = false
|
||||||
flow_widget.size.debug = false
|
flow_widget.size.debug = false
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,9 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
|
||||||
aExportDeckDecklist = new QAction(QString(), this);
|
aExportDeckDecklist = new QAction(QString(), this);
|
||||||
connect(aExportDeckDecklist, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklist()));
|
connect(aExportDeckDecklist, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklist()));
|
||||||
|
|
||||||
|
aExportDeckDecklistXyz = new QAction(QString(), this);
|
||||||
|
connect(aExportDeckDecklistXyz, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklistXyz()));
|
||||||
|
|
||||||
aAnalyzeDeckDeckstats = new QAction(QString(), this);
|
aAnalyzeDeckDeckstats = new QAction(QString(), this);
|
||||||
connect(aAnalyzeDeckDeckstats, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckDeckstats()));
|
connect(aAnalyzeDeckDeckstats, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckDeckstats()));
|
||||||
|
|
||||||
|
|
@ -63,6 +66,8 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
|
||||||
|
|
||||||
analyzeDeckMenu = new QMenu(this);
|
analyzeDeckMenu = new QMenu(this);
|
||||||
analyzeDeckMenu->addAction(aExportDeckDecklist);
|
analyzeDeckMenu->addAction(aExportDeckDecklist);
|
||||||
|
analyzeDeckMenu->addAction(aExportDeckDecklistXyz);
|
||||||
|
analyzeDeckMenu->addSeparator();
|
||||||
analyzeDeckMenu->addAction(aAnalyzeDeckDeckstats);
|
analyzeDeckMenu->addAction(aAnalyzeDeckDeckstats);
|
||||||
analyzeDeckMenu->addAction(aAnalyzeDeckTappedout);
|
analyzeDeckMenu->addAction(aAnalyzeDeckTappedout);
|
||||||
|
|
||||||
|
|
@ -160,6 +165,7 @@ void DeckEditorMenu::retranslateUi()
|
||||||
|
|
||||||
analyzeDeckMenu->setTitle(tr("&Send deck to online service"));
|
analyzeDeckMenu->setTitle(tr("&Send deck to online service"));
|
||||||
aExportDeckDecklist->setText(tr("Create decklist (decklist.org)"));
|
aExportDeckDecklist->setText(tr("Create decklist (decklist.org)"));
|
||||||
|
aExportDeckDecklistXyz->setText(tr("Create decklist (decklist.xyz)"));
|
||||||
aAnalyzeDeckDeckstats->setText(tr("Analyze deck (deckstats.net)"));
|
aAnalyzeDeckDeckstats->setText(tr("Analyze deck (deckstats.net)"));
|
||||||
aAnalyzeDeckTappedout->setText(tr("Analyze deck (tappedout.net)"));
|
aAnalyzeDeckTappedout->setText(tr("Analyze deck (tappedout.net)"));
|
||||||
|
|
||||||
|
|
@ -172,13 +178,17 @@ void DeckEditorMenu::refreshShortcuts()
|
||||||
aNewDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aNewDeck"));
|
aNewDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aNewDeck"));
|
||||||
aLoadDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeck"));
|
aLoadDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeck"));
|
||||||
aSaveDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeck"));
|
aSaveDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeck"));
|
||||||
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
|
|
||||||
aSaveDeckAs->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckAs"));
|
aSaveDeckAs->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckAs"));
|
||||||
aLoadDeckFromClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeckFromClipboard"));
|
aLoadDeckFromClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeckFromClipboard"));
|
||||||
aEditDeckInClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboard"));
|
aEditDeckInClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboard"));
|
||||||
aEditDeckInClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboardRaw"));
|
aEditDeckInClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboardRaw"));
|
||||||
aPrintDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aPrintDeck"));
|
aPrintDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aPrintDeck"));
|
||||||
|
|
||||||
|
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
|
||||||
|
aExportDeckDecklistXyz->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklistXyz"));
|
||||||
aAnalyzeDeckDeckstats->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeck"));
|
aAnalyzeDeckDeckstats->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeck"));
|
||||||
|
aAnalyzeDeckTappedout->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeckTappedout"));
|
||||||
|
|
||||||
aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose"));
|
aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose"));
|
||||||
|
|
||||||
aSaveDeckToClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboard"));
|
aSaveDeckToClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboard"));
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ public:
|
||||||
QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard,
|
QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard,
|
||||||
*aEditDeckInClipboard, *aEditDeckInClipboardRaw, *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetInfo,
|
*aEditDeckInClipboard, *aEditDeckInClipboardRaw, *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetInfo,
|
||||||
*aSaveDeckToClipboardRaw, *aSaveDeckToClipboardRawNoSetInfo, *aPrintDeck, *aExportDeckDecklist,
|
*aSaveDeckToClipboardRaw, *aSaveDeckToClipboardRawNoSetInfo, *aPrintDeck, *aExportDeckDecklist,
|
||||||
*aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
|
*aExportDeckDecklistXyz, *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
|
||||||
QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *editDeckInClipboardMenu, *saveDeckToClipboardMenu;
|
QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *editDeckInClipboardMenu, *saveDeckToClipboardMenu;
|
||||||
|
|
||||||
void setSaveStatus(bool newStatus);
|
void setSaveStatus(bool newStatus);
|
||||||
|
|
|
||||||
|
|
@ -355,8 +355,8 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
|
||||||
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
||||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
dialog.setDefaultSuffix("cod");
|
dialog.setDefaultSuffix("cod");
|
||||||
dialog.setNameFilters(DeckLoader::fileNameFilters);
|
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
||||||
dialog.selectFile(getDeckList()->getName().trimmed() + ".cod");
|
dialog.selectFile(getDeckList()->getName().trimmed());
|
||||||
if (!dialog.exec())
|
if (!dialog.exec())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -455,17 +455,12 @@ void AbstractTabDeckEditor::actPrintDeck()
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action called when export deck to decklist menu item is pressed.
|
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
|
||||||
void AbstractTabDeckEditor::actExportDeckDecklist()
|
|
||||||
{
|
{
|
||||||
// Get the decklist class for the deck.
|
|
||||||
DeckLoader *const deck = getDeckList();
|
|
||||||
// create a string to load the decklist url into.
|
|
||||||
QString decklistUrlString;
|
|
||||||
// check if deck is not null
|
// check if deck is not null
|
||||||
if (deck) {
|
if (DeckLoader *const deck = getDeckList()) {
|
||||||
// Get the decklist url string from the deck loader class.
|
// Get the decklist url string from the deck loader class.
|
||||||
decklistUrlString = deck->exportDeckToDecklist();
|
QString decklistUrlString = deck->exportDeckToDecklist(website);
|
||||||
// Check to make sure the string isn't empty.
|
// Check to make sure the string isn't empty.
|
||||||
if (QString::compare(decklistUrlString, "", Qt::CaseInsensitive) == 0) {
|
if (QString::compare(decklistUrlString, "", Qt::CaseInsensitive) == 0) {
|
||||||
// Show an error if the deck is empty, and return.
|
// Show an error if the deck is empty, and return.
|
||||||
|
|
@ -481,10 +476,26 @@ void AbstractTabDeckEditor::actExportDeckDecklist()
|
||||||
QDesktopServices::openUrl(decklistUrlString);
|
QDesktopServices::openUrl(decklistUrlString);
|
||||||
} else {
|
} else {
|
||||||
// if there's no deck loader object, return an error
|
// if there's no deck loader object, return an error
|
||||||
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be saved."));
|
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be exported."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the deck to www.decklist.org (the old website)
|
||||||
|
*/
|
||||||
|
void AbstractTabDeckEditor::actExportDeckDecklist()
|
||||||
|
{
|
||||||
|
exportToDecklistWebsite(DeckLoader::DecklistOrg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the deck to www.decklist.xyz (the new website)
|
||||||
|
*/
|
||||||
|
void AbstractTabDeckEditor::actExportDeckDecklistXyz()
|
||||||
|
{
|
||||||
|
exportToDecklistWebsite(DeckLoader::DecklistXyz);
|
||||||
|
}
|
||||||
|
|
||||||
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
|
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
|
||||||
{
|
{
|
||||||
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
|
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ protected slots:
|
||||||
void actSaveDeckToClipboardRawNoSetInfo();
|
void actSaveDeckToClipboardRawNoSetInfo();
|
||||||
void actPrintDeck();
|
void actPrintDeck();
|
||||||
void actExportDeckDecklist();
|
void actExportDeckDecklist();
|
||||||
|
void actExportDeckDecklistXyz();
|
||||||
void actAnalyzeDeckDeckstats();
|
void actAnalyzeDeckDeckstats();
|
||||||
void actAnalyzeDeckTappedout();
|
void actAnalyzeDeckTappedout();
|
||||||
|
|
||||||
|
|
@ -119,6 +120,7 @@ protected slots:
|
||||||
private:
|
private:
|
||||||
virtual void setDeck(DeckLoader *_deck);
|
virtual void setDeck(DeckLoader *_deck);
|
||||||
void editDeckInClipboard(bool annotated);
|
void editDeckInClipboard(bool annotated);
|
||||||
|
void exportToDecklistWebsite(DeckLoader::DecklistWebsite website);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,7 +149,7 @@ protected:
|
||||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
||||||
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
||||||
|
|
||||||
bool modified;
|
bool modified = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TAB_GENERIC_DECK_EDITOR_H
|
#endif // TAB_GENERIC_DECK_EDITOR_H
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,6 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
||||||
refreshShortcuts();
|
refreshShortcuts();
|
||||||
messageLog->logReplayStarted(gameInfo.game_id());
|
messageLog->logReplayStarted(gameInfo.game_id());
|
||||||
|
|
||||||
this->installEventFilter(this);
|
|
||||||
QTimer::singleShot(0, this, SLOT(loadLayout()));
|
QTimer::singleShot(0, this, SLOT(loadLayout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +163,6 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
||||||
for (int i = gameInfo.game_types_size() - 1; i >= 0; i--)
|
for (int i = gameInfo.game_types_size() - 1; i >= 0; i--)
|
||||||
gameTypes.append(roomGameTypes.find(gameInfo.game_types(i)).value());
|
gameTypes.append(roomGameTypes.find(gameInfo.game_types(i)).value());
|
||||||
|
|
||||||
this->installEventFilter(this);
|
|
||||||
QTimer::singleShot(0, this, SLOT(loadLayout()));
|
QTimer::singleShot(0, this, SLOT(loadLayout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1753,6 +1751,27 @@ void TabGame::createMessageDock(bool bReplay)
|
||||||
connect(messageLayoutDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
|
connect(messageLayoutDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabGame::hideEvent(QHideEvent *event)
|
||||||
|
{
|
||||||
|
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
||||||
|
if (replay) {
|
||||||
|
layouts.setReplayPlayAreaState(saveState());
|
||||||
|
layouts.setReplayPlayAreaGeometry(saveGeometry());
|
||||||
|
layouts.setReplayCardInfoSize(cardInfoDock->size());
|
||||||
|
layouts.setReplayMessageLayoutSize(messageLayoutDock->size());
|
||||||
|
layouts.setReplayPlayerListSize(playerListDock->size());
|
||||||
|
layouts.setReplayReplaySize(replayDock->size());
|
||||||
|
} else {
|
||||||
|
layouts.setGamePlayAreaState(saveState());
|
||||||
|
layouts.setGamePlayAreaGeometry(saveGeometry());
|
||||||
|
layouts.setGameCardInfoSize(cardInfoDock->size());
|
||||||
|
layouts.setGameMessageLayoutSize(messageLayoutDock->size());
|
||||||
|
layouts.setGamePlayerListSize(playerListDock->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab::hideEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
// Method uses to sync docks state with menu items state
|
// Method uses to sync docks state with menu items state
|
||||||
bool TabGame::eventFilter(QObject *o, QEvent *e)
|
bool TabGame::eventFilter(QObject *o, QEvent *e)
|
||||||
{
|
{
|
||||||
|
|
@ -1772,23 +1791,6 @@ bool TabGame::eventFilter(QObject *o, QEvent *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o == this && e->type() == QEvent::Hide) {
|
|
||||||
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
|
||||||
if (replay) {
|
|
||||||
layouts.setReplayPlayAreaState(saveState());
|
|
||||||
layouts.setReplayPlayAreaGeometry(saveGeometry());
|
|
||||||
layouts.setReplayCardInfoSize(cardInfoDock->size());
|
|
||||||
layouts.setReplayMessageLayoutSize(messageLayoutDock->size());
|
|
||||||
layouts.setReplayPlayerListSize(playerListDock->size());
|
|
||||||
layouts.setReplayReplaySize(replayDock->size());
|
|
||||||
} else {
|
|
||||||
layouts.setGamePlayAreaState(saveState());
|
|
||||||
layouts.setGamePlayAreaGeometry(saveGeometry());
|
|
||||||
layouts.setGameCardInfoSize(cardInfoDock->size());
|
|
||||||
layouts.setGameMessageLayoutSize(messageLayoutDock->size());
|
|
||||||
layouts.setGamePlayerListSize(playerListDock->size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ private slots:
|
||||||
void actResetLayout();
|
void actResetLayout();
|
||||||
void freeDocksSize();
|
void freeDocksSize();
|
||||||
|
|
||||||
|
void hideEvent(QHideEvent *event) override;
|
||||||
bool eventFilter(QObject *o, QEvent *e) override;
|
bool eventFilter(QObject *o, QEvent *e) override;
|
||||||
void dockVisibleTriggered();
|
void dockVisibleTriggered();
|
||||||
void dockFloatingTriggered();
|
void dockFloatingTriggered();
|
||||||
|
|
|
||||||
|
|
@ -232,22 +232,45 @@ void TabSupervisor::refreshShortcuts()
|
||||||
aTabLog->setShortcuts(shortcuts.getShortcut("Tabs/aTabLog"));
|
aTabLog->setShortcuts(shortcuts.getShortcut("Tabs/aTabLog"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TabSupervisor::closeRequest()
|
void TabSupervisor::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
|
// This will accept the event, which we may then override.
|
||||||
|
QTabWidget::closeEvent(event);
|
||||||
|
|
||||||
if (getGameCount()) {
|
if (getGameCount()) {
|
||||||
if (QMessageBox::question(this, tr("Are you sure?"),
|
if (QMessageBox::question(this, tr("Are you sure?"),
|
||||||
tr("There are still open games. Are you sure you want to quit?"),
|
tr("There are still open games. Are you sure you want to quit?"),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
|
||||||
return false;
|
event->ignore();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AbstractTabDeckEditor *tab : deckEditorTabs) {
|
for (AbstractTabDeckEditor *tab : deckEditorTabs) {
|
||||||
if (!tab->confirmClose())
|
if (!tab->confirmClose()) {
|
||||||
return false;
|
event->ignore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// Close the game tabs in order to make sure they store their layout.
|
||||||
|
QSet<int> gameTabsToRemove;
|
||||||
|
for (auto it = gameTabs.begin(), end = gameTabs.end(); it != end; ++it) {
|
||||||
|
if (it.value()->close()) {
|
||||||
|
// Hotfix: the tab owns the `QMenu`s so they need to be cleared,
|
||||||
|
// otherwise we end up with use-after-free bugs.
|
||||||
|
if (it.value() == currentWidget()) {
|
||||||
|
emit setMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
gameTabsToRemove.insert(it.key());
|
||||||
|
} else {
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto tabId : gameTabsToRemove) {
|
||||||
|
gameTabs.remove(tabId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractClient *TabSupervisor::getClient() const
|
AbstractClient *TabSupervisor::getClient() const
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ public:
|
||||||
return deckEditorTabs;
|
return deckEditorTabs;
|
||||||
}
|
}
|
||||||
bool getAdminLocked() const;
|
bool getAdminLocked() const;
|
||||||
bool closeRequest();
|
void closeEvent(QCloseEvent *event) override;
|
||||||
bool switchToGameTabIfAlreadyExists(const int gameId);
|
bool switchToGameTabIfAlreadyExists(const int gameId);
|
||||||
static void actShowPopup(const QString &message);
|
static void actShowPopup(const QString &message);
|
||||||
signals:
|
signals:
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,12 @@ QMap<QString, QPixmap> CountryPixmapGenerator::pmCache;
|
||||||
* @param idName id that the tag has to match
|
* @param idName id that the tag has to match
|
||||||
* @param attrValue the value to update the attribute to
|
* @param attrValue the value to update the attribute to
|
||||||
*/
|
*/
|
||||||
|
static void setAttrRecur(QDomElement &elem,
|
||||||
|
const QString &tagName,
|
||||||
|
const QString &attrName,
|
||||||
|
const QString &idName,
|
||||||
|
const QString &attrValue);
|
||||||
|
|
||||||
void setAttrRecur(QDomElement &elem,
|
void setAttrRecur(QDomElement &elem,
|
||||||
const QString &tagName,
|
const QString &tagName,
|
||||||
const QString &attrName,
|
const QString &attrName,
|
||||||
|
|
|
||||||
|
|
@ -120,10 +120,10 @@ void ThemeManager::themeChangedSlot()
|
||||||
if (dirPath.isEmpty()) {
|
if (dirPath.isEmpty()) {
|
||||||
// set default values
|
// set default values
|
||||||
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
|
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
|
||||||
handBgBrush = HANDZONE_BG_DEFAULT;
|
brushes[Role::Hand] = HANDZONE_BG_DEFAULT;
|
||||||
tableBgBrush = TABLEZONE_BG_DEFAULT;
|
brushes[Role::Table] = TABLEZONE_BG_DEFAULT;
|
||||||
playerBgBrush = PLAYERZONE_BG_DEFAULT;
|
brushes[Role::Player] = PLAYERZONE_BG_DEFAULT;
|
||||||
stackBgBrush = STACKZONE_BG_DEFAULT;
|
brushes[Role::Stack] = STACKZONE_BG_DEFAULT;
|
||||||
} else {
|
} else {
|
||||||
// resources
|
// resources
|
||||||
QStringList resources;
|
QStringList resources;
|
||||||
|
|
@ -132,73 +132,58 @@ void ThemeManager::themeChangedSlot()
|
||||||
|
|
||||||
// zones bg
|
// zones bg
|
||||||
dir.cd("zones");
|
dir.cd("zones");
|
||||||
handBgBrush = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
|
brushes[Role::Hand] = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
|
||||||
tableBgBrush = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
|
brushes[Role::Table] = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
|
||||||
playerBgBrush = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_BG_DEFAULT);
|
brushes[Role::Player] = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_BG_DEFAULT);
|
||||||
stackBgBrush = loadBrush(STACKZONE_BG_NAME, STACKZONE_BG_DEFAULT);
|
brushes[Role::Stack] = loadBrush(STACKZONE_BG_NAME, STACKZONE_BG_DEFAULT);
|
||||||
|
}
|
||||||
|
for (auto &brushCache : brushesCache) {
|
||||||
|
brushCache.clear();
|
||||||
}
|
}
|
||||||
tableBgBrushesCache.clear();
|
|
||||||
stackBgBrushesCache.clear();
|
|
||||||
playerBgBrushesCache.clear();
|
|
||||||
handBgBrushesCache.clear();
|
|
||||||
|
|
||||||
QPixmapCache::clear();
|
QPixmapCache::clear();
|
||||||
|
|
||||||
emit themeChanged();
|
emit themeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QBrush ThemeManager::getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
static QString roleBgName(ThemeManager::Role role)
|
||||||
{
|
{
|
||||||
QBrush returnBrush;
|
switch (role) {
|
||||||
|
case ThemeManager::Hand:
|
||||||
|
return HANDZONE_BG_NAME;
|
||||||
|
|
||||||
if (!tableBgBrushesCache.contains(extraNumber.toInt())) {
|
case ThemeManager::Player:
|
||||||
returnBrush = loadExtraBrush(TABLEZONE_BG_NAME + extraNumber, fallbackBrush);
|
return PLAYERZONE_BG_NAME;
|
||||||
tableBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
|
||||||
} else {
|
case ThemeManager::Stack:
|
||||||
returnBrush = tableBgBrushesCache.value(extraNumber.toInt());
|
return STACKZONE_BG_NAME;
|
||||||
|
|
||||||
|
case ThemeManager::Table:
|
||||||
|
return TABLEZONE_BG_NAME;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnBrush;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QBrush ThemeManager::getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
QBrush &ThemeManager::getBgBrush(Role role)
|
||||||
{
|
{
|
||||||
QBrush returnBrush;
|
return brushes[role];
|
||||||
|
|
||||||
if (!stackBgBrushesCache.contains(extraNumber.toInt())) {
|
|
||||||
returnBrush = loadExtraBrush(STACKZONE_BG_NAME + extraNumber, fallbackBrush);
|
|
||||||
stackBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
|
||||||
} else {
|
|
||||||
returnBrush = stackBgBrushesCache.value(extraNumber.toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnBrush;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QBrush ThemeManager::getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
QBrush ThemeManager::getExtraBgBrush(Role role, int zoneId)
|
||||||
{
|
{
|
||||||
QBrush returnBrush;
|
if (zoneId <= 0) {
|
||||||
|
return getBgBrush(role);
|
||||||
if (!playerBgBrushesCache.contains(extraNumber.toInt())) {
|
|
||||||
returnBrush = loadExtraBrush(PLAYERZONE_BG_NAME + extraNumber, fallbackBrush);
|
|
||||||
playerBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
|
||||||
} else {
|
|
||||||
returnBrush = playerBgBrushesCache.value(extraNumber.toInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnBrush;
|
QBrushMap &brushCache = brushesCache[role];
|
||||||
}
|
|
||||||
|
|
||||||
QBrush ThemeManager::getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
if (!brushCache.contains(zoneId)) {
|
||||||
{
|
QBrush brush = loadExtraBrush(roleBgName(role) + QString::number(zoneId), getBgBrush(role));
|
||||||
QBrush returnBrush;
|
brushCache.insert(zoneId, brush);
|
||||||
|
return brush;
|
||||||
if (!handBgBrushesCache.contains(extraNumber.toInt())) {
|
|
||||||
returnBrush = loadExtraBrush(HANDZONE_BG_NAME + extraNumber, fallbackBrush);
|
|
||||||
handBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
|
||||||
} else {
|
|
||||||
returnBrush = handBgBrushesCache.value(extraNumber.toInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnBrush;
|
return brushCache.value(zoneId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(ThemeManagerLog, "theme_manager");
|
inline Q_LOGGING_CATEGORY(ThemeManagerLog, "theme_manager");
|
||||||
|
|
||||||
|
|
@ -22,13 +23,23 @@ class ThemeManager : public QObject
|
||||||
public:
|
public:
|
||||||
ThemeManager(QObject *parent = nullptr);
|
ThemeManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
enum Role
|
||||||
|
{
|
||||||
|
MinRole = 0,
|
||||||
|
Hand = MinRole,
|
||||||
|
Stack,
|
||||||
|
Table,
|
||||||
|
Player,
|
||||||
|
MaxRole = Player,
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QBrush handBgBrush, stackBgBrush, tableBgBrush, playerBgBrush;
|
std::array<QBrush, Role::MaxRole + 1> brushes;
|
||||||
QStringMap availableThemes;
|
QStringMap availableThemes;
|
||||||
/*
|
/*
|
||||||
Internal cache for multiple backgrounds
|
Internal cache for multiple backgrounds
|
||||||
*/
|
*/
|
||||||
QBrushMap tableBgBrushesCache, stackBgBrushesCache, playerBgBrushesCache, handBgBrushesCache;
|
std::array<QBrushMap, Role::MaxRole + 1> brushesCache;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ensureThemeDirectoryExists();
|
void ensureThemeDirectoryExists();
|
||||||
|
|
@ -36,27 +47,10 @@ protected:
|
||||||
QBrush loadExtraBrush(QString fileName, QBrush &fallbackBrush);
|
QBrush loadExtraBrush(QString fileName, QBrush &fallbackBrush);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QBrush &getHandBgBrush()
|
|
||||||
{
|
|
||||||
return handBgBrush;
|
|
||||||
}
|
|
||||||
QBrush &getStackBgBrush()
|
|
||||||
{
|
|
||||||
return stackBgBrush;
|
|
||||||
}
|
|
||||||
QBrush &getTableBgBrush()
|
|
||||||
{
|
|
||||||
return tableBgBrush;
|
|
||||||
}
|
|
||||||
QBrush &getPlayerBgBrush()
|
|
||||||
{
|
|
||||||
return playerBgBrush;
|
|
||||||
}
|
|
||||||
QStringMap &getAvailableThemes();
|
QStringMap &getAvailableThemes();
|
||||||
QBrush getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
|
||||||
QBrush getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
QBrush &getBgBrush(Role zone);
|
||||||
QBrush getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
||||||
QBrush getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void themeChangedSlot();
|
void themeChangedSlot();
|
||||||
signals:
|
signals:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "color_identity_widget.h"
|
#include "color_identity_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../settings/cache_settings.h"
|
||||||
#include "mana_symbol_widget.h"
|
#include "mana_symbol_widget.h"
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
|
@ -17,18 +18,21 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, CardInfoPtr _card) : Q
|
||||||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
|
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||||
|
QString fullColorIdentity = "WUBRG";
|
||||||
|
|
||||||
if (card) {
|
if (card) {
|
||||||
QString manaCost = card->getColors(); // Get mana cost string
|
manaCost = card->getColors(); // Get mana cost string
|
||||||
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
||||||
|
|
||||||
for (const QString &symbol : symbols) {
|
populateManaSymbolWidgets();
|
||||||
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol, true);
|
|
||||||
layout->addWidget(manaSymbol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
||||||
|
&ColorIdentityWidget::toggleUnusedVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString manaCost) : QWidget(parent), card(nullptr)
|
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString _manaCost)
|
||||||
|
: QWidget(parent), card(nullptr), manaCost(_manaCost)
|
||||||
{
|
{
|
||||||
layout = new QHBoxLayout(this);
|
layout = new QHBoxLayout(this);
|
||||||
layout->setSpacing(5); // Small spacing between icons
|
layout->setSpacing(5); // Small spacing between icons
|
||||||
|
|
@ -36,12 +40,41 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString manaCost) : QW
|
||||||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
|
populateManaSymbolWidgets();
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
||||||
|
&ColorIdentityWidget::toggleUnusedVisibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorIdentityWidget::populateManaSymbolWidgets()
|
||||||
|
{
|
||||||
|
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||||
|
QString fullColorIdentity = "WUBRG";
|
||||||
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
||||||
|
|
||||||
for (const QString &symbol : symbols) {
|
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()) {
|
||||||
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol);
|
for (const QString symbol : fullColorIdentity) {
|
||||||
|
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||||
layout->addWidget(manaSymbol);
|
layout->addWidget(manaSymbol);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for (const QString &symbol : symbols) {
|
||||||
|
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||||
|
layout->addWidget(manaSymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorIdentityWidget::toggleUnusedVisibility()
|
||||||
|
{
|
||||||
|
if (layout != nullptr) {
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = layout->takeAt(0)) != nullptr) {
|
||||||
|
item->widget()->deleteLater(); // Delete the widget
|
||||||
|
delete item; // Delete the layout item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
populateManaSymbolWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorIdentityWidget::resizeEvent(QResizeEvent *event)
|
void ColorIdentityWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,17 @@ class ColorIdentityWidget : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit ColorIdentityWidget(QWidget *parent, CardInfoPtr card);
|
explicit ColorIdentityWidget(QWidget *parent, CardInfoPtr card);
|
||||||
explicit ColorIdentityWidget(QWidget *parent, QString manaCost);
|
explicit ColorIdentityWidget(QWidget *parent, QString manaCost);
|
||||||
|
void populateManaSymbolWidgets();
|
||||||
|
|
||||||
QStringList parseColorIdentity(const QString &manaString);
|
QStringList parseColorIdentity(const QString &manaString);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
void toggleUnusedVisibility();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CardInfoPtr card;
|
CardInfoPtr card;
|
||||||
|
QString manaCost;
|
||||||
QHBoxLayout *layout;
|
QHBoxLayout *layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "mana_symbol_widget.h"
|
#include "mana_symbol_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
|
|
||||||
ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isActive, bool _mayBeToggled)
|
ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isActive, bool _mayBeToggled)
|
||||||
|
|
@ -13,6 +15,9 @@ ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isAct
|
||||||
opacityEffect = new QGraphicsOpacityEffect(this);
|
opacityEffect = new QGraphicsOpacityEffect(this);
|
||||||
setGraphicsEffect(opacityEffect);
|
setGraphicsEffect(opacityEffect);
|
||||||
updateOpacity();
|
updateOpacity();
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageUnusedColorIdentitiesOpacityChanged, this,
|
||||||
|
&ManaSymbolWidget::updateOpacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManaSymbolWidget::setColorActive(bool active)
|
void ManaSymbolWidget::setColorActive(bool active)
|
||||||
|
|
@ -26,7 +31,14 @@ void ManaSymbolWidget::setColorActive(bool active)
|
||||||
|
|
||||||
void ManaSymbolWidget::updateOpacity()
|
void ManaSymbolWidget::updateOpacity()
|
||||||
{
|
{
|
||||||
qreal opacity = isActive ? 1.0 : 0.5;
|
qreal opacity;
|
||||||
|
if (mayBeToggled) {
|
||||||
|
// UI elements that users can click on shouldn't be transparent.
|
||||||
|
opacity = isActive ? 1.0 : 0.5;
|
||||||
|
} else {
|
||||||
|
// It's just for display, they can do whatever they want.
|
||||||
|
opacity = isActive ? 1.0 : SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity() / 100.0;
|
||||||
|
}
|
||||||
opacityEffect->setOpacity(opacity);
|
opacityEffect->setOpacity(opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "card_info_picture_enlarged_widget.h"
|
#include "card_info_picture_enlarged_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../settings/cache_settings.h"
|
||||||
#include "../../picture_loader/picture_loader.h"
|
#include "../../picture_loader/picture_loader.h"
|
||||||
|
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
|
|
@ -17,6 +18,12 @@ CardInfoPictureEnlargedWidget::CardInfoPictureEnlargedWidget(QWidget *parent)
|
||||||
{
|
{
|
||||||
setWindowFlags(Qt::ToolTip); // Keeps this widget on top of everything
|
setWindowFlags(Qt::ToolTip); // Keeps this widget on top of everything
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
||||||
|
update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -79,7 +86,8 @@ void CardInfoPictureEnlargedWidget::paintEvent(QPaintEvent *event)
|
||||||
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
|
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
|
||||||
|
|
||||||
// Define the radius for rounded corners
|
// Define the radius for rounded corners
|
||||||
qreal radius = 0.05 * scaledSize.width(); // Adjust the radius as needed for rounded corners
|
// Adjust the radius as needed for rounded corners
|
||||||
|
qreal radius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * scaledSize.width() : 0.;
|
||||||
|
|
||||||
QStylePainter painter(this);
|
QStylePainter painter(this);
|
||||||
// Fill the background with transparent color to ensure rounded corners are rendered properly
|
// Fill the background with transparent color to ensure rounded corners are rendered properly
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#include "../../../../game/cards/card_database_manager.h"
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
#include "../../../../game/cards/card_item.h"
|
#include "../../../../game/cards/card_item.h"
|
||||||
#include "../../../../settings/cache_settings.h"
|
#include "../../../../settings/cache_settings.h"
|
||||||
#include "../../../tabs/tab_deck_editor.h"
|
|
||||||
#include "../../../tabs/tab_supervisor.h"
|
#include "../../../tabs/tab_supervisor.h"
|
||||||
#include "../../picture_loader/picture_loader.h"
|
#include "../../picture_loader/picture_loader.h"
|
||||||
#include "../../window_main.h"
|
#include "../../window_main.h"
|
||||||
|
|
@ -44,6 +43,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool hoverTo
|
||||||
hoverTimer = new QTimer(this);
|
hoverTimer = new QTimer(this);
|
||||||
hoverTimer->setSingleShot(true);
|
hoverTimer->setSingleShot(true);
|
||||||
connect(hoverTimer, &QTimer::timeout, this, &CardInfoPictureWidget::showEnlargedPixmap);
|
connect(hoverTimer, &QTimer::timeout, this, &CardInfoPictureWidget::showEnlargedPixmap);
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
||||||
|
update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -186,7 +191,8 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
|
||||||
QRect targetRect{targetX, targetY, targetW, targetH};
|
QRect targetRect{targetX, targetY, targetW, targetH};
|
||||||
|
|
||||||
// Compute rounded corner radius
|
// Compute rounded corner radius
|
||||||
qreal radius = 0.05 * static_cast<qreal>(targetRect.width()); // Ensure consistent rounding
|
// Ensure consistent rounding
|
||||||
|
qreal radius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * static_cast<qreal>(targetRect.width()) : 0.;
|
||||||
|
|
||||||
// Draw the pixmap with rounded corners
|
// Draw the pixmap with rounded corners
|
||||||
QStylePainter painter(this);
|
QStylePainter painter(this);
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,8 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
|
|
||||||
auto *upperLayout = new QGridLayout;
|
auto *upperLayout = new QGridLayout;
|
||||||
upperLayout->setObjectName("upperLayout");
|
upperLayout->setObjectName("upperLayout");
|
||||||
|
upperLayout->setContentsMargins(11, 11, 11, 0);
|
||||||
|
|
||||||
upperLayout->addWidget(nameLabel, 0, 0);
|
upperLayout->addWidget(nameLabel, 0, 0);
|
||||||
upperLayout->addWidget(nameEdit, 0, 1);
|
upperLayout->addWidget(nameEdit, 0, 1);
|
||||||
|
|
||||||
|
|
@ -314,12 +316,17 @@ DeckLoader *DeckEditorDeckDockWidget::getDeckList()
|
||||||
return deckModel->getDeckList();
|
return deckModel->getDeckList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the tab to the state for a blank new tab.
|
||||||
|
*/
|
||||||
void DeckEditorDeckDockWidget::cleanDeck()
|
void DeckEditorDeckDockWidget::cleanDeck()
|
||||||
{
|
{
|
||||||
deckModel->cleanList();
|
deckModel->cleanList();
|
||||||
nameEdit->setText(QString());
|
nameEdit->setText(QString());
|
||||||
commentsEdit->setText(QString());
|
commentsEdit->setText(QString());
|
||||||
hashLabel->setText(QString());
|
hashLabel->setText(QString());
|
||||||
|
updateBannerCardComboBox();
|
||||||
|
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)
|
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,11 @@ void DeckEditorFilterDockWidget::filterViewCustomContextMenu(const QPoint &point
|
||||||
|
|
||||||
action = menu.addAction(QString("delete"));
|
action = menu.addAction(QString("delete"));
|
||||||
action->setData(point);
|
action->setData(point);
|
||||||
connect(&menu, SIGNAL(triggered(QAction *)), this, SLOT(filterRemove(QAction *)));
|
connect(&menu, &QMenu::triggered, this, &DeckEditorFilterDockWidget::filterRemove);
|
||||||
menu.exec(filterView->mapToGlobal(point));
|
menu.exec(filterView->mapToGlobal(point));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorFilterDockWidget::filterRemove(QAction *action)
|
void DeckEditorFilterDockWidget::filterRemove(const QAction *action)
|
||||||
{
|
{
|
||||||
QPoint point;
|
QPoint point;
|
||||||
QModelIndex idx;
|
QModelIndex idx;
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,9 @@ private:
|
||||||
KeySignals filterViewKeySignals;
|
KeySignals filterViewKeySignals;
|
||||||
QWidget *filterBox;
|
QWidget *filterBox;
|
||||||
|
|
||||||
void filterRemove(QAction *action);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void filterViewCustomContextMenu(const QPoint &point);
|
void filterViewCustomContextMenu(const QPoint &point);
|
||||||
|
void filterRemove(const QAction *action);
|
||||||
void actClearFilterAll();
|
void actClearFilterAll();
|
||||||
void actClearFilterOne();
|
void actClearFilterOne();
|
||||||
void refreshShortcuts();
|
void refreshShortcuts();
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,21 @@
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
|
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
|
||||||
: QWidget(_parent), deckList(_deckList)
|
: QWidget(_parent), deckList(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
// Create layout
|
// Create layout
|
||||||
auto *layout = new QHBoxLayout(this);
|
auto *layout = new QHBoxLayout(this);
|
||||||
layout->setContentsMargins(5, 5, 5, 5);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->setSpacing(5);
|
|
||||||
|
|
||||||
setFixedHeight(100);
|
setFixedHeight(100);
|
||||||
|
|
||||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
if (deckList) {
|
if (_deckList) {
|
||||||
connectDeckList(deckList);
|
connectDeckList(_deckList);
|
||||||
}
|
}
|
||||||
|
|
||||||
layout->addWidget(flowWidget);
|
layout->addWidget(flowWidget);
|
||||||
|
|
@ -37,10 +36,20 @@ DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_par
|
||||||
|
|
||||||
void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
|
void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
|
||||||
{
|
{
|
||||||
flowWidget->clearLayout();
|
if (deckList) {
|
||||||
|
disconnect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
||||||
|
}
|
||||||
|
|
||||||
deckList = _deckList;
|
deckList = _deckList;
|
||||||
connect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
connect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
||||||
|
|
||||||
|
refreshTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewDeckTagsDisplayWidget::refreshTags()
|
||||||
|
{
|
||||||
|
flowWidget->clearLayout();
|
||||||
|
|
||||||
for (const QString &tag : deckList->getTags()) {
|
for (const QString &tag : deckList->getTags()) {
|
||||||
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
|
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
|
||||||
}
|
}
|
||||||
|
|
@ -51,16 +60,6 @@ void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
|
||||||
flowWidget->addWidget(tagAdditionWidget);
|
flowWidget->addWidget(tagAdditionWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckPreviewDeckTagsDisplayWidget::refreshTags()
|
|
||||||
{
|
|
||||||
flowWidget->clearLayout();
|
|
||||||
QStringList tags = deckList->getTags();
|
|
||||||
for (const QString &tag : tags) {
|
|
||||||
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
|
|
||||||
}
|
|
||||||
flowWidget->addWidget(new DeckPreviewTagAdditionWidget(this, tr("Edit tags ...")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the filepath of all files (no directories) in target directory and all subdirectories
|
* Gets the filepath of all files (no directories) in target directory and all subdirectories
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -298,11 +298,11 @@ QMenu *DeckPreviewWidget::createRightClickMenu()
|
||||||
|
|
||||||
connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this,
|
connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this,
|
||||||
[this] { deckLoader->saveToClipboard(true, true); });
|
[this] { deckLoader->saveToClipboard(true, true); });
|
||||||
connect(saveToClipboardMenu->addAction(tr("Annotated (No set name or number)")), &QAction::triggered, this,
|
connect(saveToClipboardMenu->addAction(tr("Annotated (No set info)")), &QAction::triggered, this,
|
||||||
[this] { deckLoader->saveToClipboard(true, false); });
|
[this] { deckLoader->saveToClipboard(true, false); });
|
||||||
connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this,
|
connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this,
|
||||||
[this] { deckLoader->saveToClipboard(false, true); });
|
[this] { deckLoader->saveToClipboard(false, true); });
|
||||||
connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set name or number)")), &QAction::triggered, this,
|
connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set info)")), &QAction::triggered, this,
|
||||||
[this] { deckLoader->saveToClipboard(false, false); });
|
[this] { deckLoader->saveToClipboard(false, false); });
|
||||||
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,12 @@ void VisualDeckStorageFolderDisplayWidget::refreshUi()
|
||||||
header->setText(bannerText);
|
header->setText(bannerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all files in the directory that have an accepted decklist file extension
|
||||||
|
*
|
||||||
|
* @param filePath The directory to search through
|
||||||
|
* @param recursive Whether to search through subdirectories
|
||||||
|
*/
|
||||||
static QStringList getAllFiles(const QString &filePath, bool recursive)
|
static QStringList getAllFiles(const QString &filePath, bool recursive)
|
||||||
{
|
{
|
||||||
QStringList allFiles;
|
QStringList allFiles;
|
||||||
|
|
@ -65,7 +71,7 @@ static QStringList getAllFiles(const QString &filePath, bool recursive)
|
||||||
// QDirIterator with QDir::Files ensures only files are listed (no directories)
|
// QDirIterator with QDir::Files ensures only files are listed (no directories)
|
||||||
auto flags =
|
auto flags =
|
||||||
recursive ? QDirIterator::Subdirectories | QDirIterator::FollowSymlinks : QDirIterator::NoIteratorFlags;
|
recursive ? QDirIterator::Subdirectories | QDirIterator::FollowSymlinks : QDirIterator::NoIteratorFlags;
|
||||||
QDirIterator it(filePath, QDir::Files, flags);
|
QDirIterator it(filePath, DeckLoader::ACCEPTED_FILE_EXTENSIONS, QDir::Files, flags);
|
||||||
|
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
allFiles << it.next(); // Add each file path to the list
|
allFiles << it.next(); // Add each file path to the list
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QSpinBox>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), folderWidget(nullptr)
|
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), folderWidget(nullptr)
|
||||||
|
|
@ -40,6 +41,7 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
||||||
refreshButton->setFixedSize(32, 32);
|
refreshButton->setFixedSize(32, 32);
|
||||||
connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible);
|
connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible);
|
||||||
|
|
||||||
|
// quick settings menu
|
||||||
showFoldersCheckBox = new QCheckBox(this);
|
showFoldersCheckBox = new QCheckBox(this);
|
||||||
showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
|
showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
|
||||||
connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &VisualDeckStorageWidget::updateShowFolders);
|
connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &VisualDeckStorageWidget::updateShowFolders);
|
||||||
|
|
@ -77,6 +79,29 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
||||||
connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
|
connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
|
||||||
&SettingsCache::setVisualDeckStorageSearchFolderNames);
|
&SettingsCache::setVisualDeckStorageSearchFolderNames);
|
||||||
|
|
||||||
|
// color identity opacity selector
|
||||||
|
auto unusedColorIdentityOpacityWidget = new QWidget(this);
|
||||||
|
|
||||||
|
unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget);
|
||||||
|
unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget);
|
||||||
|
|
||||||
|
unusedColorIdentitiesOpacitySpinBox->setMinimum(0);
|
||||||
|
unusedColorIdentitiesOpacitySpinBox->setMaximum(100);
|
||||||
|
unusedColorIdentitiesOpacitySpinBox->setValue(
|
||||||
|
SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
|
||||||
|
connect(unusedColorIdentitiesOpacitySpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||||
|
&SettingsCache::instance(), &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
|
|
||||||
|
unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox);
|
||||||
|
|
||||||
|
unusedColorIdentitiesOpacitySpinBox->setValue(
|
||||||
|
SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
|
||||||
|
|
||||||
|
auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget);
|
||||||
|
unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0);
|
||||||
|
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
|
||||||
|
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
|
||||||
|
|
||||||
// card size slider
|
// card size slider
|
||||||
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
|
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
|
||||||
|
|
||||||
|
|
@ -84,9 +109,10 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
||||||
quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
|
quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
|
||||||
quickSettingsWidget->addSettingsWidget(tagFilterVisibilityCheckBox);
|
quickSettingsWidget->addSettingsWidget(tagFilterVisibilityCheckBox);
|
||||||
quickSettingsWidget->addSettingsWidget(tagsOnWidgetsVisibilityCheckBox);
|
quickSettingsWidget->addSettingsWidget(tagsOnWidgetsVisibilityCheckBox);
|
||||||
quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
|
|
||||||
quickSettingsWidget->addSettingsWidget(bannerCardComboBoxVisibilityCheckBox);
|
quickSettingsWidget->addSettingsWidget(bannerCardComboBoxVisibilityCheckBox);
|
||||||
quickSettingsWidget->addSettingsWidget(searchFolderNamesCheckBox);
|
quickSettingsWidget->addSettingsWidget(searchFolderNamesCheckBox);
|
||||||
|
quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
|
||||||
|
quickSettingsWidget->addSettingsWidget(unusedColorIdentityOpacityWidget);
|
||||||
quickSettingsWidget->addSettingsWidget(cardSizeWidget);
|
quickSettingsWidget->addSettingsWidget(cardSizeWidget);
|
||||||
|
|
||||||
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
|
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
|
||||||
|
|
@ -159,9 +185,11 @@ void VisualDeckStorageWidget::retranslateUi()
|
||||||
showFoldersCheckBox->setText(tr("Show Folders"));
|
showFoldersCheckBox->setText(tr("Show Folders"));
|
||||||
tagFilterVisibilityCheckBox->setText(tr("Show Tag Filter"));
|
tagFilterVisibilityCheckBox->setText(tr("Show Tag Filter"));
|
||||||
tagsOnWidgetsVisibilityCheckBox->setText(tr("Show Tags On Deck Previews"));
|
tagsOnWidgetsVisibilityCheckBox->setText(tr("Show Tags On Deck Previews"));
|
||||||
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw not contained Color Identities"));
|
|
||||||
bannerCardComboBoxVisibilityCheckBox->setText(tr("Show Banner Card Selection Option"));
|
bannerCardComboBoxVisibilityCheckBox->setText(tr("Show Banner Card Selection Option"));
|
||||||
searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
|
searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
|
||||||
|
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
|
||||||
|
unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
|
||||||
|
unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
|
|
||||||
|
class QSpinBox;
|
||||||
class VisualDeckStorageSearchWidget;
|
class VisualDeckStorageSearchWidget;
|
||||||
class VisualDeckStorageSortWidget;
|
class VisualDeckStorageSortWidget;
|
||||||
class VisualDeckStorageTagFilterWidget;
|
class VisualDeckStorageTagFilterWidget;
|
||||||
|
|
@ -64,6 +65,8 @@ private:
|
||||||
QCheckBox *tagFilterVisibilityCheckBox;
|
QCheckBox *tagFilterVisibilityCheckBox;
|
||||||
QCheckBox *tagsOnWidgetsVisibilityCheckBox;
|
QCheckBox *tagsOnWidgetsVisibilityCheckBox;
|
||||||
QCheckBox *searchFolderNamesCheckBox;
|
QCheckBox *searchFolderNamesCheckBox;
|
||||||
|
QLabel *unusedColorIdentitiesOpacityLabel;
|
||||||
|
QSpinBox *unusedColorIdentitiesOpacitySpinBox;
|
||||||
QScrollArea *scrollArea;
|
QScrollArea *scrollArea;
|
||||||
VisualDeckStorageFolderDisplayWidget *folderWidget;
|
VisualDeckStorageFolderDisplayWidget *folderWidget;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1018,7 +1018,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||||
return;
|
return;
|
||||||
bClosingDown = true;
|
bClosingDown = true;
|
||||||
|
|
||||||
if (!tabSupervisor->closeRequest()) {
|
if (!tabSupervisor->close()) {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
bClosingDown = false;
|
bClosingDown = false;
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
|
||||||
const QStringList DeckLoader::fileNameFilters = QStringList()
|
const QStringList DeckLoader::ACCEPTED_FILE_EXTENSIONS = {"*.cod", "*.dec", "*.dek", "*.txt", "*.mwDeck"};
|
||||||
<< QObject::tr("Common deck formats (*.cod *.dec *.dek *.txt *.mwDeck)")
|
|
||||||
<< QObject::tr("All files (*.*)");
|
const QStringList DeckLoader::FILE_NAME_FILTERS = {
|
||||||
|
tr("Common deck formats (%1)").arg(ACCEPTED_FILE_EXTENSIONS.join(" ")), tr("All files (*.*)")};
|
||||||
|
|
||||||
DeckLoader::DeckLoader() : DeckList(), lastFileName(QString()), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
|
DeckLoader::DeckLoader() : DeckList(), lastFileName(QString()), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
|
||||||
{
|
{
|
||||||
|
|
@ -225,6 +226,19 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, FileFormat f
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString getDomainForWebsite(DeckLoader::DecklistWebsite website)
|
||||||
|
{
|
||||||
|
switch (website) {
|
||||||
|
case DeckLoader::DecklistOrg:
|
||||||
|
return "www.decklist.org";
|
||||||
|
case DeckLoader::DecklistXyz:
|
||||||
|
return "www.decklist.xyz";
|
||||||
|
default:
|
||||||
|
qCWarning(DeckLoaderLog) << "Invalid decklist website enum:" << website;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This struct is here to support the forEachCard function call, defined in decklist. It
|
// This struct is here to support the forEachCard function call, defined in decklist. It
|
||||||
// requires a function to be called for each card, and passes an inner node and a card for
|
// requires a function to be called for each card, and passes an inner node and a card for
|
||||||
// each card in the decklist.
|
// each card in the decklist.
|
||||||
|
|
@ -274,11 +288,14 @@ struct FormatDeckListForExport
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export deck to decklist function, called to format the deck in a way to be sent to a server
|
/**
|
||||||
QString DeckLoader::exportDeckToDecklist()
|
* Export deck to decklist function, called to format the deck in a way to be sent to a server
|
||||||
|
* @param website The website we're sending the deck to
|
||||||
|
*/
|
||||||
|
QString DeckLoader::exportDeckToDecklist(DecklistWebsite website)
|
||||||
{
|
{
|
||||||
// Add the base url
|
// Add the base url
|
||||||
QString deckString = "https://www.decklist.org/?";
|
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
|
||||||
// Create two strings to pass to function
|
// Create two strings to pass to function
|
||||||
QString mainBoardCards, sideBoardCards;
|
QString mainBoardCards, sideBoardCards;
|
||||||
// Set up the struct to call.
|
// Set up the struct to call.
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,22 @@ public:
|
||||||
PlainTextFormat,
|
PlainTextFormat,
|
||||||
CockatriceFormat
|
CockatriceFormat
|
||||||
};
|
};
|
||||||
static const QStringList fileNameFilters;
|
|
||||||
|
/**
|
||||||
|
* Supported file extensions for decklist files
|
||||||
|
*/
|
||||||
|
static const QStringList ACCEPTED_FILE_EXTENSIONS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For use with `QFileDialog::setNameFilters`
|
||||||
|
*/
|
||||||
|
static const QStringList FILE_NAME_FILTERS;
|
||||||
|
|
||||||
|
enum DecklistWebsite
|
||||||
|
{
|
||||||
|
DecklistOrg,
|
||||||
|
DecklistXyz
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString lastFileName;
|
QString lastFileName;
|
||||||
|
|
@ -62,7 +77,7 @@ public:
|
||||||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
||||||
bool saveToFile(const QString &fileName, FileFormat fmt);
|
bool saveToFile(const QString &fileName, FileFormat fmt);
|
||||||
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
||||||
QString exportDeckToDecklist();
|
QString exportDeckToDecklist(DecklistWebsite website);
|
||||||
|
|
||||||
void resolveSetNameAndNumberToProviderID();
|
void resolveSetNameAndNumberToProviderID();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ DlgLoadDeck::DlgLoadDeck(QWidget *parent) : QFileDialog(parent, tr("Load Deck"))
|
||||||
}
|
}
|
||||||
|
|
||||||
setDirectory(startingDir);
|
setDirectory(startingDir);
|
||||||
setNameFilters(DeckLoader::fileNameFilters);
|
setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
||||||
|
|
||||||
connect(this, &DlgLoadDeck::accepted, this, &DlgLoadDeck::actAccepted);
|
connect(this, &DlgLoadDeck::accepted, this, &DlgLoadDeck::actAccepted);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const
|
||||||
|
|
||||||
QTextStream stream(&buffer);
|
QTextStream stream(&buffer);
|
||||||
|
|
||||||
if (deckLoader->loadFromStream_Plain(stream)) {
|
if (deckLoader->loadFromStream_Plain(stream, true)) {
|
||||||
if (loadSetNameAndNumberCheckBox->isChecked()) {
|
if (loadSetNameAndNumberCheckBox->isChecked()) {
|
||||||
deckLoader->resolveSetNameAndNumberToProviderID();
|
deckLoader->resolveSetNameAndNumberToProviderID();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../settings/cache_settings.h"
|
#include "../settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
|
@ -162,6 +163,11 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
sortWarning->setLayout(sortWarningLayout);
|
sortWarning->setLayout(sortWarningLayout);
|
||||||
sortWarning->setVisible(false);
|
sortWarning->setVisible(false);
|
||||||
|
|
||||||
|
includeOnlineOnlyCards = SettingsCache::instance().getIncludeOnlineOnlyCards();
|
||||||
|
QCheckBox *onlineOnly = new QCheckBox(tr("Include online-only (Arena) cards [requires restart]"));
|
||||||
|
onlineOnly->setChecked(includeOnlineOnlyCards);
|
||||||
|
connect(onlineOnly, &QAbstractButton::toggled, this, &WndSets::includeOnlineOnlyCardsChanged);
|
||||||
|
|
||||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actSave()));
|
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actSave()));
|
||||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(actRestore()));
|
connect(buttonBox, SIGNAL(rejected()), this, SLOT(actRestore()));
|
||||||
|
|
@ -175,8 +181,9 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
mainLayout->addWidget(enableSomeButton, 2, 1);
|
mainLayout->addWidget(enableSomeButton, 2, 1);
|
||||||
mainLayout->addWidget(disableSomeButton, 2, 2);
|
mainLayout->addWidget(disableSomeButton, 2, 2);
|
||||||
mainLayout->addWidget(sortWarning, 3, 1, 1, 2);
|
mainLayout->addWidget(sortWarning, 3, 1, 1, 2);
|
||||||
mainLayout->addWidget(hintsGroupBox, 4, 1, 1, 2);
|
mainLayout->addWidget(onlineOnly, 4, 1, 1, 2);
|
||||||
mainLayout->addWidget(buttonBox, 5, 1, 1, 2);
|
mainLayout->addWidget(hintsGroupBox, 5, 1, 1, 2);
|
||||||
|
mainLayout->addWidget(buttonBox, 6, 1, 1, 2);
|
||||||
mainLayout->setColumnStretch(1, 1);
|
mainLayout->setColumnStretch(1, 1);
|
||||||
mainLayout->setColumnStretch(2, 1);
|
mainLayout->setColumnStretch(2, 1);
|
||||||
|
|
||||||
|
|
@ -239,9 +246,15 @@ void WndSets::rebuildMainLayout(int actionToTake)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WndSets::includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCards)
|
||||||
|
{
|
||||||
|
includeOnlineOnlyCards = _includeOnlineOnlyCards;
|
||||||
|
}
|
||||||
|
|
||||||
void WndSets::actSave()
|
void WndSets::actSave()
|
||||||
{
|
{
|
||||||
model->save(CardDatabaseManager::getInstance());
|
model->save(CardDatabaseManager::getInstance());
|
||||||
|
SettingsCache::instance().setIncludeOnlineOnlyCards(includeOnlineOnlyCards);
|
||||||
PictureLoader::clearPixmapCache();
|
PictureLoader::clearPixmapCache();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ private:
|
||||||
void saveHeaderState();
|
void saveHeaderState();
|
||||||
void rebuildMainLayout(int actionToTake);
|
void rebuildMainLayout(int actionToTake);
|
||||||
bool setOrderIsSorted;
|
bool setOrderIsSorted;
|
||||||
|
bool includeOnlineOnlyCards;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
NO_SETS_SELECTED,
|
NO_SETS_SELECTED,
|
||||||
|
|
@ -73,6 +74,7 @@ private slots:
|
||||||
void actDisableResetButton(const QString &filterText);
|
void actDisableResetButton(const QString &filterText);
|
||||||
void actSort(int index);
|
void actSort(int index);
|
||||||
void actIgnoreWarning();
|
void actIgnoreWarning();
|
||||||
|
void includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCardsChanged);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#include "../game/cards/card_database.h"
|
#include "../game/cards/card_database.h"
|
||||||
#include "../game/cards/card_database_manager.h"
|
#include "../game/cards/card_database_manager.h"
|
||||||
#include "../game/filters/filter_string.h"
|
#include "../game/filters/filter_string.h"
|
||||||
#include "trice_limits.h"
|
|
||||||
|
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
@ -14,15 +13,17 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QString _expr, uint _numberOfHits, bool autoPlay)
|
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QStringList exprs, uint _numberOfHits, bool autoPlay)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
{
|
{
|
||||||
exprLabel = new QLabel(tr("Card name (or search expressions):"));
|
exprLabel = new QLabel(tr("Card name (or search expressions):"));
|
||||||
|
|
||||||
exprEdit = new QLineEdit(this);
|
exprComboBox = new QComboBox(this);
|
||||||
exprEdit->setFocus();
|
exprComboBox->setFocus();
|
||||||
exprEdit->setText(_expr);
|
exprComboBox->setEditable(true);
|
||||||
exprLabel->setBuddy(exprEdit);
|
exprComboBox->setInsertPolicy(QComboBox::InsertAtTop);
|
||||||
|
exprComboBox->insertItems(0, exprs);
|
||||||
|
exprLabel->setBuddy(exprComboBox);
|
||||||
|
|
||||||
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
|
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
|
||||||
numberOfHitsEdit = new QSpinBox(this);
|
numberOfHitsEdit = new QSpinBox(this);
|
||||||
|
|
@ -43,7 +44,7 @@ DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QString _expr, uint
|
||||||
|
|
||||||
auto *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addWidget(exprLabel);
|
mainLayout->addWidget(exprLabel);
|
||||||
mainLayout->addWidget(exprEdit);
|
mainLayout->addWidget(exprComboBox);
|
||||||
mainLayout->addItem(grid);
|
mainLayout->addItem(grid);
|
||||||
mainLayout->addWidget(autoPlayCheckBox);
|
mainLayout->addWidget(autoPlayCheckBox);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
|
|
@ -92,7 +93,7 @@ bool DlgMoveTopCardsUntil::validateMatchExists(const FilterString &filterString)
|
||||||
|
|
||||||
void DlgMoveTopCardsUntil::validateAndAccept()
|
void DlgMoveTopCardsUntil::validateAndAccept()
|
||||||
{
|
{
|
||||||
auto movingCardsUntilFilter = FilterString(exprEdit->text());
|
auto movingCardsUntilFilter = FilterString(exprComboBox->currentText());
|
||||||
if (!movingCardsUntilFilter.valid()) {
|
if (!movingCardsUntilFilter.valid()) {
|
||||||
QMessageBox::warning(this, tr("Invalid filter"), movingCardsUntilFilter.error(), QMessageBox::Ok);
|
QMessageBox::warning(this, tr("Invalid filter"), movingCardsUntilFilter.error(), QMessageBox::Ok);
|
||||||
return;
|
return;
|
||||||
|
|
@ -102,12 +103,29 @@ void DlgMoveTopCardsUntil::validateAndAccept()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move currently selected text to top of history list
|
||||||
|
if (exprComboBox->currentIndex() != 0) {
|
||||||
|
QString currentExpr = exprComboBox->currentText();
|
||||||
|
exprComboBox->removeItem(exprComboBox->currentIndex());
|
||||||
|
exprComboBox->insertItem(0, currentExpr);
|
||||||
|
exprComboBox->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DlgMoveTopCardsUntil::getExpr() const
|
QString DlgMoveTopCardsUntil::getExpr() const
|
||||||
{
|
{
|
||||||
return exprEdit->text();
|
return exprComboBox->currentText();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList DlgMoveTopCardsUntil::getExprs() const
|
||||||
|
{
|
||||||
|
QStringList exprs;
|
||||||
|
for (int i = 0; i < exprComboBox->count(); ++i) {
|
||||||
|
exprs.append(exprComboBox->itemText(i));
|
||||||
|
}
|
||||||
|
return exprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint DlgMoveTopCardsUntil::getNumberOfHits() const
|
uint DlgMoveTopCardsUntil::getNumberOfHits() const
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
#define DLG_MOVE_TOP_CARDS_UNTIL_H
|
#define DLG_MOVE_TOP_CARDS_UNTIL_H
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
|
|
||||||
class FilterString;
|
class FilterString;
|
||||||
|
|
@ -15,7 +15,7 @@ class DlgMoveTopCardsUntil : public QDialog
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
QLabel *exprLabel, *numberOfHitsLabel;
|
QLabel *exprLabel, *numberOfHitsLabel;
|
||||||
QLineEdit *exprEdit;
|
QComboBox *exprComboBox;
|
||||||
QSpinBox *numberOfHitsEdit;
|
QSpinBox *numberOfHitsEdit;
|
||||||
QDialogButtonBox *buttonBox;
|
QDialogButtonBox *buttonBox;
|
||||||
QCheckBox *autoPlayCheckBox;
|
QCheckBox *autoPlayCheckBox;
|
||||||
|
|
@ -25,10 +25,11 @@ class DlgMoveTopCardsUntil : public QDialog
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr,
|
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr,
|
||||||
QString expr = QString(),
|
QStringList exprs = QStringList(),
|
||||||
uint numberOfHits = 1,
|
uint numberOfHits = 1,
|
||||||
bool autoPlay = false);
|
bool autoPlay = false);
|
||||||
QString getExpr() const;
|
QString getExpr() const;
|
||||||
|
QStringList getExprs() const;
|
||||||
uint getNumberOfHits() const;
|
uint getNumberOfHits() const;
|
||||||
bool isAutoPlay() const;
|
bool isAutoPlay() const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <qabstractbutton.h>
|
||||||
|
|
||||||
#define WIKI_CUSTOM_PIC_URL "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Picture-Download-URLs"
|
#define WIKI_CUSTOM_PIC_URL "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Picture-Download-URLs"
|
||||||
#define WIKI_CUSTOM_SHORTCUTS "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Keyboard-Shortcuts"
|
#define WIKI_CUSTOM_SHORTCUTS "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Keyboard-Shortcuts"
|
||||||
|
|
@ -358,25 +359,8 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
||||||
showShortcutsCheckBox.setChecked(settings.getShowShortcuts());
|
showShortcutsCheckBox.setChecked(settings.getShowShortcuts());
|
||||||
connect(&showShortcutsCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &AppearanceSettingsPage::showShortcutsChanged);
|
connect(&showShortcutsCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &AppearanceSettingsPage::showShortcutsChanged);
|
||||||
|
|
||||||
visualDeckStorageDrawUnusedColorIdentitiesCheckBox.setChecked(
|
|
||||||
settings.getVisualDeckStorageDrawUnusedColorIdentities());
|
|
||||||
connect(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
|
|
||||||
&SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
|
|
||||||
|
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setMinimum(0);
|
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setMaximum(100);
|
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setValue(
|
|
||||||
settings.getVisualDeckStorageUnusedColorIdentitiesOpacity());
|
|
||||||
connect(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
|
|
||||||
&settings, &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
|
|
||||||
|
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacityLabel.setBuddy(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox);
|
|
||||||
|
|
||||||
auto *menuGrid = new QGridLayout;
|
auto *menuGrid = new QGridLayout;
|
||||||
menuGrid->addWidget(&showShortcutsCheckBox, 0, 0);
|
menuGrid->addWidget(&showShortcutsCheckBox, 0, 0);
|
||||||
menuGrid->addWidget(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, 1, 0);
|
|
||||||
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacityLabel, 2, 0);
|
|
||||||
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, 2, 1);
|
|
||||||
|
|
||||||
menuGroupBox = new QGroupBox;
|
menuGroupBox = new QGroupBox;
|
||||||
menuGroupBox->setLayout(menuGrid);
|
menuGroupBox->setLayout(menuGrid);
|
||||||
|
|
@ -400,6 +384,9 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
||||||
cardScalingCheckBox.setChecked(settings.getScaleCards());
|
cardScalingCheckBox.setChecked(settings.getScaleCards());
|
||||||
connect(&cardScalingCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setCardScaling);
|
connect(&cardScalingCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setCardScaling);
|
||||||
|
|
||||||
|
roundCardCornersCheckBox.setChecked(settings.getRoundCardCorners());
|
||||||
|
connect(&roundCardCornersCheckBox, &QAbstractButton::toggled, &settings, &SettingsCache::setRoundCardCorners);
|
||||||
|
|
||||||
verticalCardOverlapPercentBox.setValue(settings.getStackCardOverlapPercent());
|
verticalCardOverlapPercentBox.setValue(settings.getStackCardOverlapPercent());
|
||||||
verticalCardOverlapPercentBox.setRange(0, 80);
|
verticalCardOverlapPercentBox.setRange(0, 80);
|
||||||
connect(&verticalCardOverlapPercentBox, SIGNAL(valueChanged(int)), &settings,
|
connect(&verticalCardOverlapPercentBox, SIGNAL(valueChanged(int)), &settings,
|
||||||
|
|
@ -419,14 +406,15 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
||||||
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
|
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
|
||||||
cardsGrid->addWidget(&autoRotateSidewaysLayoutCardsCheckBox, 1, 0, 1, 2);
|
cardsGrid->addWidget(&autoRotateSidewaysLayoutCardsCheckBox, 1, 0, 1, 2);
|
||||||
cardsGrid->addWidget(&cardScalingCheckBox, 2, 0, 1, 2);
|
cardsGrid->addWidget(&cardScalingCheckBox, 2, 0, 1, 2);
|
||||||
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 3, 0, 1, 2);
|
cardsGrid->addWidget(&roundCardCornersCheckBox, 3, 0, 1, 2);
|
||||||
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 4, 0, 1, 2);
|
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 4, 0, 1, 2);
|
||||||
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 5, 0, 1, 1);
|
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 5, 0, 1, 2);
|
||||||
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 5, 1, 1, 1);
|
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 6, 0, 1, 1);
|
||||||
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 6, 0);
|
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 6, 1, 1, 1);
|
||||||
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 6, 1);
|
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 7, 0);
|
||||||
cardsGrid->addWidget(&cardViewExpandedRowsMaxLabel, 7, 0);
|
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 7, 1);
|
||||||
cardsGrid->addWidget(&cardViewExpandedRowsMaxBox, 7, 1);
|
cardsGrid->addWidget(&cardViewExpandedRowsMaxLabel, 8, 0);
|
||||||
|
cardsGrid->addWidget(&cardViewExpandedRowsMaxBox, 8, 1);
|
||||||
|
|
||||||
cardsGroupBox = new QGroupBox;
|
cardsGroupBox = new QGroupBox;
|
||||||
cardsGroupBox->setLayout(cardsGrid);
|
cardsGroupBox->setLayout(cardsGrid);
|
||||||
|
|
@ -547,10 +535,6 @@ void AppearanceSettingsPage::retranslateUi()
|
||||||
|
|
||||||
menuGroupBox->setTitle(tr("Menu settings"));
|
menuGroupBox->setTitle(tr("Menu settings"));
|
||||||
showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus"));
|
showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus"));
|
||||||
visualDeckStorageDrawUnusedColorIdentitiesCheckBox.setText(
|
|
||||||
tr("Draw missing color identities in visual deck storage without color label"));
|
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacityLabel.setText(tr("Missing color identity opacity"));
|
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setSuffix("%");
|
|
||||||
|
|
||||||
cardsGroupBox->setTitle(tr("Card rendering"));
|
cardsGroupBox->setTitle(tr("Card rendering"));
|
||||||
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
||||||
|
|
@ -561,6 +545,7 @@ void AppearanceSettingsPage::retranslateUi()
|
||||||
bumpSetsWithCardsInDeckToTopCheckBox.setText(
|
bumpSetsWithCardsInDeckToTopCheckBox.setText(
|
||||||
tr("Bump sets that the deck contains cards from to the top in the printing selector"));
|
tr("Bump sets that the deck contains cards from to the top in the printing selector"));
|
||||||
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
|
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
|
||||||
|
roundCardCornersCheckBox.setText(tr("Use rounded card corners"));
|
||||||
verticalCardOverlapPercentLabel.setText(
|
verticalCardOverlapPercentLabel.setText(
|
||||||
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));
|
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));
|
||||||
cardViewInitialRowsMaxLabel.setText(tr("Maximum initial height for card view window:"));
|
cardViewInitialRowsMaxLabel.setText(tr("Maximum initial height for card view window:"));
|
||||||
|
|
|
||||||
|
|
@ -102,14 +102,12 @@ private:
|
||||||
QLabel minPlayersForMultiColumnLayoutLabel;
|
QLabel minPlayersForMultiColumnLayoutLabel;
|
||||||
QLabel maxFontSizeForCardsLabel;
|
QLabel maxFontSizeForCardsLabel;
|
||||||
QCheckBox showShortcutsCheckBox;
|
QCheckBox showShortcutsCheckBox;
|
||||||
QCheckBox visualDeckStorageDrawUnusedColorIdentitiesCheckBox;
|
|
||||||
QLabel visualDeckStorageUnusedColorIdentitiesOpacityLabel;
|
|
||||||
QSpinBox visualDeckStorageUnusedColorIdentitiesOpacitySpinBox;
|
|
||||||
QCheckBox displayCardNamesCheckBox;
|
QCheckBox displayCardNamesCheckBox;
|
||||||
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
||||||
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
||||||
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
|
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
|
||||||
QCheckBox cardScalingCheckBox;
|
QCheckBox cardScalingCheckBox;
|
||||||
|
QCheckBox roundCardCornersCheckBox;
|
||||||
QLabel verticalCardOverlapPercentLabel;
|
QLabel verticalCardOverlapPercentLabel;
|
||||||
QSpinBox verticalCardOverlapPercentBox;
|
QSpinBox verticalCardOverlapPercentBox;
|
||||||
QLabel cardViewInitialRowsMaxLabel;
|
QLabel cardViewInitialRowsMaxLabel;
|
||||||
|
|
|
||||||
|
|
@ -165,10 +165,12 @@ void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Releas
|
||||||
QString(":</b> %1<br>").arg(release->getName()) + "<b>" + tr("Released") +
|
QString(":</b> %1<br>").arg(release->getName()) + "<b>" + tr("Released") +
|
||||||
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
|
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
|
||||||
"</a>)<br><br>" +
|
"</a>)<br><br>" +
|
||||||
tr("Unfortunately there are no download packages available for your operating system. \nYou may have "
|
tr("Unfortunately, the automatic updater failed to find a compatible download. \nYou may have to "
|
||||||
"to build from source yourself.") +
|
"manually download the new version.") +
|
||||||
"<br><br>" +
|
"<br><br>" +
|
||||||
tr("Please check the download page manually and visit the wiki for instructions on compiling."));
|
tr("Please check the <a href=\"%1\">releases page</a> on our Github and download the build for your "
|
||||||
|
"system.")
|
||||||
|
.arg(release->getDescriptionUrl()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
ArrowTarget::ArrowTarget(Player *_owner, QGraphicsItem *parent)
|
ArrowTarget::ArrowTarget(Player *_owner, QGraphicsItem *parent)
|
||||||
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
|
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
|
||||||
{
|
{
|
||||||
|
setFlag(ItemSendsScenePositionChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrowTarget::~ArrowTarget()
|
ArrowTarget::~ArrowTarget()
|
||||||
|
|
@ -25,3 +26,16 @@ void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
|
||||||
beingPointedAt = _beingPointedAt;
|
beingPointedAt = _beingPointedAt;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant ArrowTarget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (change == ItemScenePositionHasChanged && scene()) {
|
||||||
|
for (auto *arrow : arrowsFrom)
|
||||||
|
arrow->updatePath();
|
||||||
|
|
||||||
|
for (auto *arrow : arrowsTo)
|
||||||
|
arrow->updatePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QGraphicsItem::itemChange(change, value);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,5 +57,8 @@ public:
|
||||||
{
|
{
|
||||||
arrowsTo.removeOne(arrow);
|
arrowsTo.removeOne(arrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "abstract_card_drag_item.h"
|
#include "abstract_card_drag_item.h"
|
||||||
|
|
||||||
#include "card_database.h"
|
#include "../../settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
@ -32,6 +32,13 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
||||||
|
|
||||||
setCacheMode(DeviceCoordinateCache);
|
setCacheMode(DeviceCoordinateCache);
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
||||||
|
prepareGeometryChange();
|
||||||
|
update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractCardDragItem::~AbstractCardDragItem()
|
AbstractCardDragItem::~AbstractCardDragItem()
|
||||||
|
|
@ -43,7 +50,8 @@ AbstractCardDragItem::~AbstractCardDragItem()
|
||||||
QPainterPath AbstractCardDragItem::shape() const
|
QPainterPath AbstractCardDragItem::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
||||||
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,13 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
|
||||||
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::displayCardNamesChanged, this, [this] { update(); });
|
connect(&SettingsCache::instance(), &SettingsCache::displayCardNamesChanged, this, [this] { update(); });
|
||||||
refreshCardInfo();
|
refreshCardInfo();
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
||||||
|
prepareGeometryChange();
|
||||||
|
update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractCardItem::~AbstractCardItem()
|
AbstractCardItem::~AbstractCardItem()
|
||||||
|
|
@ -41,7 +48,8 @@ QRectF AbstractCardItem::boundingRect() const
|
||||||
QPainterPath AbstractCardItem::shape() const
|
QPainterPath AbstractCardItem::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
||||||
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,5 +333,5 @@ QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change,
|
||||||
update();
|
update();
|
||||||
return value;
|
return value;
|
||||||
} else
|
} else
|
||||||
return QGraphicsItem::itemChange(change, value);
|
return ArrowTarget::itemChange(change, value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
#include "card_database.h"
|
#include "card_database.h"
|
||||||
|
|
||||||
#include "../../client/network/spoiler_background_updater.h"
|
|
||||||
#include "../../client/ui/picture_loader/picture_loader.h"
|
#include "../../client/ui/picture_loader/picture_loader.h"
|
||||||
#include "../../settings/cache_settings.h"
|
#include "../../settings/cache_settings.h"
|
||||||
#include "../../utility/card_set_comparator.h"
|
#include "../../utility/card_set_comparator.h"
|
||||||
#include "../game_specific_terms.h"
|
|
||||||
#include "./card_database_parser/cockatrice_xml_3.h"
|
#include "./card_database_parser/cockatrice_xml_3.h"
|
||||||
#include "./card_database_parser/cockatrice_xml_4.h"
|
#include "./card_database_parser/cockatrice_xml_4.h"
|
||||||
|
|
||||||
|
|
@ -20,351 +18,6 @@
|
||||||
|
|
||||||
const char *CardDatabase::TOKENS_SETNAME = "TK";
|
const char *CardDatabase::TOKENS_SETNAME = "TK";
|
||||||
|
|
||||||
CardSet::CardSet(const QString &_shortName,
|
|
||||||
const QString &_longName,
|
|
||||||
const QString &_setType,
|
|
||||||
const QDate &_releaseDate,
|
|
||||||
const CardSet::Priority _priority)
|
|
||||||
: shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType), priority(_priority)
|
|
||||||
{
|
|
||||||
loadSetOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
CardSetPtr CardSet::newInstance(const QString &_shortName,
|
|
||||||
const QString &_longName,
|
|
||||||
const QString &_setType,
|
|
||||||
const QDate &_releaseDate,
|
|
||||||
const Priority _priority)
|
|
||||||
{
|
|
||||||
CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate, _priority));
|
|
||||||
// ptr->setSmartPointer(ptr);
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CardSet::getCorrectedShortName() const
|
|
||||||
{
|
|
||||||
// For Windows machines.
|
|
||||||
QSet<QString> invalidFileNames;
|
|
||||||
invalidFileNames << "CON"
|
|
||||||
<< "PRN"
|
|
||||||
<< "AUX"
|
|
||||||
<< "NUL"
|
|
||||||
<< "COM1"
|
|
||||||
<< "COM2"
|
|
||||||
<< "COM3"
|
|
||||||
<< "COM4"
|
|
||||||
<< "COM5"
|
|
||||||
<< "COM6"
|
|
||||||
<< "COM7"
|
|
||||||
<< "COM8"
|
|
||||||
<< "COM9"
|
|
||||||
<< "LPT1"
|
|
||||||
<< "LPT2"
|
|
||||||
<< "LPT3"
|
|
||||||
<< "LPT4"
|
|
||||||
<< "LPT5"
|
|
||||||
<< "LPT6"
|
|
||||||
<< "LPT7"
|
|
||||||
<< "LPT8"
|
|
||||||
<< "LPT9";
|
|
||||||
|
|
||||||
return invalidFileNames.contains(shortName) ? shortName + "_" : shortName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardSet::loadSetOptions()
|
|
||||||
{
|
|
||||||
sortKey = SettingsCache::instance().cardDatabase().getSortKey(shortName);
|
|
||||||
enabled = SettingsCache::instance().cardDatabase().isEnabled(shortName);
|
|
||||||
isknown = SettingsCache::instance().cardDatabase().isKnown(shortName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardSet::setSortKey(unsigned int _sortKey)
|
|
||||||
{
|
|
||||||
sortKey = _sortKey;
|
|
||||||
SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardSet::setEnabled(bool _enabled)
|
|
||||||
{
|
|
||||||
enabled = _enabled;
|
|
||||||
SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardSet::setIsKnown(bool _isknown)
|
|
||||||
{
|
|
||||||
isknown = _isknown;
|
|
||||||
SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
class SetList::KeyCompareFunctor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
|
|
||||||
{
|
|
||||||
if (a.isNull() || b.isNull()) {
|
|
||||||
qCDebug(CardDatabaseLog) << "SetList::KeyCompareFunctor a or b is null";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a->getSortKey() < b->getSortKey();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetList::sortByKey()
|
|
||||||
{
|
|
||||||
std::sort(begin(), end(), KeyCompareFunctor());
|
|
||||||
}
|
|
||||||
|
|
||||||
int SetList::getEnabledSetsNum()
|
|
||||||
{
|
|
||||||
int num = 0;
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
if (set && set->getEnabled()) {
|
|
||||||
++num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SetList::getUnknownSetsNum()
|
|
||||||
{
|
|
||||||
int num = 0;
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
|
||||||
++num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList SetList::getUnknownSetsNames()
|
|
||||||
{
|
|
||||||
QStringList sets = QStringList();
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
|
||||||
sets << set->getShortName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sets;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetList::enableAllUnknown()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
|
||||||
set->setIsKnown(true);
|
|
||||||
set->setEnabled(true);
|
|
||||||
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
|
|
||||||
set->setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetList::enableAll()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
|
|
||||||
if (set == nullptr) {
|
|
||||||
qCDebug(CardDatabaseLog) << "enabledAll has null";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set->getIsKnownIgnored()) {
|
|
||||||
set->setIsKnown(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
set->setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetList::markAllAsKnown()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
|
||||||
set->setIsKnown(true);
|
|
||||||
set->setEnabled(false);
|
|
||||||
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
|
|
||||||
set->setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetList::guessSortKeys()
|
|
||||||
{
|
|
||||||
defaultSort();
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
CardSetPtr set = at(i);
|
|
||||||
if (set.isNull()) {
|
|
||||||
qCDebug(CardDatabaseLog) << "guessSortKeys set is null";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
set->setSortKey(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetList::defaultSort()
|
|
||||||
{
|
|
||||||
std::sort(begin(), end(), [](const CardSetPtr &a, const CardSetPtr &b) {
|
|
||||||
// Sort by priority, then by release date, then by short name
|
|
||||||
if (a->getPriority() != b->getPriority()) {
|
|
||||||
return a->getPriority() < b->getPriority(); // lowest first
|
|
||||||
} else if (a->getReleaseDate() != b->getReleaseDate()) {
|
|
||||||
return a->getReleaseDate() > b->getReleaseDate(); // most recent first
|
|
||||||
} else {
|
|
||||||
return a->getShortName() < b->getShortName(); // alphabetically
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CardInfo::CardInfo(const QString &_name,
|
|
||||||
const QString &_text,
|
|
||||||
bool _isToken,
|
|
||||||
QVariantHash _properties,
|
|
||||||
const QList<CardRelation *> &_relatedCards,
|
|
||||||
const QList<CardRelation *> &_reverseRelatedCards,
|
|
||||||
CardInfoPerSetMap _sets,
|
|
||||||
bool _cipt,
|
|
||||||
bool _landscapeOrientation,
|
|
||||||
int _tableRow,
|
|
||||||
bool _upsideDownArt)
|
|
||||||
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
|
|
||||||
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt),
|
|
||||||
landscapeOrientation(_landscapeOrientation), tableRow(_tableRow), upsideDownArt(_upsideDownArt)
|
|
||||||
{
|
|
||||||
pixmapCacheKey = QLatin1String("card_") + name;
|
|
||||||
simpleName = CardInfo::simplifyName(name);
|
|
||||||
|
|
||||||
refreshCachedSetNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
CardInfo::~CardInfo()
|
|
||||||
{
|
|
||||||
PictureLoader::clearPixmapCache(smartThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
CardInfoPtr CardInfo::newInstance(const QString &_name)
|
|
||||||
{
|
|
||||||
return newInstance(_name, QString(), false, QVariantHash(), QList<CardRelation *>(), QList<CardRelation *>(),
|
|
||||||
CardInfoPerSetMap(), false, false, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
CardInfoPtr CardInfo::newInstance(const QString &_name,
|
|
||||||
const QString &_text,
|
|
||||||
bool _isToken,
|
|
||||||
QVariantHash _properties,
|
|
||||||
const QList<CardRelation *> &_relatedCards,
|
|
||||||
const QList<CardRelation *> &_reverseRelatedCards,
|
|
||||||
CardInfoPerSetMap _sets,
|
|
||||||
bool _cipt,
|
|
||||||
bool _landscapeOrientation,
|
|
||||||
int _tableRow,
|
|
||||||
bool _upsideDownArt)
|
|
||||||
{
|
|
||||||
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
|
|
||||||
_sets, _cipt, _landscapeOrientation, _tableRow, _upsideDownArt));
|
|
||||||
ptr->setSmartPointer(ptr);
|
|
||||||
|
|
||||||
for (const auto &cardInfoPerSetList : _sets) {
|
|
||||||
for (const CardInfoPerSet &set : cardInfoPerSetList) {
|
|
||||||
set.getPtr()->append(ptr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
|
|
||||||
{
|
|
||||||
_set->append(smartThis);
|
|
||||||
sets[_set->getShortName()].append(_info);
|
|
||||||
|
|
||||||
refreshCachedSetNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfo::combineLegalities(const QVariantHash &props)
|
|
||||||
{
|
|
||||||
QHashIterator<QString, QVariant> it(props);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
if (it.key().startsWith("format-")) {
|
|
||||||
smartThis->setProperty(it.key(), it.value().toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfo::refreshCachedSetNames()
|
|
||||||
{
|
|
||||||
QStringList setList;
|
|
||||||
// update the cached list of set names
|
|
||||||
for (const auto &cardInfoPerSetList : sets) {
|
|
||||||
for (const auto &set : cardInfoPerSetList) {
|
|
||||||
if (set.getPtr()->getEnabled()) {
|
|
||||||
setList << set.getPtr()->getShortName();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setsNames = setList.join(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CardInfo::simplifyName(const QString &name)
|
|
||||||
{
|
|
||||||
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
|
|
||||||
static const QRegularExpression nonAlnum("[^a-z0-9]");
|
|
||||||
|
|
||||||
QString simpleName = name.toLower();
|
|
||||||
|
|
||||||
// remove spaces and right halves of split cards
|
|
||||||
simpleName.remove(spaceOrSplit);
|
|
||||||
|
|
||||||
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
|
|
||||||
// with nothing.
|
|
||||||
simpleName.replace("æ", "ae");
|
|
||||||
|
|
||||||
// Replace Jötun Grunt with Jotun Grunt.
|
|
||||||
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
|
|
||||||
|
|
||||||
// remove all non alphanumeric characters from the name
|
|
||||||
simpleName.remove(nonAlnum);
|
|
||||||
return simpleName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QChar CardInfo::getColorChar() const
|
|
||||||
{
|
|
||||||
QString colors = getColors();
|
|
||||||
switch (colors.size()) {
|
|
||||||
case 0:
|
|
||||||
return QChar();
|
|
||||||
case 1:
|
|
||||||
return colors.at(0);
|
|
||||||
default:
|
|
||||||
return QChar('m');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
|
CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
|
||||||
{
|
{
|
||||||
qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
|
qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
|
||||||
|
|
@ -884,64 +537,3 @@ bool CardDatabase::saveCustomTokensToFile()
|
||||||
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
|
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CardRelation::CardRelation(const QString &_name,
|
|
||||||
AttachType _attachType,
|
|
||||||
bool _isCreateAllExclusion,
|
|
||||||
bool _isVariableCount,
|
|
||||||
int _defaultCount,
|
|
||||||
bool _isPersistent)
|
|
||||||
: name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion),
|
|
||||||
isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardInfo::resetReverseRelatedCards2Me()
|
|
||||||
{
|
|
||||||
for (CardRelation *cardRelation : this->getReverseRelatedCards2Me()) {
|
|
||||||
cardRelation->deleteLater();
|
|
||||||
}
|
|
||||||
reverseRelatedCardsToMe = QList<CardRelation *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Back-compatibility methods. Remove ASAP
|
|
||||||
const QString CardInfo::getCardType() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::CardType);
|
|
||||||
}
|
|
||||||
void CardInfo::setCardType(const QString &value)
|
|
||||||
{
|
|
||||||
setProperty(Mtg::CardType, value);
|
|
||||||
}
|
|
||||||
const QString CardInfo::getCmc() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::ConvertedManaCost);
|
|
||||||
}
|
|
||||||
const QString CardInfo::getColors() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::Colors);
|
|
||||||
}
|
|
||||||
void CardInfo::setColors(const QString &value)
|
|
||||||
{
|
|
||||||
setProperty(Mtg::Colors, value);
|
|
||||||
}
|
|
||||||
const QString CardInfo::getLoyalty() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::Loyalty);
|
|
||||||
}
|
|
||||||
const QString CardInfo::getMainCardType() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::MainCardType);
|
|
||||||
}
|
|
||||||
const QString CardInfo::getManaCost() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::ManaCost);
|
|
||||||
}
|
|
||||||
const QString CardInfo::getPowTough() const
|
|
||||||
{
|
|
||||||
return getProperty(Mtg::PowTough);
|
|
||||||
}
|
|
||||||
void CardInfo::setPowTough(const QString &value)
|
|
||||||
{
|
|
||||||
setProperty(Mtg::PowTough, value);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
#ifndef CARDDATABASE_H
|
#ifndef CARDDATABASE_H
|
||||||
#define CARDDATABASE_H
|
#define CARDDATABASE_H
|
||||||
|
|
||||||
|
#include "card_info.h"
|
||||||
|
|
||||||
#include <QBasicMutex>
|
#include <QBasicMutex>
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QMap>
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QSharedPointer>
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVariant>
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
@ -18,406 +16,8 @@ inline Q_LOGGING_CATEGORY(CardDatabaseLog, "card_database");
|
||||||
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingLog, "card_database.loading");
|
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingLog, "card_database.loading");
|
||||||
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingSuccessOrFailureLog, "card_database.loading.success_or_failure");
|
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingSuccessOrFailureLog, "card_database.loading.success_or_failure");
|
||||||
|
|
||||||
class CardDatabase;
|
|
||||||
class CardInfo;
|
|
||||||
class CardInfoPerSet;
|
|
||||||
class CardSet;
|
|
||||||
class CardRelation;
|
|
||||||
class ICardDatabaseParser;
|
class ICardDatabaseParser;
|
||||||
|
|
||||||
typedef QMap<QString, QString> QStringMap;
|
|
||||||
typedef QSharedPointer<CardInfo> CardInfoPtr;
|
|
||||||
typedef QSharedPointer<CardSet> CardSetPtr;
|
|
||||||
typedef QMap<QString, QList<CardInfoPerSet>> CardInfoPerSetMap;
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(CardInfoPtr)
|
|
||||||
|
|
||||||
class CardSet : public QList<CardInfoPtr>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Priority
|
|
||||||
{
|
|
||||||
PriorityFallback = 0,
|
|
||||||
PriorityPrimary = 10,
|
|
||||||
PrioritySecondary = 20,
|
|
||||||
PriorityReprint = 30,
|
|
||||||
PriorityOther = 40,
|
|
||||||
PriorityLowest = 100,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString shortName, longName;
|
|
||||||
unsigned int sortKey;
|
|
||||||
QDate releaseDate;
|
|
||||||
QString setType;
|
|
||||||
Priority priority;
|
|
||||||
bool enabled, isknown;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CardSet(const QString &_shortName = QString(),
|
|
||||||
const QString &_longName = QString(),
|
|
||||||
const QString &_setType = QString(),
|
|
||||||
const QDate &_releaseDate = QDate(),
|
|
||||||
const Priority _priority = PriorityFallback);
|
|
||||||
static CardSetPtr newInstance(const QString &_shortName = QString(),
|
|
||||||
const QString &_longName = QString(),
|
|
||||||
const QString &_setType = QString(),
|
|
||||||
const QDate &_releaseDate = QDate(),
|
|
||||||
const Priority _priority = PriorityFallback);
|
|
||||||
QString getCorrectedShortName() const;
|
|
||||||
QString getShortName() const
|
|
||||||
{
|
|
||||||
return shortName;
|
|
||||||
}
|
|
||||||
QString getLongName() const
|
|
||||||
{
|
|
||||||
return longName;
|
|
||||||
}
|
|
||||||
QString getSetType() const
|
|
||||||
{
|
|
||||||
return setType;
|
|
||||||
}
|
|
||||||
QDate getReleaseDate() const
|
|
||||||
{
|
|
||||||
return releaseDate;
|
|
||||||
}
|
|
||||||
Priority getPriority() const
|
|
||||||
{
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
void setLongName(const QString &_longName)
|
|
||||||
{
|
|
||||||
longName = _longName;
|
|
||||||
}
|
|
||||||
void setSetType(const QString &_setType)
|
|
||||||
{
|
|
||||||
setType = _setType;
|
|
||||||
}
|
|
||||||
void setReleaseDate(const QDate &_releaseDate)
|
|
||||||
{
|
|
||||||
releaseDate = _releaseDate;
|
|
||||||
}
|
|
||||||
void setPriority(const Priority _priority)
|
|
||||||
{
|
|
||||||
priority = _priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadSetOptions();
|
|
||||||
int getSortKey() const
|
|
||||||
{
|
|
||||||
return sortKey;
|
|
||||||
}
|
|
||||||
void setSortKey(unsigned int _sortKey);
|
|
||||||
bool getEnabled() const
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
void setEnabled(bool _enabled);
|
|
||||||
bool getIsKnown() const
|
|
||||||
{
|
|
||||||
return isknown;
|
|
||||||
}
|
|
||||||
void setIsKnown(bool _isknown);
|
|
||||||
|
|
||||||
// Determine incomplete sets.
|
|
||||||
bool getIsKnownIgnored() const
|
|
||||||
{
|
|
||||||
return longName.length() + setType.length() + releaseDate.toString().length() == 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SetList : public QList<CardSetPtr>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
class KeyCompareFunctor;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void sortByKey();
|
|
||||||
void guessSortKeys();
|
|
||||||
void enableAllUnknown();
|
|
||||||
void enableAll();
|
|
||||||
void markAllAsKnown();
|
|
||||||
int getEnabledSetsNum();
|
|
||||||
int getUnknownSetsNum();
|
|
||||||
QStringList getUnknownSetsNames();
|
|
||||||
void defaultSort();
|
|
||||||
};
|
|
||||||
|
|
||||||
class CardInfoPerSet
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit CardInfoPerSet(const CardSetPtr &_set = QSharedPointer<CardSet>(nullptr));
|
|
||||||
~CardInfoPerSet() = default;
|
|
||||||
|
|
||||||
bool operator==(const CardInfoPerSet &other) const
|
|
||||||
{
|
|
||||||
return this->set == other.set && this->properties == other.properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CardSetPtr set;
|
|
||||||
// per-set card properties;
|
|
||||||
QVariantHash properties;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const CardSetPtr getPtr() const
|
|
||||||
{
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
const QStringList getProperties() const
|
|
||||||
{
|
|
||||||
return properties.keys();
|
|
||||||
}
|
|
||||||
const QString getProperty(const QString &propertyName) const
|
|
||||||
{
|
|
||||||
return properties.value(propertyName).toString();
|
|
||||||
}
|
|
||||||
void setProperty(const QString &_name, const QString &_value)
|
|
||||||
{
|
|
||||||
properties.insert(_name, _value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CardInfo : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private:
|
|
||||||
CardInfoPtr smartThis;
|
|
||||||
// The card name
|
|
||||||
QString name;
|
|
||||||
// The name without punctuation or capitalization, for better card name recognition.
|
|
||||||
QString simpleName;
|
|
||||||
// The key used to identify this card in the cache
|
|
||||||
QString pixmapCacheKey;
|
|
||||||
// card text
|
|
||||||
QString text;
|
|
||||||
// whether this is not a "real" card but a token
|
|
||||||
bool isToken;
|
|
||||||
// basic card properties; common for all the sets
|
|
||||||
QVariantHash properties;
|
|
||||||
// the cards i'm related to
|
|
||||||
QList<CardRelation *> relatedCards;
|
|
||||||
// the card i'm reverse-related to
|
|
||||||
QList<CardRelation *> reverseRelatedCards;
|
|
||||||
// the cards thare are reverse-related to me
|
|
||||||
QList<CardRelation *> reverseRelatedCardsToMe;
|
|
||||||
// card sets
|
|
||||||
CardInfoPerSetMap sets;
|
|
||||||
// cached set names
|
|
||||||
QString setsNames;
|
|
||||||
// positioning properties; used by UI
|
|
||||||
bool cipt;
|
|
||||||
bool landscapeOrientation;
|
|
||||||
int tableRow;
|
|
||||||
bool upsideDownArt;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CardInfo(const QString &_name,
|
|
||||||
const QString &_text,
|
|
||||||
bool _isToken,
|
|
||||||
QVariantHash _properties,
|
|
||||||
const QList<CardRelation *> &_relatedCards,
|
|
||||||
const QList<CardRelation *> &_reverseRelatedCards,
|
|
||||||
CardInfoPerSetMap _sets,
|
|
||||||
bool _cipt,
|
|
||||||
bool _landscapeOrientation,
|
|
||||||
int _tableRow,
|
|
||||||
bool _upsideDownArt);
|
|
||||||
CardInfo(const CardInfo &other)
|
|
||||||
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), pixmapCacheKey(other.pixmapCacheKey),
|
|
||||||
text(other.text), isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
|
|
||||||
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
|
|
||||||
sets(other.sets), setsNames(other.setsNames), cipt(other.cipt),
|
|
||||||
landscapeOrientation(other.landscapeOrientation), tableRow(other.tableRow), upsideDownArt(other.upsideDownArt)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~CardInfo() override;
|
|
||||||
|
|
||||||
static CardInfoPtr newInstance(const QString &_name);
|
|
||||||
|
|
||||||
static CardInfoPtr newInstance(const QString &_name,
|
|
||||||
const QString &_text,
|
|
||||||
bool _isToken,
|
|
||||||
QVariantHash _properties,
|
|
||||||
const QList<CardRelation *> &_relatedCards,
|
|
||||||
const QList<CardRelation *> &_reverseRelatedCards,
|
|
||||||
CardInfoPerSetMap _sets,
|
|
||||||
bool _cipt,
|
|
||||||
bool _landscapeOrientation,
|
|
||||||
int _tableRow,
|
|
||||||
bool _upsideDownArt);
|
|
||||||
|
|
||||||
CardInfoPtr clone() const
|
|
||||||
{
|
|
||||||
// Use the copy constructor to create a new instance
|
|
||||||
CardInfoPtr newCardInfo = CardInfoPtr(new CardInfo(*this));
|
|
||||||
newCardInfo->setSmartPointer(newCardInfo); // Set the smart pointer for the new instance
|
|
||||||
return newCardInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSmartPointer(CardInfoPtr _ptr)
|
|
||||||
{
|
|
||||||
smartThis = std::move(_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// basic properties
|
|
||||||
inline const QString &getName() const
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
const QString &getSimpleName() const
|
|
||||||
{
|
|
||||||
return simpleName;
|
|
||||||
}
|
|
||||||
void setPixmapCacheKey(QString _pixmapCacheKey)
|
|
||||||
{
|
|
||||||
pixmapCacheKey = _pixmapCacheKey;
|
|
||||||
}
|
|
||||||
const QString &getPixmapCacheKey() const
|
|
||||||
{
|
|
||||||
return pixmapCacheKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &getText() const
|
|
||||||
{
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
void setText(const QString &_text)
|
|
||||||
{
|
|
||||||
text = _text;
|
|
||||||
emit cardInfoChanged(smartThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getIsToken() const
|
|
||||||
{
|
|
||||||
return isToken;
|
|
||||||
}
|
|
||||||
const QStringList getProperties() const
|
|
||||||
{
|
|
||||||
return properties.keys();
|
|
||||||
}
|
|
||||||
const QString getProperty(const QString &propertyName) const
|
|
||||||
{
|
|
||||||
return properties.value(propertyName).toString();
|
|
||||||
}
|
|
||||||
void setProperty(const QString &_name, const QString &_value)
|
|
||||||
{
|
|
||||||
properties.insert(_name, _value);
|
|
||||||
emit cardInfoChanged(smartThis);
|
|
||||||
}
|
|
||||||
bool hasProperty(const QString &propertyName) const
|
|
||||||
{
|
|
||||||
return properties.contains(propertyName);
|
|
||||||
}
|
|
||||||
const CardInfoPerSetMap &getSets() const
|
|
||||||
{
|
|
||||||
return sets;
|
|
||||||
}
|
|
||||||
const QString &getSetsNames() const
|
|
||||||
{
|
|
||||||
return setsNames;
|
|
||||||
}
|
|
||||||
const QString getSetProperty(const QString &setName, const QString &propertyName) const
|
|
||||||
{
|
|
||||||
if (!sets.contains(setName))
|
|
||||||
return "";
|
|
||||||
|
|
||||||
for (const auto &set : sets[setName]) {
|
|
||||||
if (QLatin1String("card_") + this->getName() + QString("_") + QString(set.getProperty("uuid")) ==
|
|
||||||
this->getPixmapCacheKey()) {
|
|
||||||
return set.getProperty(propertyName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sets[setName][0].getProperty(propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// related cards
|
|
||||||
const QList<CardRelation *> &getRelatedCards() const
|
|
||||||
{
|
|
||||||
return relatedCards;
|
|
||||||
}
|
|
||||||
const QList<CardRelation *> &getReverseRelatedCards() const
|
|
||||||
{
|
|
||||||
return reverseRelatedCards;
|
|
||||||
}
|
|
||||||
const QList<CardRelation *> &getReverseRelatedCards2Me() const
|
|
||||||
{
|
|
||||||
return reverseRelatedCardsToMe;
|
|
||||||
}
|
|
||||||
const QList<CardRelation *> getAllRelatedCards() const
|
|
||||||
{
|
|
||||||
QList<CardRelation *> result;
|
|
||||||
result.append(getRelatedCards());
|
|
||||||
result.append(getReverseRelatedCards2Me());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
void resetReverseRelatedCards2Me();
|
|
||||||
void addReverseRelatedCards2Me(CardRelation *cardRelation)
|
|
||||||
{
|
|
||||||
reverseRelatedCardsToMe.append(cardRelation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// positioning
|
|
||||||
bool getCipt() const
|
|
||||||
{
|
|
||||||
return cipt;
|
|
||||||
}
|
|
||||||
bool getLandscapeOrientation() const
|
|
||||||
{
|
|
||||||
return landscapeOrientation;
|
|
||||||
}
|
|
||||||
int getTableRow() const
|
|
||||||
{
|
|
||||||
return tableRow;
|
|
||||||
}
|
|
||||||
void setTableRow(int _tableRow)
|
|
||||||
{
|
|
||||||
tableRow = _tableRow;
|
|
||||||
}
|
|
||||||
bool getUpsideDownArt() const
|
|
||||||
{
|
|
||||||
return upsideDownArt;
|
|
||||||
}
|
|
||||||
const QChar getColorChar() const;
|
|
||||||
|
|
||||||
// Back-compatibility methods. Remove ASAP
|
|
||||||
const QString getCardType() const;
|
|
||||||
void setCardType(const QString &value);
|
|
||||||
const QString getCmc() const;
|
|
||||||
const QString getColors() const;
|
|
||||||
void setColors(const QString &value);
|
|
||||||
const QString getLoyalty() const;
|
|
||||||
const QString getMainCardType() const;
|
|
||||||
const QString getManaCost() const;
|
|
||||||
const QString getPowTough() const;
|
|
||||||
void setPowTough(const QString &value);
|
|
||||||
|
|
||||||
// methods using per-set properties
|
|
||||||
QString getCustomPicURL(const QString &set) const
|
|
||||||
{
|
|
||||||
return getSetProperty(set, "picurl");
|
|
||||||
}
|
|
||||||
QString getCorrectedName() const;
|
|
||||||
void addToSet(const CardSetPtr &_set, CardInfoPerSet _info = CardInfoPerSet());
|
|
||||||
void combineLegalities(const QVariantHash &props);
|
|
||||||
void emitPixmapUpdated()
|
|
||||||
{
|
|
||||||
emit pixmapUpdated();
|
|
||||||
}
|
|
||||||
void refreshCachedSetNames();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplify a name to have no punctuation and lowercase all letters, for
|
|
||||||
* less strict name-matching.
|
|
||||||
*/
|
|
||||||
static QString simplifyName(const QString &name);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void pixmapUpdated();
|
|
||||||
void cardInfoChanged(CardInfoPtr card);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LoadStatus
|
enum LoadStatus
|
||||||
{
|
{
|
||||||
Ok,
|
Ok,
|
||||||
|
|
@ -523,79 +123,4 @@ signals:
|
||||||
void cardRemoved(CardInfoPtr card);
|
void cardRemoved(CardInfoPtr card);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CardRelation : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum AttachType
|
|
||||||
{
|
|
||||||
DoesNotAttach = 0,
|
|
||||||
AttachTo = 1,
|
|
||||||
TransformInto = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString name;
|
|
||||||
AttachType attachType;
|
|
||||||
bool isCreateAllExclusion;
|
|
||||||
bool isVariableCount;
|
|
||||||
int defaultCount;
|
|
||||||
bool isPersistent;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CardRelation(const QString &_name = QString(),
|
|
||||||
AttachType _attachType = DoesNotAttach,
|
|
||||||
bool _isCreateAllExclusion = false,
|
|
||||||
bool _isVariableCount = false,
|
|
||||||
int _defaultCount = 1,
|
|
||||||
bool _isPersistent = false);
|
|
||||||
|
|
||||||
inline const QString &getName() const
|
|
||||||
{
|
|
||||||
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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool getCanCreateAnother() const
|
|
||||||
{
|
|
||||||
return !getDoesAttach();
|
|
||||||
}
|
|
||||||
bool getIsCreateAllExclusion() const
|
|
||||||
{
|
|
||||||
return isCreateAllExclusion;
|
|
||||||
}
|
|
||||||
bool getIsVariable() const
|
|
||||||
{
|
|
||||||
return isVariableCount;
|
|
||||||
}
|
|
||||||
int getDefaultCount() const
|
|
||||||
{
|
|
||||||
return defaultCount;
|
|
||||||
}
|
|
||||||
bool getIsPersistent() const
|
|
||||||
{
|
|
||||||
return isPersistent;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "cockatrice_xml_4.h"
|
#include "cockatrice_xml_4.h"
|
||||||
|
|
||||||
|
#include "../../../settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
@ -124,6 +126,7 @@ QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &x
|
||||||
|
|
||||||
void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
{
|
{
|
||||||
|
bool includeOnlineOnlyCards = SettingsCache::instance().getIncludeOnlineOnlyCards();
|
||||||
while (!xml.atEnd()) {
|
while (!xml.atEnd()) {
|
||||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -183,8 +186,18 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
attrName = "picurl";
|
attrName = "picurl";
|
||||||
setInfo.setProperty(attrName, attr.value().toString());
|
setInfo.setProperty(attrName, attr.value().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is very much a hack and not the right place to
|
||||||
|
// put this check, as it requires a reload of Cockatrice
|
||||||
|
// to be apply.
|
||||||
|
//
|
||||||
|
// However, this is also true of the `set->getEnabled()`
|
||||||
|
// check above (which is currently bugged as well), so
|
||||||
|
// we'll fix both at the same time.
|
||||||
|
if (includeOnlineOnlyCards || setInfo.getProperty("isOnlineOnly") != "true") {
|
||||||
_sets[setName].append(setInfo);
|
_sets[setName].append(setInfo);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// related cards
|
// related cards
|
||||||
} else if (xmlName == "related" || xmlName == "reverse-related") {
|
} else if (xmlName == "related" || xmlName == "reverse-related") {
|
||||||
CardRelation::AttachType attachType = CardRelation::DoesNotAttach;
|
CardRelation::AttachType attachType = CardRelation::DoesNotAttach;
|
||||||
|
|
|
||||||
418
cockatrice/src/game/cards/card_info.cpp
Normal file
418
cockatrice/src/game/cards/card_info.cpp
Normal file
|
|
@ -0,0 +1,418 @@
|
||||||
|
#include "card_info.h"
|
||||||
|
|
||||||
|
#include "../../client/ui/picture_loader/picture_loader.h"
|
||||||
|
#include "../../settings/cache_settings.h"
|
||||||
|
#include "../game_specific_terms.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
CardSet::CardSet(const QString &_shortName,
|
||||||
|
const QString &_longName,
|
||||||
|
const QString &_setType,
|
||||||
|
const QDate &_releaseDate,
|
||||||
|
const CardSet::Priority _priority)
|
||||||
|
: shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType), priority(_priority)
|
||||||
|
{
|
||||||
|
loadSetOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
CardSetPtr CardSet::newInstance(const QString &_shortName,
|
||||||
|
const QString &_longName,
|
||||||
|
const QString &_setType,
|
||||||
|
const QDate &_releaseDate,
|
||||||
|
const Priority _priority)
|
||||||
|
{
|
||||||
|
CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate, _priority));
|
||||||
|
// ptr->setSmartPointer(ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CardSet::getCorrectedShortName() const
|
||||||
|
{
|
||||||
|
// For Windows machines.
|
||||||
|
QSet<QString> invalidFileNames;
|
||||||
|
invalidFileNames << "CON"
|
||||||
|
<< "PRN"
|
||||||
|
<< "AUX"
|
||||||
|
<< "NUL"
|
||||||
|
<< "COM1"
|
||||||
|
<< "COM2"
|
||||||
|
<< "COM3"
|
||||||
|
<< "COM4"
|
||||||
|
<< "COM5"
|
||||||
|
<< "COM6"
|
||||||
|
<< "COM7"
|
||||||
|
<< "COM8"
|
||||||
|
<< "COM9"
|
||||||
|
<< "LPT1"
|
||||||
|
<< "LPT2"
|
||||||
|
<< "LPT3"
|
||||||
|
<< "LPT4"
|
||||||
|
<< "LPT5"
|
||||||
|
<< "LPT6"
|
||||||
|
<< "LPT7"
|
||||||
|
<< "LPT8"
|
||||||
|
<< "LPT9";
|
||||||
|
|
||||||
|
return invalidFileNames.contains(shortName) ? shortName + "_" : shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardSet::loadSetOptions()
|
||||||
|
{
|
||||||
|
sortKey = SettingsCache::instance().cardDatabase().getSortKey(shortName);
|
||||||
|
enabled = SettingsCache::instance().cardDatabase().isEnabled(shortName);
|
||||||
|
isknown = SettingsCache::instance().cardDatabase().isKnown(shortName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardSet::setSortKey(unsigned int _sortKey)
|
||||||
|
{
|
||||||
|
sortKey = _sortKey;
|
||||||
|
SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardSet::setEnabled(bool _enabled)
|
||||||
|
{
|
||||||
|
enabled = _enabled;
|
||||||
|
SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardSet::setIsKnown(bool _isknown)
|
||||||
|
{
|
||||||
|
isknown = _isknown;
|
||||||
|
SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SetList::KeyCompareFunctor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
|
||||||
|
{
|
||||||
|
if (a.isNull() || b.isNull()) {
|
||||||
|
qCDebug(CardInfoLog) << "SetList::KeyCompareFunctor a or b is null";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a->getSortKey() < b->getSortKey();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetList::sortByKey()
|
||||||
|
{
|
||||||
|
std::sort(begin(), end(), KeyCompareFunctor());
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetList::getEnabledSetsNum()
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
if (set && set->getEnabled()) {
|
||||||
|
++num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetList::getUnknownSetsNum()
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
||||||
|
++num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList SetList::getUnknownSetsNames()
|
||||||
|
{
|
||||||
|
QStringList sets = QStringList();
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
||||||
|
sets << set->getShortName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetList::enableAllUnknown()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
||||||
|
set->setIsKnown(true);
|
||||||
|
set->setEnabled(true);
|
||||||
|
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
|
||||||
|
set->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetList::enableAll()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
|
||||||
|
if (set == nullptr) {
|
||||||
|
qCDebug(CardInfoLog) << "enabledAll has null";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set->getIsKnownIgnored()) {
|
||||||
|
set->setIsKnown(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
set->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetList::markAllAsKnown()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
|
||||||
|
set->setIsKnown(true);
|
||||||
|
set->setEnabled(false);
|
||||||
|
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
|
||||||
|
set->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetList::guessSortKeys()
|
||||||
|
{
|
||||||
|
defaultSort();
|
||||||
|
for (int i = 0; i < size(); ++i) {
|
||||||
|
CardSetPtr set = at(i);
|
||||||
|
if (set.isNull()) {
|
||||||
|
qCDebug(CardInfoLog) << "guessSortKeys set is null";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
set->setSortKey(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetList::defaultSort()
|
||||||
|
{
|
||||||
|
std::sort(begin(), end(), [](const CardSetPtr &a, const CardSetPtr &b) {
|
||||||
|
// Sort by priority, then by release date, then by short name
|
||||||
|
if (a->getPriority() != b->getPriority()) {
|
||||||
|
return a->getPriority() < b->getPriority(); // lowest first
|
||||||
|
} else if (a->getReleaseDate() != b->getReleaseDate()) {
|
||||||
|
return a->getReleaseDate() > b->getReleaseDate(); // most recent first
|
||||||
|
} else {
|
||||||
|
return a->getShortName() < b->getShortName(); // alphabetically
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CardInfo::CardInfo(const QString &_name,
|
||||||
|
const QString &_text,
|
||||||
|
bool _isToken,
|
||||||
|
QVariantHash _properties,
|
||||||
|
const QList<CardRelation *> &_relatedCards,
|
||||||
|
const QList<CardRelation *> &_reverseRelatedCards,
|
||||||
|
CardInfoPerSetMap _sets,
|
||||||
|
bool _cipt,
|
||||||
|
bool _landscapeOrientation,
|
||||||
|
int _tableRow,
|
||||||
|
bool _upsideDownArt)
|
||||||
|
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
|
||||||
|
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt),
|
||||||
|
landscapeOrientation(_landscapeOrientation), tableRow(_tableRow), upsideDownArt(_upsideDownArt)
|
||||||
|
{
|
||||||
|
pixmapCacheKey = QLatin1String("card_") + name;
|
||||||
|
simpleName = CardInfo::simplifyName(name);
|
||||||
|
|
||||||
|
refreshCachedSetNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
CardInfo::~CardInfo()
|
||||||
|
{
|
||||||
|
PictureLoader::clearPixmapCache(smartThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
CardInfoPtr CardInfo::newInstance(const QString &_name)
|
||||||
|
{
|
||||||
|
return newInstance(_name, QString(), false, QVariantHash(), QList<CardRelation *>(), QList<CardRelation *>(),
|
||||||
|
CardInfoPerSetMap(), false, false, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CardInfoPtr CardInfo::newInstance(const QString &_name,
|
||||||
|
const QString &_text,
|
||||||
|
bool _isToken,
|
||||||
|
QVariantHash _properties,
|
||||||
|
const QList<CardRelation *> &_relatedCards,
|
||||||
|
const QList<CardRelation *> &_reverseRelatedCards,
|
||||||
|
CardInfoPerSetMap _sets,
|
||||||
|
bool _cipt,
|
||||||
|
bool _landscapeOrientation,
|
||||||
|
int _tableRow,
|
||||||
|
bool _upsideDownArt)
|
||||||
|
{
|
||||||
|
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
|
||||||
|
_sets, _cipt, _landscapeOrientation, _tableRow, _upsideDownArt));
|
||||||
|
ptr->setSmartPointer(ptr);
|
||||||
|
|
||||||
|
for (const auto &cardInfoPerSetList : _sets) {
|
||||||
|
for (const CardInfoPerSet &set : cardInfoPerSetList) {
|
||||||
|
set.getPtr()->append(ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
|
||||||
|
{
|
||||||
|
_set->append(smartThis);
|
||||||
|
sets[_set->getShortName()].append(_info);
|
||||||
|
|
||||||
|
refreshCachedSetNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardInfo::combineLegalities(const QVariantHash &props)
|
||||||
|
{
|
||||||
|
QHashIterator<QString, QVariant> it(props);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
if (it.key().startsWith("format-")) {
|
||||||
|
smartThis->setProperty(it.key(), it.value().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardInfo::refreshCachedSetNames()
|
||||||
|
{
|
||||||
|
QStringList setList;
|
||||||
|
// update the cached list of set names
|
||||||
|
for (const auto &cardInfoPerSetList : sets) {
|
||||||
|
for (const auto &set : cardInfoPerSetList) {
|
||||||
|
if (set.getPtr()->getEnabled()) {
|
||||||
|
setList << set.getPtr()->getShortName();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setsNames = setList.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CardInfo::simplifyName(const QString &name)
|
||||||
|
{
|
||||||
|
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
|
||||||
|
static const QRegularExpression nonAlnum("[^a-z0-9]");
|
||||||
|
|
||||||
|
QString simpleName = name.toLower();
|
||||||
|
|
||||||
|
// remove spaces and right halves of split cards
|
||||||
|
simpleName.remove(spaceOrSplit);
|
||||||
|
|
||||||
|
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
|
||||||
|
// with nothing.
|
||||||
|
simpleName.replace("æ", "ae");
|
||||||
|
|
||||||
|
// Replace Jötun Grunt with Jotun Grunt.
|
||||||
|
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
|
||||||
|
|
||||||
|
// remove all non alphanumeric characters from the name
|
||||||
|
simpleName.remove(nonAlnum);
|
||||||
|
return simpleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QChar CardInfo::getColorChar() const
|
||||||
|
{
|
||||||
|
QString colors = getColors();
|
||||||
|
switch (colors.size()) {
|
||||||
|
case 0:
|
||||||
|
return QChar();
|
||||||
|
case 1:
|
||||||
|
return colors.at(0);
|
||||||
|
default:
|
||||||
|
return QChar('m');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CardRelation::CardRelation(const QString &_name,
|
||||||
|
AttachType _attachType,
|
||||||
|
bool _isCreateAllExclusion,
|
||||||
|
bool _isVariableCount,
|
||||||
|
int _defaultCount,
|
||||||
|
bool _isPersistent)
|
||||||
|
: name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion),
|
||||||
|
isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardInfo::resetReverseRelatedCards2Me()
|
||||||
|
{
|
||||||
|
for (CardRelation *cardRelation : this->getReverseRelatedCards2Me()) {
|
||||||
|
cardRelation->deleteLater();
|
||||||
|
}
|
||||||
|
reverseRelatedCardsToMe = QList<CardRelation *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back-compatibility methods. Remove ASAP
|
||||||
|
const QString CardInfo::getCardType() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::CardType);
|
||||||
|
}
|
||||||
|
void CardInfo::setCardType(const QString &value)
|
||||||
|
{
|
||||||
|
setProperty(Mtg::CardType, value);
|
||||||
|
}
|
||||||
|
const QString CardInfo::getCmc() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::ConvertedManaCost);
|
||||||
|
}
|
||||||
|
const QString CardInfo::getColors() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::Colors);
|
||||||
|
}
|
||||||
|
void CardInfo::setColors(const QString &value)
|
||||||
|
{
|
||||||
|
setProperty(Mtg::Colors, value);
|
||||||
|
}
|
||||||
|
const QString CardInfo::getLoyalty() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::Loyalty);
|
||||||
|
}
|
||||||
|
const QString CardInfo::getMainCardType() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::MainCardType);
|
||||||
|
}
|
||||||
|
const QString CardInfo::getManaCost() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::ManaCost);
|
||||||
|
}
|
||||||
|
const QString CardInfo::getPowTough() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::PowTough);
|
||||||
|
}
|
||||||
|
void CardInfo::setPowTough(const QString &value)
|
||||||
|
{
|
||||||
|
setProperty(Mtg::PowTough, value);
|
||||||
|
}
|
||||||
491
cockatrice/src/game/cards/card_info.h
Normal file
491
cockatrice/src/game/cards/card_info.h
Normal file
|
|
@ -0,0 +1,491 @@
|
||||||
|
#ifndef CARD_INFO_H
|
||||||
|
#define CARD_INFO_H
|
||||||
|
|
||||||
|
#include <QDate>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QList>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
inline Q_LOGGING_CATEGORY(CardInfoLog, "card_info");
|
||||||
|
|
||||||
|
class CardInfo;
|
||||||
|
class CardInfoPerSet;
|
||||||
|
class CardSet;
|
||||||
|
class CardRelation;
|
||||||
|
class ICardDatabaseParser;
|
||||||
|
|
||||||
|
typedef QMap<QString, QString> QStringMap;
|
||||||
|
typedef QSharedPointer<CardInfo> CardInfoPtr;
|
||||||
|
typedef QSharedPointer<CardSet> CardSetPtr;
|
||||||
|
typedef QMap<QString, QList<CardInfoPerSet>> CardInfoPerSetMap;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(CardInfoPtr)
|
||||||
|
|
||||||
|
class CardSet : public QList<CardInfoPtr>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Priority
|
||||||
|
{
|
||||||
|
PriorityFallback = 0,
|
||||||
|
PriorityPrimary = 10,
|
||||||
|
PrioritySecondary = 20,
|
||||||
|
PriorityReprint = 30,
|
||||||
|
PriorityOther = 40,
|
||||||
|
PriorityLowest = 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString shortName, longName;
|
||||||
|
unsigned int sortKey;
|
||||||
|
QDate releaseDate;
|
||||||
|
QString setType;
|
||||||
|
Priority priority;
|
||||||
|
bool enabled, isknown;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CardSet(const QString &_shortName = QString(),
|
||||||
|
const QString &_longName = QString(),
|
||||||
|
const QString &_setType = QString(),
|
||||||
|
const QDate &_releaseDate = QDate(),
|
||||||
|
const Priority _priority = PriorityFallback);
|
||||||
|
static CardSetPtr newInstance(const QString &_shortName = QString(),
|
||||||
|
const QString &_longName = QString(),
|
||||||
|
const QString &_setType = QString(),
|
||||||
|
const QDate &_releaseDate = QDate(),
|
||||||
|
const Priority _priority = PriorityFallback);
|
||||||
|
QString getCorrectedShortName() const;
|
||||||
|
QString getShortName() const
|
||||||
|
{
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
QString getLongName() const
|
||||||
|
{
|
||||||
|
return longName;
|
||||||
|
}
|
||||||
|
QString getSetType() const
|
||||||
|
{
|
||||||
|
return setType;
|
||||||
|
}
|
||||||
|
QDate getReleaseDate() const
|
||||||
|
{
|
||||||
|
return releaseDate;
|
||||||
|
}
|
||||||
|
Priority getPriority() const
|
||||||
|
{
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
void setLongName(const QString &_longName)
|
||||||
|
{
|
||||||
|
longName = _longName;
|
||||||
|
}
|
||||||
|
void setSetType(const QString &_setType)
|
||||||
|
{
|
||||||
|
setType = _setType;
|
||||||
|
}
|
||||||
|
void setReleaseDate(const QDate &_releaseDate)
|
||||||
|
{
|
||||||
|
releaseDate = _releaseDate;
|
||||||
|
}
|
||||||
|
void setPriority(const Priority _priority)
|
||||||
|
{
|
||||||
|
priority = _priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadSetOptions();
|
||||||
|
int getSortKey() const
|
||||||
|
{
|
||||||
|
return sortKey;
|
||||||
|
}
|
||||||
|
void setSortKey(unsigned int _sortKey);
|
||||||
|
bool getEnabled() const
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
void setEnabled(bool _enabled);
|
||||||
|
bool getIsKnown() const
|
||||||
|
{
|
||||||
|
return isknown;
|
||||||
|
}
|
||||||
|
void setIsKnown(bool _isknown);
|
||||||
|
|
||||||
|
// Determine incomplete sets.
|
||||||
|
bool getIsKnownIgnored() const
|
||||||
|
{
|
||||||
|
return longName.length() + setType.length() + releaseDate.toString().length() == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetList : public QList<CardSetPtr>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
class KeyCompareFunctor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void sortByKey();
|
||||||
|
void guessSortKeys();
|
||||||
|
void enableAllUnknown();
|
||||||
|
void enableAll();
|
||||||
|
void markAllAsKnown();
|
||||||
|
int getEnabledSetsNum();
|
||||||
|
int getUnknownSetsNum();
|
||||||
|
QStringList getUnknownSetsNames();
|
||||||
|
void defaultSort();
|
||||||
|
};
|
||||||
|
|
||||||
|
class CardInfoPerSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CardInfoPerSet(const CardSetPtr &_set = QSharedPointer<CardSet>(nullptr));
|
||||||
|
~CardInfoPerSet() = default;
|
||||||
|
|
||||||
|
bool operator==(const CardInfoPerSet &other) const
|
||||||
|
{
|
||||||
|
return this->set == other.set && this->properties == other.properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CardSetPtr set;
|
||||||
|
// per-set card properties;
|
||||||
|
QVariantHash properties;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const CardSetPtr getPtr() const
|
||||||
|
{
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
const QStringList getProperties() const
|
||||||
|
{
|
||||||
|
return properties.keys();
|
||||||
|
}
|
||||||
|
const QString getProperty(const QString &propertyName) const
|
||||||
|
{
|
||||||
|
return properties.value(propertyName).toString();
|
||||||
|
}
|
||||||
|
void setProperty(const QString &_name, const QString &_value)
|
||||||
|
{
|
||||||
|
properties.insert(_name, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CardInfo : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
CardInfoPtr smartThis;
|
||||||
|
// The card name
|
||||||
|
QString name;
|
||||||
|
// The name without punctuation or capitalization, for better card name recognition.
|
||||||
|
QString simpleName;
|
||||||
|
// The key used to identify this card in the cache
|
||||||
|
QString pixmapCacheKey;
|
||||||
|
// card text
|
||||||
|
QString text;
|
||||||
|
// whether this is not a "real" card but a token
|
||||||
|
bool isToken;
|
||||||
|
// basic card properties; common for all the sets
|
||||||
|
QVariantHash properties;
|
||||||
|
// the cards i'm related to
|
||||||
|
QList<CardRelation *> relatedCards;
|
||||||
|
// the card i'm reverse-related to
|
||||||
|
QList<CardRelation *> reverseRelatedCards;
|
||||||
|
// the cards thare are reverse-related to me
|
||||||
|
QList<CardRelation *> reverseRelatedCardsToMe;
|
||||||
|
// card sets
|
||||||
|
CardInfoPerSetMap sets;
|
||||||
|
// cached set names
|
||||||
|
QString setsNames;
|
||||||
|
// positioning properties; used by UI
|
||||||
|
bool cipt;
|
||||||
|
bool landscapeOrientation;
|
||||||
|
int tableRow;
|
||||||
|
bool upsideDownArt;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CardInfo(const QString &_name,
|
||||||
|
const QString &_text,
|
||||||
|
bool _isToken,
|
||||||
|
QVariantHash _properties,
|
||||||
|
const QList<CardRelation *> &_relatedCards,
|
||||||
|
const QList<CardRelation *> &_reverseRelatedCards,
|
||||||
|
CardInfoPerSetMap _sets,
|
||||||
|
bool _cipt,
|
||||||
|
bool _landscapeOrientation,
|
||||||
|
int _tableRow,
|
||||||
|
bool _upsideDownArt);
|
||||||
|
CardInfo(const CardInfo &other)
|
||||||
|
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), pixmapCacheKey(other.pixmapCacheKey),
|
||||||
|
text(other.text), isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
|
||||||
|
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
|
||||||
|
sets(other.sets), setsNames(other.setsNames), cipt(other.cipt),
|
||||||
|
landscapeOrientation(other.landscapeOrientation), tableRow(other.tableRow), upsideDownArt(other.upsideDownArt)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~CardInfo() override;
|
||||||
|
|
||||||
|
static CardInfoPtr newInstance(const QString &_name);
|
||||||
|
|
||||||
|
static CardInfoPtr newInstance(const QString &_name,
|
||||||
|
const QString &_text,
|
||||||
|
bool _isToken,
|
||||||
|
QVariantHash _properties,
|
||||||
|
const QList<CardRelation *> &_relatedCards,
|
||||||
|
const QList<CardRelation *> &_reverseRelatedCards,
|
||||||
|
CardInfoPerSetMap _sets,
|
||||||
|
bool _cipt,
|
||||||
|
bool _landscapeOrientation,
|
||||||
|
int _tableRow,
|
||||||
|
bool _upsideDownArt);
|
||||||
|
|
||||||
|
CardInfoPtr clone() const
|
||||||
|
{
|
||||||
|
// Use the copy constructor to create a new instance
|
||||||
|
CardInfoPtr newCardInfo = CardInfoPtr(new CardInfo(*this));
|
||||||
|
newCardInfo->setSmartPointer(newCardInfo); // Set the smart pointer for the new instance
|
||||||
|
return newCardInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSmartPointer(CardInfoPtr _ptr)
|
||||||
|
{
|
||||||
|
smartThis = std::move(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// basic properties
|
||||||
|
inline const QString &getName() const
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
const QString &getSimpleName() const
|
||||||
|
{
|
||||||
|
return simpleName;
|
||||||
|
}
|
||||||
|
void setPixmapCacheKey(QString _pixmapCacheKey)
|
||||||
|
{
|
||||||
|
pixmapCacheKey = _pixmapCacheKey;
|
||||||
|
}
|
||||||
|
const QString &getPixmapCacheKey() const
|
||||||
|
{
|
||||||
|
return pixmapCacheKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &getText() const
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
void setText(const QString &_text)
|
||||||
|
{
|
||||||
|
text = _text;
|
||||||
|
emit cardInfoChanged(smartThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getIsToken() const
|
||||||
|
{
|
||||||
|
return isToken;
|
||||||
|
}
|
||||||
|
const QStringList getProperties() const
|
||||||
|
{
|
||||||
|
return properties.keys();
|
||||||
|
}
|
||||||
|
const QString getProperty(const QString &propertyName) const
|
||||||
|
{
|
||||||
|
return properties.value(propertyName).toString();
|
||||||
|
}
|
||||||
|
void setProperty(const QString &_name, const QString &_value)
|
||||||
|
{
|
||||||
|
properties.insert(_name, _value);
|
||||||
|
emit cardInfoChanged(smartThis);
|
||||||
|
}
|
||||||
|
bool hasProperty(const QString &propertyName) const
|
||||||
|
{
|
||||||
|
return properties.contains(propertyName);
|
||||||
|
}
|
||||||
|
const CardInfoPerSetMap &getSets() const
|
||||||
|
{
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
const QString &getSetsNames() const
|
||||||
|
{
|
||||||
|
return setsNames;
|
||||||
|
}
|
||||||
|
const QString getSetProperty(const QString &setName, const QString &propertyName) const
|
||||||
|
{
|
||||||
|
if (!sets.contains(setName))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
for (const auto &set : sets[setName]) {
|
||||||
|
if (QLatin1String("card_") + this->getName() + QString("_") + QString(set.getProperty("uuid")) ==
|
||||||
|
this->getPixmapCacheKey()) {
|
||||||
|
return set.getProperty(propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sets[setName][0].getProperty(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// related cards
|
||||||
|
const QList<CardRelation *> &getRelatedCards() const
|
||||||
|
{
|
||||||
|
return relatedCards;
|
||||||
|
}
|
||||||
|
const QList<CardRelation *> &getReverseRelatedCards() const
|
||||||
|
{
|
||||||
|
return reverseRelatedCards;
|
||||||
|
}
|
||||||
|
const QList<CardRelation *> &getReverseRelatedCards2Me() const
|
||||||
|
{
|
||||||
|
return reverseRelatedCardsToMe;
|
||||||
|
}
|
||||||
|
const QList<CardRelation *> getAllRelatedCards() const
|
||||||
|
{
|
||||||
|
QList<CardRelation *> result;
|
||||||
|
result.append(getRelatedCards());
|
||||||
|
result.append(getReverseRelatedCards2Me());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void resetReverseRelatedCards2Me();
|
||||||
|
void addReverseRelatedCards2Me(CardRelation *cardRelation)
|
||||||
|
{
|
||||||
|
reverseRelatedCardsToMe.append(cardRelation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// positioning
|
||||||
|
bool getCipt() const
|
||||||
|
{
|
||||||
|
return cipt;
|
||||||
|
}
|
||||||
|
bool getLandscapeOrientation() const
|
||||||
|
{
|
||||||
|
return landscapeOrientation;
|
||||||
|
}
|
||||||
|
int getTableRow() const
|
||||||
|
{
|
||||||
|
return tableRow;
|
||||||
|
}
|
||||||
|
void setTableRow(int _tableRow)
|
||||||
|
{
|
||||||
|
tableRow = _tableRow;
|
||||||
|
}
|
||||||
|
bool getUpsideDownArt() const
|
||||||
|
{
|
||||||
|
return upsideDownArt;
|
||||||
|
}
|
||||||
|
const QChar getColorChar() const;
|
||||||
|
|
||||||
|
// Back-compatibility methods. Remove ASAP
|
||||||
|
const QString getCardType() const;
|
||||||
|
void setCardType(const QString &value);
|
||||||
|
const QString getCmc() const;
|
||||||
|
const QString getColors() const;
|
||||||
|
void setColors(const QString &value);
|
||||||
|
const QString getLoyalty() const;
|
||||||
|
const QString getMainCardType() const;
|
||||||
|
const QString getManaCost() const;
|
||||||
|
const QString getPowTough() const;
|
||||||
|
void setPowTough(const QString &value);
|
||||||
|
|
||||||
|
// methods using per-set properties
|
||||||
|
QString getCustomPicURL(const QString &set) const
|
||||||
|
{
|
||||||
|
return getSetProperty(set, "picurl");
|
||||||
|
}
|
||||||
|
QString getCorrectedName() const;
|
||||||
|
void addToSet(const CardSetPtr &_set, CardInfoPerSet _info = CardInfoPerSet());
|
||||||
|
void combineLegalities(const QVariantHash &props);
|
||||||
|
void emitPixmapUpdated()
|
||||||
|
{
|
||||||
|
emit pixmapUpdated();
|
||||||
|
}
|
||||||
|
void refreshCachedSetNames();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplify a name to have no punctuation and lowercase all letters, for
|
||||||
|
* less strict name-matching.
|
||||||
|
*/
|
||||||
|
static QString simplifyName(const QString &name);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void pixmapUpdated();
|
||||||
|
void cardInfoChanged(CardInfoPtr card);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CardRelation : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum AttachType
|
||||||
|
{
|
||||||
|
DoesNotAttach = 0,
|
||||||
|
AttachTo = 1,
|
||||||
|
TransformInto = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString name;
|
||||||
|
AttachType attachType;
|
||||||
|
bool isCreateAllExclusion;
|
||||||
|
bool isVariableCount;
|
||||||
|
int defaultCount;
|
||||||
|
bool isPersistent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CardRelation(const QString &_name = QString(),
|
||||||
|
AttachType _attachType = DoesNotAttach,
|
||||||
|
bool _isCreateAllExclusion = false,
|
||||||
|
bool _isVariableCount = false,
|
||||||
|
int _defaultCount = 1,
|
||||||
|
bool _isPersistent = false);
|
||||||
|
|
||||||
|
inline const QString &getName() const
|
||||||
|
{
|
||||||
|
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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool getCanCreateAnother() const
|
||||||
|
{
|
||||||
|
return !getDoesAttach();
|
||||||
|
}
|
||||||
|
bool getIsCreateAllExclusion() const
|
||||||
|
{
|
||||||
|
return isCreateAllExclusion;
|
||||||
|
}
|
||||||
|
bool getIsVariable() const
|
||||||
|
{
|
||||||
|
return isVariableCount;
|
||||||
|
}
|
||||||
|
int getDefaultCount() const
|
||||||
|
{
|
||||||
|
return defaultCount;
|
||||||
|
}
|
||||||
|
bool getIsPersistent() const
|
||||||
|
{
|
||||||
|
return isPersistent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
@ -22,10 +22,9 @@ CardItem::CardItem(Player *_owner,
|
||||||
const QString &_name,
|
const QString &_name,
|
||||||
const QString &_providerId,
|
const QString &_providerId,
|
||||||
int _cardid,
|
int _cardid,
|
||||||
bool _revealedCard,
|
|
||||||
CardZone *_zone)
|
CardZone *_zone)
|
||||||
: AbstractCardItem(parent, _name, _providerId, _owner, _cardid), zone(_zone), revealedCard(_revealedCard),
|
: AbstractCardItem(parent, _name, _providerId, _owner, _cardid), zone(_zone), attacking(false),
|
||||||
attacking(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
|
destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
|
||||||
{
|
{
|
||||||
owner->addCard(this);
|
owner->addCard(this);
|
||||||
|
|
||||||
|
|
@ -483,11 +482,9 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||||
owner->setCardMenu(cardMenu);
|
owner->setCardMenu(cardMenu);
|
||||||
owner->getGame()->setActiveCard(this);
|
owner->getGame()->setActiveCard(this);
|
||||||
} else if (owner->getCardMenu() == cardMenu) {
|
} else if (owner->getCardMenu() == cardMenu) {
|
||||||
if (scene() && scene()->selectedItems().isEmpty()) {
|
|
||||||
owner->setCardMenu(nullptr);
|
owner->setCardMenu(nullptr);
|
||||||
}
|
|
||||||
owner->getGame()->setActiveCard(nullptr);
|
owner->getGame()->setActiveCard(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QGraphicsItem::itemChange(change, value);
|
return AbstractCardItem::itemChange(change, value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ class CardItem : public AbstractCardItem
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
CardZone *zone;
|
CardZone *zone;
|
||||||
bool revealedCard;
|
|
||||||
bool attacking;
|
bool attacking;
|
||||||
QMap<int, int> counters;
|
QMap<int, int> counters;
|
||||||
QString annotation;
|
QString annotation;
|
||||||
|
|
@ -55,7 +54,6 @@ public:
|
||||||
const QString &_name = QString(),
|
const QString &_name = QString(),
|
||||||
const QString &_providerId = QString(),
|
const QString &_providerId = QString(),
|
||||||
int _cardid = -1,
|
int _cardid = -1,
|
||||||
bool revealedCard = false,
|
|
||||||
CardZone *_zone = nullptr);
|
CardZone *_zone = nullptr);
|
||||||
~CardItem() override;
|
~CardItem() override;
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
@ -85,10 +83,6 @@ public:
|
||||||
{
|
{
|
||||||
owner = _owner;
|
owner = _owner;
|
||||||
}
|
}
|
||||||
bool getRevealedCard() const
|
|
||||||
{
|
|
||||||
return revealedCard;
|
|
||||||
}
|
|
||||||
bool getAttacking() const
|
bool getAttacking() const
|
||||||
{
|
{
|
||||||
return attacking;
|
return attacking;
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,12 @@ DeckViewCard::DeckViewCard(QGraphicsItem *parent,
|
||||||
: AbstractCardItem(parent, _name, _providerId, 0, -1), originZone(_originZone), dragItem(0)
|
: AbstractCardItem(parent, _name, _providerId, 0, -1), originZone(_originZone), dragItem(0)
|
||||||
{
|
{
|
||||||
setAcceptHoverEvents(true);
|
setAcceptHoverEvents(true);
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
||||||
|
update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckViewCard::~DeckViewCard()
|
DeckViewCard::~DeckViewCard()
|
||||||
|
|
@ -91,7 +97,7 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||||
pen.setJoinStyle(Qt::MiterJoin);
|
pen.setJoinStyle(Qt::MiterJoin);
|
||||||
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
||||||
painter->setPen(pen);
|
painter->setPen(pen);
|
||||||
qreal cardRadius = 0.05 * (CARD_WIDTH - 3);
|
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CARD_WIDTH - 3) : 0.0;
|
||||||
painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius);
|
painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +184,7 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI
|
||||||
{
|
{
|
||||||
qreal totalTextWidth = getCardTypeTextWidth();
|
qreal totalTextWidth = getCardTypeTextWidth();
|
||||||
|
|
||||||
painter->fillRect(boundingRect(), themeManager->getTableBgBrush());
|
painter->fillRect(boundingRect(), themeManager->getBgBrush(ThemeManager::Table));
|
||||||
painter->setPen(QColor(255, 255, 255, 100));
|
painter->setPen(QColor(255, 255, 255, 100));
|
||||||
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
|
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,12 +93,7 @@ void PlayerArea::updateBg()
|
||||||
|
|
||||||
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
QBrush brush = themeManager->getPlayerBgBrush();
|
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Player, playerZoneId);
|
||||||
|
|
||||||
if (playerZoneId > 0) {
|
|
||||||
// If the extra image is not found, load the default one
|
|
||||||
brush = themeManager->getExtraPlayerBgBrush(QString::number(playerZoneId), brush);
|
|
||||||
}
|
|
||||||
painter->fillRect(boundingRect(), brush);
|
painter->fillRect(boundingRect(), brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1448,19 +1443,20 @@ void Player::actMoveTopCardsUntil()
|
||||||
{
|
{
|
||||||
stopMoveTopCardsUntil();
|
stopMoveTopCardsUntil();
|
||||||
|
|
||||||
DlgMoveTopCardsUntil dlg(game, movingCardsUntilExpr, movingCardsUntilNumberOfHits, movingCardsUntilAutoPlay);
|
DlgMoveTopCardsUntil dlg(game, movingCardsUntilExprs, movingCardsUntilNumberOfHits, movingCardsUntilAutoPlay);
|
||||||
if (!dlg.exec()) {
|
if (!dlg.exec()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
movingCardsUntilExpr = dlg.getExpr();
|
auto expr = dlg.getExpr();
|
||||||
|
movingCardsUntilExprs = dlg.getExprs();
|
||||||
movingCardsUntilNumberOfHits = dlg.getNumberOfHits();
|
movingCardsUntilNumberOfHits = dlg.getNumberOfHits();
|
||||||
movingCardsUntilAutoPlay = dlg.isAutoPlay();
|
movingCardsUntilAutoPlay = dlg.isAutoPlay();
|
||||||
|
|
||||||
if (zones.value("deck")->getCards().empty()) {
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
stopMoveTopCardsUntil();
|
stopMoveTopCardsUntil();
|
||||||
} else {
|
} else {
|
||||||
movingCardsUntilFilter = FilterString(movingCardsUntilExpr);
|
movingCardsUntilFilter = FilterString(expr);
|
||||||
movingCardsUntilCounter = movingCardsUntilNumberOfHits;
|
movingCardsUntilCounter = movingCardsUntilNumberOfHits;
|
||||||
movingCardsUntil = true;
|
movingCardsUntil = true;
|
||||||
actMoveTopCardToPlay();
|
actMoveTopCardToPlay();
|
||||||
|
|
@ -2069,7 +2065,6 @@ void Player::createCard(const CardItem *sourceCard,
|
||||||
cmd.set_target_zone("table"); // We currently only support creating tokens on the table
|
cmd.set_target_zone("table"); // We currently only support creating tokens on the table
|
||||||
cmd.set_target_card_id(sourceCard->getId());
|
cmd.set_target_card_id(sourceCard->getId());
|
||||||
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
||||||
cmd.set_card_provider_id(sourceCard->getProviderId().toStdString());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CardRelation::TransformInto:
|
case CardRelation::TransformInto:
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ private:
|
||||||
|
|
||||||
bool movingCardsUntil;
|
bool movingCardsUntil;
|
||||||
QTimer *moveTopCardTimer;
|
QTimer *moveTopCardTimer;
|
||||||
QString movingCardsUntilExpr = {};
|
QStringList movingCardsUntilExprs = {};
|
||||||
int movingCardsUntilNumberOfHits = 1;
|
int movingCardsUntilNumberOfHits = 1;
|
||||||
bool movingCardsUntilAutoPlay = false;
|
bool movingCardsUntilAutoPlay = false;
|
||||||
FilterString movingCardsUntilFilter;
|
FilterString movingCardsUntilFilter;
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,7 @@ QRectF HandZone::boundingRect() const
|
||||||
|
|
||||||
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
QBrush brush = themeManager->getHandBgBrush();
|
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Hand, player->getZoneId());
|
||||||
|
|
||||||
if (player->getZoneId() > 0) {
|
|
||||||
// If the extra image is not found, load the default one
|
|
||||||
brush = themeManager->getExtraHandBgBrush(QString::number(player->getZoneId()), brush);
|
|
||||||
}
|
|
||||||
painter->fillRect(boundingRect(), brush);
|
painter->fillRect(boundingRect(), brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@ PileZone::PileZone(Player *_p, const QString &_name, bool _isShufflable, bool _c
|
||||||
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
|
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
|
||||||
.rotate(90)
|
.rotate(90)
|
||||||
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
|
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
||||||
|
prepareGeometryChange();
|
||||||
|
update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF PileZone::boundingRect() const
|
QRectF PileZone::boundingRect() const
|
||||||
|
|
@ -31,7 +38,8 @@ QRectF PileZone::boundingRect() const
|
||||||
QPainterPath PileZone::shape() const
|
QPainterPath PileZone::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
||||||
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,7 @@ QRectF StackZone::boundingRect() const
|
||||||
|
|
||||||
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
QBrush brush = themeManager->getStackBgBrush();
|
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Stack, player->getZoneId());
|
||||||
|
|
||||||
if (player->getZoneId() > 0) {
|
|
||||||
// If the extra image is not found, load the default one
|
|
||||||
brush = themeManager->getExtraStackBgBrush(QString::number(player->getZoneId()), brush);
|
|
||||||
}
|
|
||||||
painter->fillRect(boundingRect(), brush);
|
painter->fillRect(boundingRect(), brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,28 +66,27 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
|
||||||
cmd.set_target_zone(getName().toStdString());
|
cmd.set_target_zone(getName().toStdString());
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
if (cards.isEmpty()) {
|
|
||||||
index = 0;
|
if (!cards.isEmpty()) {
|
||||||
} else {
|
|
||||||
const auto cardCount = static_cast<int>(cards.size());
|
const auto cardCount = static_cast<int>(cards.size());
|
||||||
const auto &card = cards.at(0);
|
const auto &card = cards.at(0);
|
||||||
|
|
||||||
if (card == nullptr) {
|
|
||||||
qCWarning(StackZoneLog) << "Attempted to move card from" << startZone->getName() << ", but was null";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = qRound(divideCardSpaceInZone(dropPoint.y(), cardCount, boundingRect().height(),
|
index = qRound(divideCardSpaceInZone(dropPoint.y(), cardCount, boundingRect().height(),
|
||||||
card->boundingRect().height(), true));
|
card->boundingRect().height(), true));
|
||||||
}
|
|
||||||
|
// divideCardSpaceInZone is not guaranteed to return a valid index
|
||||||
|
// currently, so clamp it to avoid crashes.
|
||||||
|
index = qBound(0, index, cardCount - 1);
|
||||||
|
|
||||||
if (startZone == this) {
|
if (startZone == this) {
|
||||||
const auto &dragItem = dragItems.at(0);
|
const auto &dragItem = dragItems.at(0);
|
||||||
const auto &card = cards.at(index);
|
const auto &card = cards.at(index);
|
||||||
if (card != nullptr && dragItem != nullptr && card->getId() == dragItem->getId()) {
|
|
||||||
|
if (card->getId() == dragItem->getId()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd.set_x(index);
|
cmd.set_x(index);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
@ -109,8 +103,6 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
|
||||||
void StackZone::reorganizeCards()
|
void StackZone::reorganizeCards()
|
||||||
{
|
{
|
||||||
if (!cards.isEmpty()) {
|
if (!cards.isEmpty()) {
|
||||||
QSet<ArrowItem *> arrowsToUpdate;
|
|
||||||
|
|
||||||
const auto cardCount = static_cast<int>(cards.size());
|
const auto cardCount = static_cast<int>(cards.size());
|
||||||
qreal totalWidth = boundingRect().width();
|
qreal totalWidth = boundingRect().width();
|
||||||
qreal cardWidth = cards.at(0)->boundingRect().width();
|
qreal cardWidth = cards.at(0)->boundingRect().width();
|
||||||
|
|
@ -125,16 +117,6 @@ void StackZone::reorganizeCards()
|
||||||
divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
|
divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
|
||||||
card->setPos(x, y);
|
card->setPos(x, y);
|
||||||
card->setRealZValue(i);
|
card->setRealZValue(i);
|
||||||
|
|
||||||
for (ArrowItem *item : card->getArrowsFrom()) {
|
|
||||||
arrowsToUpdate.insert(item);
|
|
||||||
}
|
|
||||||
for (ArrowItem *item : card->getArrowsTo()) {
|
|
||||||
arrowsToUpdate.insert(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (ArrowItem *item : arrowsToUpdate) {
|
|
||||||
item->updatePath();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include "select_zone.h"
|
#include "select_zone.h"
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(StackZoneLog, "stack_zone");
|
|
||||||
|
|
||||||
class StackZone : public SelectZone
|
class StackZone : public SelectZone
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,7 @@ bool TableZone::isInverted() const
|
||||||
|
|
||||||
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
QBrush brush = themeManager->getTableBgBrush();
|
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Table, player->getZoneId());
|
||||||
|
|
||||||
if (player->getZoneId() > 0) {
|
|
||||||
// If the extra image is not found, load the default one
|
|
||||||
brush = themeManager->getExtraTableBgBrush(QString::number(player->getZoneId()), brush);
|
|
||||||
}
|
|
||||||
painter->fillRect(boundingRect(), brush);
|
painter->fillRect(boundingRect(), brush);
|
||||||
|
|
||||||
if (active) {
|
if (active) {
|
||||||
|
|
@ -157,8 +152,6 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
|
||||||
|
|
||||||
void TableZone::reorganizeCards()
|
void TableZone::reorganizeCards()
|
||||||
{
|
{
|
||||||
QSet<ArrowItem *> arrowsToUpdate;
|
|
||||||
|
|
||||||
// Calculate card stack widths so mapping functions work properly
|
// Calculate card stack widths so mapping functions work properly
|
||||||
computeCardStackWidths();
|
computeCardStackWidths();
|
||||||
|
|
||||||
|
|
@ -189,23 +182,7 @@ void TableZone::reorganizeCards()
|
||||||
qreal childY = y + 5;
|
qreal childY = y + 5;
|
||||||
attachedCard->setPos(childX, childY);
|
attachedCard->setPos(childX, childY);
|
||||||
attachedCard->setRealZValue((childY + CARD_HEIGHT) * 100000 + (childX + 1) * 100);
|
attachedCard->setRealZValue((childY + CARD_HEIGHT) * 100000 + (childX + 1) * 100);
|
||||||
for (ArrowItem *item : attachedCard->getArrowsFrom()) {
|
|
||||||
arrowsToUpdate.insert(item);
|
|
||||||
}
|
}
|
||||||
for (ArrowItem *item : attachedCard->getArrowsTo()) {
|
|
||||||
arrowsToUpdate.insert(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ArrowItem *item : cards[i]->getArrowsFrom()) {
|
|
||||||
arrowsToUpdate.insert(item);
|
|
||||||
}
|
|
||||||
for (ArrowItem *item : cards[i]->getArrowsTo()) {
|
|
||||||
arrowsToUpdate.insert(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (ArrowItem *item : arrowsToUpdate) {
|
|
||||||
item->updatePath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeToContents();
|
resizeToContents();
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
||||||
if (!cardList.isEmpty()) {
|
if (!cardList.isEmpty()) {
|
||||||
for (int i = 0; i < cardList.size(); ++i)
|
for (int i = 0; i < cardList.size(); ++i)
|
||||||
addCard(new CardItem(player, this, QString::fromStdString(cardList[i]->name()),
|
addCard(new CardItem(player, this, QString::fromStdString(cardList[i]->name()),
|
||||||
QString::fromStdString(cardList[i]->provider_id()), cardList[i]->id(), revealZone),
|
QString::fromStdString(cardList[i]->provider_id()), cardList[i]->id()),
|
||||||
false, i);
|
false, i);
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
} else if (!origZone->contentsKnown()) {
|
} else if (!origZone->contentsKnown()) {
|
||||||
|
|
@ -88,8 +88,7 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
||||||
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
|
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
|
||||||
for (int i = 0; i < number; i++) {
|
for (int i = 0; i < number; i++) {
|
||||||
CardItem *card = c.at(i);
|
CardItem *card = c.at(i);
|
||||||
addCard(new CardItem(player, this, card->getName(), card->getProviderId(), card->getId(), revealZone),
|
addCard(new CardItem(player, this, card->getName(), card->getProviderId(), card->getId()), false, i);
|
||||||
false, i);
|
|
||||||
}
|
}
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +102,7 @@ void ZoneViewZone::zoneDumpReceived(const Response &r)
|
||||||
const ServerInfo_Card &cardInfo = resp.zone_info().card_list(i);
|
const ServerInfo_Card &cardInfo = resp.zone_info().card_list(i);
|
||||||
auto cardName = QString::fromStdString(cardInfo.name());
|
auto cardName = QString::fromStdString(cardInfo.name());
|
||||||
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
|
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
|
||||||
auto *card = new CardItem(player, this, cardName, cardProviderId, cardInfo.id(), revealZone, this);
|
auto *card = new CardItem(player, this, cardName, cardProviderId, cardInfo.id(), this);
|
||||||
cards.insert(i, card);
|
cards.insert(i, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,11 +254,13 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
|
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
|
||||||
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
|
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
|
||||||
|
roundCardCorners = settings->value("cards/roundcardcorners", true).toBool();
|
||||||
overrideAllCardArtWithPersonalPreference =
|
overrideAllCardArtWithPersonalPreference =
|
||||||
settings->value("cards/overrideallcardartwithpersonalpreference", false).toBool();
|
settings->value("cards/overrideallcardartwithpersonalpreference", false).toBool();
|
||||||
bumpSetsWithCardsInDeckToTop = settings->value("cards/bumpsetswithcardsindecktotop", true).toBool();
|
bumpSetsWithCardsInDeckToTop = settings->value("cards/bumpsetswithcardsindecktotop", true).toBool();
|
||||||
printingSelectorSortOrder = settings->value("cards/printingselectorsortorder", 1).toInt();
|
printingSelectorSortOrder = settings->value("cards/printingselectorsortorder", 1).toInt();
|
||||||
printingSelectorCardSize = settings->value("cards/printingselectorcardsize", 100).toInt();
|
printingSelectorCardSize = settings->value("cards/printingselectorcardsize", 100).toInt();
|
||||||
|
includeOnlineOnlyCards = settings->value("cards/includeonlineonlycards", false).toBool();
|
||||||
printingSelectorNavigationButtonsVisible =
|
printingSelectorNavigationButtonsVisible =
|
||||||
settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
|
settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
|
||||||
visualDeckStorageCardSize = settings->value("interface/visualdeckstoragecardsize", 100).toInt();
|
visualDeckStorageCardSize = settings->value("interface/visualdeckstoragecardsize", 100).toInt();
|
||||||
|
|
@ -661,6 +663,13 @@ void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
|
||||||
emit printingSelectorCardSizeChanged();
|
emit printingSelectorCardSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setIncludeOnlineOnlyCards(bool _includeOnlineOnlyCards)
|
||||||
|
{
|
||||||
|
includeOnlineOnlyCards = _includeOnlineOnlyCards;
|
||||||
|
settings->setValue("cards/includeonlineonlycards", includeOnlineOnlyCards);
|
||||||
|
emit includeOnlineOnlyCardsChanged(includeOnlineOnlyCards);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible)
|
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible)
|
||||||
{
|
{
|
||||||
printingSelectorNavigationButtonsVisible = _navigationButtonsVisible;
|
printingSelectorNavigationButtonsVisible = _navigationButtonsVisible;
|
||||||
|
|
@ -728,6 +737,7 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visual
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacity = _visualDeckStorageUnusedColorIdentitiesOpacity;
|
visualDeckStorageUnusedColorIdentitiesOpacity = _visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
settings->setValue("interface/visualdeckstorageunusedcoloridentitiesopacity",
|
settings->setValue("interface/visualdeckstorageunusedcoloridentitiesopacity",
|
||||||
visualDeckStorageUnusedColorIdentitiesOpacity);
|
visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
|
emit visualDeckStorageUnusedColorIdentitiesOpacityChanged(visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setVisualDeckStoragePromptForConversion(QT_STATE_CHANGED_T _visualDeckStoragePromptForConversion)
|
void SettingsCache::setVisualDeckStoragePromptForConversion(QT_STATE_CHANGED_T _visualDeckStoragePromptForConversion)
|
||||||
|
|
@ -1292,6 +1302,16 @@ void SettingsCache::setMaxFontSize(int _max)
|
||||||
settings->setValue("game/maxfontsize", maxFontSize);
|
settings->setValue("game/maxfontsize", maxFontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
|
||||||
|
{
|
||||||
|
if (_roundCardCorners == roundCardCorners)
|
||||||
|
return;
|
||||||
|
|
||||||
|
roundCardCorners = _roundCardCorners;
|
||||||
|
settings->setValue("cards/roundcardcorners", _roundCardCorners);
|
||||||
|
emit roundCardCornersChanged(roundCardCorners);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::loadPaths()
|
void SettingsCache::loadPaths()
|
||||||
{
|
{
|
||||||
QString dataPath = getDataPath();
|
QString dataPath = getDataPath();
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ class QSettings;
|
||||||
class SettingsCache : public QObject
|
class SettingsCache : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void langChanged();
|
void langChanged();
|
||||||
void picsPathChanged();
|
void picsPathChanged();
|
||||||
|
|
@ -58,12 +59,14 @@ signals:
|
||||||
void bumpSetsWithCardsInDeckToTopChanged();
|
void bumpSetsWithCardsInDeckToTopChanged();
|
||||||
void printingSelectorSortOrderChanged();
|
void printingSelectorSortOrderChanged();
|
||||||
void printingSelectorCardSizeChanged();
|
void printingSelectorCardSizeChanged();
|
||||||
|
void includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCards);
|
||||||
void printingSelectorNavigationButtonsVisibleChanged();
|
void printingSelectorNavigationButtonsVisibleChanged();
|
||||||
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
||||||
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
||||||
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
||||||
void visualDeckStorageCardSizeChanged();
|
void visualDeckStorageCardSizeChanged();
|
||||||
void visualDeckStorageDrawUnusedColorIdentitiesChanged(bool _visible);
|
void visualDeckStorageDrawUnusedColorIdentitiesChanged(bool _visible);
|
||||||
|
void visualDeckStorageUnusedColorIdentitiesOpacityChanged(bool value);
|
||||||
void visualDeckStorageInGameChanged(bool enabled);
|
void visualDeckStorageInGameChanged(bool enabled);
|
||||||
void horizontalHandChanged();
|
void horizontalHandChanged();
|
||||||
void handJustificationChanged();
|
void handJustificationChanged();
|
||||||
|
|
@ -81,6 +84,7 @@ signals:
|
||||||
void downloadSpoilerTimeIndexChanged();
|
void downloadSpoilerTimeIndexChanged();
|
||||||
void downloadSpoilerStatusChanged();
|
void downloadSpoilerStatusChanged();
|
||||||
void useTearOffMenusChanged(bool state);
|
void useTearOffMenusChanged(bool state);
|
||||||
|
void roundCardCornersChanged(bool roundCardCorners);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSettings *settings;
|
QSettings *settings;
|
||||||
|
|
@ -127,6 +131,7 @@ private:
|
||||||
bool bumpSetsWithCardsInDeckToTop;
|
bool bumpSetsWithCardsInDeckToTop;
|
||||||
int printingSelectorSortOrder;
|
int printingSelectorSortOrder;
|
||||||
int printingSelectorCardSize;
|
int printingSelectorCardSize;
|
||||||
|
bool includeOnlineOnlyCards;
|
||||||
bool printingSelectorNavigationButtonsVisible;
|
bool printingSelectorNavigationButtonsVisible;
|
||||||
int visualDeckStorageSortingOrder;
|
int visualDeckStorageSortingOrder;
|
||||||
bool visualDeckStorageShowFolders;
|
bool visualDeckStorageShowFolders;
|
||||||
|
|
@ -201,6 +206,7 @@ private:
|
||||||
QList<ReleaseChannel *> releaseChannels;
|
QList<ReleaseChannel *> releaseChannels;
|
||||||
bool isPortableBuild;
|
bool isPortableBuild;
|
||||||
bool localTime;
|
bool localTime;
|
||||||
|
bool roundCardCorners;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SettingsCache();
|
SettingsCache();
|
||||||
|
|
@ -401,6 +407,10 @@ public:
|
||||||
{
|
{
|
||||||
return printingSelectorCardSize;
|
return printingSelectorCardSize;
|
||||||
}
|
}
|
||||||
|
bool getIncludeOnlineOnlyCards() const
|
||||||
|
{
|
||||||
|
return includeOnlineOnlyCards;
|
||||||
|
}
|
||||||
bool getPrintingSelectorNavigationButtonsVisible() const
|
bool getPrintingSelectorNavigationButtonsVisible() const
|
||||||
{
|
{
|
||||||
return printingSelectorNavigationButtonsVisible;
|
return printingSelectorNavigationButtonsVisible;
|
||||||
|
|
@ -731,6 +741,10 @@ public:
|
||||||
{
|
{
|
||||||
return mbDownloadSpoilers;
|
return mbDownloadSpoilers;
|
||||||
}
|
}
|
||||||
|
bool getRoundCardCorners() const
|
||||||
|
{
|
||||||
|
return roundCardCorners;
|
||||||
|
}
|
||||||
|
|
||||||
static SettingsCache &instance();
|
static SettingsCache &instance();
|
||||||
void resetPaths();
|
void resetPaths();
|
||||||
|
|
@ -778,6 +792,7 @@ public slots:
|
||||||
void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
|
void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
|
||||||
void setPrintingSelectorSortOrder(int _printingSelectorSortOrder);
|
void setPrintingSelectorSortOrder(int _printingSelectorSortOrder);
|
||||||
void setPrintingSelectorCardSize(int _printingSelectorCardSize);
|
void setPrintingSelectorCardSize(int _printingSelectorCardSize);
|
||||||
|
void setIncludeOnlineOnlyCards(bool _includeOnlineOnlyCards);
|
||||||
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
|
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
|
||||||
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
|
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
|
||||||
void setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value);
|
void setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value);
|
||||||
|
|
@ -839,6 +854,7 @@ public slots:
|
||||||
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
||||||
void setUpdateReleaseChannelIndex(int value);
|
void setUpdateReleaseChannelIndex(int value);
|
||||||
void setMaxFontSize(int _max);
|
void setMaxFontSize(int _max);
|
||||||
|
void setRoundCardCorners(bool _roundCardCorners);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,11 @@ private:
|
||||||
{"MainWindow/aWatchReplay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Watch Replay..."),
|
{"MainWindow/aWatchReplay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Watch Replay..."),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Main_Window)},
|
ShortcutGroup::Main_Window)},
|
||||||
{"TabDeckEditor/aAnalyzeDeck", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Analyze Deck"),
|
{"TabDeckEditor/aAnalyzeDeck", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Analyze Deck (deckstats.net)"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Deck_Editor)},
|
||||||
|
{"TabDeckEditor/aAnalyzeDeckTappedout",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Analyze Deck (tappedout.net)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Deck_Editor)},
|
ShortcutGroup::Deck_Editor)},
|
||||||
{"TabDeckEditor/aClearFilterAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Clear All Filters"),
|
{"TabDeckEditor/aClearFilterAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Clear All Filters"),
|
||||||
|
|
@ -193,7 +197,12 @@ private:
|
||||||
{"TabDeckEditor/aEditTokens", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Edit Custom Tokens..."),
|
{"TabDeckEditor/aEditTokens", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Edit Custom Tokens..."),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Deck_Editor)},
|
ShortcutGroup::Deck_Editor)},
|
||||||
{"TabDeckEditor/aExportDeckDecklist", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck"),
|
{"TabDeckEditor/aExportDeckDecklist",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck (decklist.org)"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Deck_Editor)},
|
||||||
|
{"TabDeckEditor/aExportDeckDecklistXyz",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck (decklist.xyz)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Deck_Editor)},
|
ShortcutGroup::Deck_Editor)},
|
||||||
{"TabDeckEditor/aIncrement", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Card"),
|
{"TabDeckEditor/aIncrement", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Card"),
|
||||||
|
|
|
||||||
|
|
@ -548,7 +548,14 @@ bool DeckList::saveToFile_Native(QIODevice *device)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckList::loadFromStream_Plain(QTextStream &in)
|
/**
|
||||||
|
* Clears the decklist and loads in a new deck from text
|
||||||
|
*
|
||||||
|
* @param in The text to load
|
||||||
|
* @param preserveMetadata If true, don't clear the existing metadata
|
||||||
|
* @return False if the input was empty, true otherwise.
|
||||||
|
*/
|
||||||
|
bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata)
|
||||||
{
|
{
|
||||||
const QRegularExpression reCardLine(R"(^\s*[\w\[\(\{].*$)", QRegularExpression::UseUnicodePropertiesOption);
|
const QRegularExpression reCardLine(R"(^\s*[\w\[\(\{].*$)", QRegularExpression::UseUnicodePropertiesOption);
|
||||||
const QRegularExpression reEmpty("^\\s*$");
|
const QRegularExpression reEmpty("^\\s*$");
|
||||||
|
|
@ -577,7 +584,7 @@ bool DeckList::loadFromStream_Plain(QTextStream &in)
|
||||||
{QRegularExpression("æ"), QString("ae")},
|
{QRegularExpression("æ"), QString("ae")},
|
||||||
{QRegularExpression(" ?[|/]+ ?"), QString(" // ")}};
|
{QRegularExpression(" ?[|/]+ ?"), QString(" // ")}};
|
||||||
|
|
||||||
cleanList();
|
cleanList(preserveMetadata);
|
||||||
|
|
||||||
auto inputs = in.readAll().trimmed().split('\n');
|
auto inputs = in.readAll().trimmed().split('\n');
|
||||||
auto max_line = inputs.size();
|
auto max_line = inputs.size();
|
||||||
|
|
@ -752,7 +759,7 @@ InnerDecklistNode *DeckList::getZoneObjFromName(const QString &zoneName)
|
||||||
bool DeckList::loadFromFile_Plain(QIODevice *device)
|
bool DeckList::loadFromFile_Plain(QIODevice *device)
|
||||||
{
|
{
|
||||||
QTextStream in(device);
|
QTextStream in(device);
|
||||||
return loadFromStream_Plain(in);
|
return loadFromStream_Plain(in, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WriteToStream
|
struct WriteToStream
|
||||||
|
|
@ -801,12 +808,19 @@ QString DeckList::writeToString_Plain(bool prefixSideboardCards, bool slashTappe
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckList::cleanList()
|
/**
|
||||||
|
* Clears all cards and other data from the decklist
|
||||||
|
*
|
||||||
|
* @param preserveMetadata If true, only clear the cards
|
||||||
|
*/
|
||||||
|
void DeckList::cleanList(bool preserveMetadata)
|
||||||
{
|
{
|
||||||
root->clearTree();
|
root->clearTree();
|
||||||
|
if (!preserveMetadata) {
|
||||||
setName();
|
setName();
|
||||||
setComments();
|
setComments();
|
||||||
setTags();
|
setTags();
|
||||||
|
}
|
||||||
refreshDeckHash();
|
refreshDeckHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -351,13 +351,13 @@ public:
|
||||||
QString writeToString_Native();
|
QString writeToString_Native();
|
||||||
bool loadFromFile_Native(QIODevice *device);
|
bool loadFromFile_Native(QIODevice *device);
|
||||||
bool saveToFile_Native(QIODevice *device);
|
bool saveToFile_Native(QIODevice *device);
|
||||||
bool loadFromStream_Plain(QTextStream &stream);
|
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
|
||||||
bool loadFromFile_Plain(QIODevice *device);
|
bool loadFromFile_Plain(QIODevice *device);
|
||||||
bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards);
|
bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards);
|
||||||
bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
||||||
QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
||||||
|
|
||||||
void cleanList();
|
void cleanList(bool preserveMetadata = false);
|
||||||
bool isEmpty() const
|
bool isEmpty() const
|
||||||
{
|
{
|
||||||
return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty();
|
return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty();
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ set(dbconverter_SOURCES
|
||||||
../cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp
|
../cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp
|
||||||
../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
||||||
../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
||||||
|
../cockatrice/src/game/cards/card_info.cpp
|
||||||
../cockatrice/src/settings/settings_manager.cpp
|
../cockatrice/src/settings/settings_manager.cpp
|
||||||
${VERSION_STRING_CPP}
|
${VERSION_STRING_CPP}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,9 @@ void SettingsCache::setPrintingSelectorSortOrder(int /* _printingSelectorSortOrd
|
||||||
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
|
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setIncludeOnlineOnlyCards(bool /* _includeOnlineOnlyCards */)
|
||||||
|
{
|
||||||
|
}
|
||||||
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
|
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -387,6 +390,9 @@ void SettingsCache::setUpdateReleaseChannelIndex(int /* value */)
|
||||||
void SettingsCache::setMaxFontSize(int /* _max */)
|
void SettingsCache::setMaxFontSize(int /* _max */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setRoundCardCorners(bool /* _roundCardCorners */)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void PictureLoader::clearPixmapCache(CardInfoPtr /* card */)
|
void PictureLoader::clearPixmapCache(CardInfoPtr /* card */)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
<xs:attribute type="xs:anyURI" name="picURL" use="optional" />
|
<xs:attribute type="xs:anyURI" name="picURL" use="optional" />
|
||||||
<xs:attribute type="xs:string" name="num" use="optional" />
|
<xs:attribute type="xs:string" name="num" use="optional" />
|
||||||
<xs:attribute type="xs:string" name="rarity" use="optional" />
|
<xs:attribute type="xs:string" name="rarity" use="optional" />
|
||||||
|
<xs:attribute type="xs:boolean" name="onlineOnly" use="optional" />
|
||||||
</xs:extension>
|
</xs:extension>
|
||||||
</xs:simpleContent>
|
</xs:simpleContent>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql
|
- mysql
|
||||||
ports:
|
ports:
|
||||||
- "4747:4747"
|
|
||||||
- "4748:4748"
|
- "4748:4748"
|
||||||
entrypoint: "/bin/bash -c 'sleep 10; servatrice --config /tmp/servatrice.ini --log-to-console'"
|
entrypoint: "/bin/bash -c 'sleep 10; servatrice --config /tmp/servatrice.ini --log-to-console'"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql
|
- mysql
|
||||||
ports:
|
ports:
|
||||||
- "4747:4747"
|
|
||||||
- "4748:4748"
|
- "4748:4748"
|
||||||
entrypoint: "/bin/bash -c 'sleep 10; servatrice --config /tmp/servatrice.ini --log-to-console'"
|
entrypoint: "/bin/bash -c 'sleep 10; servatrice --config /tmp/servatrice.ini --log-to-console'"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,11 @@ set(oracle_SOURCES
|
||||||
src/oraclewizard.cpp
|
src/oraclewizard.cpp
|
||||||
src/oracleimporter.cpp
|
src/oracleimporter.cpp
|
||||||
src/pagetemplates.cpp
|
src/pagetemplates.cpp
|
||||||
|
src/parsehelpers.cpp
|
||||||
src/qt-json/json.cpp
|
src/qt-json/json.cpp
|
||||||
../cockatrice/src/game/cards/card_database.cpp
|
../cockatrice/src/game/cards/card_database.cpp
|
||||||
../cockatrice/src/game/cards/card_database_manager.cpp
|
../cockatrice/src/game/cards/card_database_manager.cpp
|
||||||
|
../cockatrice/src/game/cards/card_info.cpp
|
||||||
../cockatrice/src/client/ui/picture_loader/picture_loader.cpp
|
../cockatrice/src/client/ui/picture_loader/picture_loader.cpp
|
||||||
../cockatrice/src/client/ui/picture_loader/picture_loader_worker.cpp
|
../cockatrice/src/client/ui/picture_loader/picture_loader_worker.cpp
|
||||||
../cockatrice/src/client/ui/picture_loader/picture_to_load.cpp
|
../cockatrice/src/client/ui/picture_loader/picture_to_load.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,29 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!DOCTYPE TS>
|
<!DOCTYPE TS>
|
||||||
<TS version="2.1" language="en_US">
|
<TS version="2.1" language="en_US">
|
||||||
|
<context>
|
||||||
|
<name>BetaReleaseChannel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="210"/>
|
||||||
|
<source>Beta</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="236"/>
|
||||||
|
<source>No reply received from the release update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="245"/>
|
||||||
|
<source>Invalid reply received from the release update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="278"/>
|
||||||
|
<source>No reply received from the file update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>IntroPage</name>
|
<name>IntroPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -63,7 +86,8 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oraclewizard.cpp" line="287"/>
|
<location filename="src/oraclewizard.cpp" line="287"/>
|
||||||
<source>Sets JSON file (%1)</source>
|
<source>Sets file (%1)</source>
|
||||||
|
<oldsource>Sets JSON file (%1)</oldsource>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -247,7 +271,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>OracleImporter</name>
|
<name>OracleImporter</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oracleimporter.cpp" line="465"/>
|
<location filename="src/oracleimporter.cpp" line="472"/>
|
||||||
<source>Dummy set containing tokens</source>
|
<source>Dummy set containing tokens</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -283,6 +307,15 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PictureLoader</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/ui/picture_loader/picture_to_load.cpp" line="219"/>
|
||||||
|
<source>en</source>
|
||||||
|
<comment>code for scryfall's language property, not available for all languages</comment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SaveSetsPage</name>
|
<name>SaveSetsPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -357,6 +390,21 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ShortcutsSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/settings/shortcuts_settings.cpp" line="54"/>
|
||||||
|
<source>Your configuration file contained invalid shortcuts.
|
||||||
|
Please check your shortcut settings!</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/settings/shortcuts_settings.cpp" line="56"/>
|
||||||
|
<source>The following shortcuts have been set to default:
|
||||||
|
</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SimpleDownloadFilePage</name>
|
<name>SimpleDownloadFilePage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -392,6 +440,34 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StableReleaseChannel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="104"/>
|
||||||
|
<source>Default</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="120"/>
|
||||||
|
<source>No reply received from the release update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="128"/>
|
||||||
|
<source>Invalid reply received from the release update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="176"/>
|
||||||
|
<source>No reply received from the tag update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="183"/>
|
||||||
|
<source>Invalid reply received from the tag update server.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>UnZip</name>
|
<name>UnZip</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -537,6 +613,7 @@
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oraclewizard.cpp" line="58"/>
|
<location filename="src/oraclewizard.cpp" line="58"/>
|
||||||
|
<location filename="../cockatrice/src/settings/cache_settings.cpp" line="167"/>
|
||||||
<source>English</source>
|
<source>English</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "oracleimporter.h"
|
#include "oracleimporter.h"
|
||||||
|
|
||||||
#include "game/cards/card_database_parser/cockatrice_xml_4.h"
|
#include "game/cards/card_database_parser/cockatrice_xml_4.h"
|
||||||
|
#include "parsehelpers.h"
|
||||||
#include "qt-json/json.h"
|
#include "qt-json/json.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
@ -157,9 +158,7 @@ CardInfoPtr OracleImporter::addCard(QString name,
|
||||||
// DETECT CARD POSITIONING INFO
|
// DETECT CARD POSITIONING INFO
|
||||||
|
|
||||||
// cards that enter the field tapped
|
// cards that enter the field tapped
|
||||||
QRegularExpression ciptRegex("( it|" + QRegularExpression::escape(name) +
|
bool cipt = parseCipt(name, text);
|
||||||
") enters( the battlefield)? tapped(?! unless)");
|
|
||||||
bool cipt = ciptRegex.match(text).hasMatch();
|
|
||||||
|
|
||||||
bool landscapeOrientation = properties.value("maintype").toString() == "Battle" ||
|
bool landscapeOrientation = properties.value("maintype").toString() == "Battle" ||
|
||||||
properties.value("layout").toString() == "split" ||
|
properties.value("layout").toString() == "split" ||
|
||||||
|
|
@ -209,10 +208,12 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
|
||||||
static const QMap<QString, QString> cardProperties{
|
static const QMap<QString, QString> cardProperties{
|
||||||
{"manaCost", "manacost"}, {"manaValue", "cmc"}, {"type", "type"},
|
{"manaCost", "manacost"}, {"manaValue", "cmc"}, {"type", "type"},
|
||||||
{"loyalty", "loyalty"}, {"layout", "layout"}, {"side", "side"},
|
{"loyalty", "loyalty"}, {"layout", "layout"}, {"side", "side"},
|
||||||
|
{"convertedManaCost", "cmc"}, // old name for manaValue, for backwards compatibility
|
||||||
};
|
};
|
||||||
|
|
||||||
// mtgjson name => xml name
|
// mtgjson name => xml name
|
||||||
static const QMap<QString, QString> setInfoProperties{{"number", "num"}, {"rarity", "rarity"}};
|
static const QMap<QString, QString> setInfoProperties{
|
||||||
|
{"number", "num"}, {"rarity", "rarity"}, {"isOnlineOnly", "isOnlineOnly"}};
|
||||||
|
|
||||||
// mtgjson name => xml name
|
// mtgjson name => xml name
|
||||||
static const QMap<QString, QString> identifierProperties{{"multiverseId", "muid"}, {"scryfallId", "uuid"}};
|
static const QMap<QString, QString> identifierProperties{{"multiverseId", "muid"}, {"scryfallId", "uuid"}};
|
||||||
|
|
@ -350,7 +351,13 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
|
||||||
|
|
||||||
// add other face for split cards as card relation
|
// add other face for split cards as card relation
|
||||||
if (!getStringPropertyFromMap(card, "side").isEmpty()) {
|
if (!getStringPropertyFromMap(card, "side").isEmpty()) {
|
||||||
properties["cmc"] = getStringPropertyFromMap(card, "faceManaValue");
|
auto faceManaValue = getStringPropertyFromMap(card, "faceManaValue");
|
||||||
|
if (faceManaValue.isEmpty()) {
|
||||||
|
// check the old name for the property, for backwards compatibility purposes
|
||||||
|
faceManaValue = getStringPropertyFromMap(card, "faceConvertedManaCost");
|
||||||
|
}
|
||||||
|
properties["cmc"] = faceManaValue;
|
||||||
|
|
||||||
if (layout == "meld") { // meld cards don't work
|
if (layout == "meld") { // meld cards don't work
|
||||||
static const QRegularExpression meldNameRegex{"then meld them into ([^\\.]*)"};
|
static const QRegularExpression meldNameRegex{"then meld them into ([^\\.]*)"};
|
||||||
QString additionalName = meldNameRegex.match(text).captured(1);
|
QString additionalName = meldNameRegex.match(text).captured(1);
|
||||||
|
|
|
||||||
69
oracle/src/parsehelpers.cpp
Normal file
69
oracle/src/parsehelpers.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "parsehelpers.h"
|
||||||
|
|
||||||
|
#include <QChar>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the card text to determine if the card should have the cipt tag
|
||||||
|
*
|
||||||
|
* The parsing logic is able to handle the following cases:
|
||||||
|
* - "<name> enters tapped"
|
||||||
|
* - "<shortname> enters tapped", if the card name starts with the shortname
|
||||||
|
* - "This <type> enters tapped"
|
||||||
|
* - "..., it enters tapped"
|
||||||
|
* - Any naming scheme that appends a non-alphanumeric character plus extra text to the end of the name.
|
||||||
|
* (e.g. name is "Card Name_SET" or "Card Name (Set)" and text contains "Card Name enters tapped")
|
||||||
|
*
|
||||||
|
* However, it will still miss on certain cases:
|
||||||
|
* - shortnames that aren't the at the beginning of the card name
|
||||||
|
*
|
||||||
|
* Note that "...enters tapped unless..." returns false.
|
||||||
|
*
|
||||||
|
* @param name The name of the card
|
||||||
|
* @param text The oracle text of the card
|
||||||
|
*/
|
||||||
|
bool parseCipt(const QString &name, const QString &text)
|
||||||
|
{
|
||||||
|
// Use precompiled regex to check if text is a possible candidate, and early return if not
|
||||||
|
static auto prelimCheck = QRegularExpression(" enters( the battlefield)? tapped(?! unless)");
|
||||||
|
if (!prelimCheck.match(text).hasMatch()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to split shortname on most non-alphanumeric characters (including _)
|
||||||
|
auto isShortnameDivider = [](const QChar &c) {
|
||||||
|
return c == '_' || (!c.isLetterOrNumber() && c != '\'' && c != '\"');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try all possible shortnames.
|
||||||
|
// This also handles the case of extra text appended at end.
|
||||||
|
QStringList possibleNames;
|
||||||
|
bool inAlphanumericPart = true;
|
||||||
|
for (int i = 0; i < name.length(); ++i) {
|
||||||
|
if (isShortnameDivider(name.at(i))) {
|
||||||
|
if (inAlphanumericPart) {
|
||||||
|
// only add to names on a "falling edge", in order to reduce the amount of redundant splits
|
||||||
|
possibleNames.append(QRegularExpression::escape(name.left(i)));
|
||||||
|
inAlphanumericPart = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inAlphanumericPart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// and the full name
|
||||||
|
possibleNames.append(QRegularExpression::escape(name));
|
||||||
|
|
||||||
|
QString subject = "(it|" // "..., it enters tapped"
|
||||||
|
"(T|t)his [^ ]+|" // "This <type> enters tapped"
|
||||||
|
+ possibleNames.join("|") + ")";
|
||||||
|
|
||||||
|
auto ciptPattern = QRegularExpression(
|
||||||
|
// cipt phrase is either first sentence of line, or is after a punctuation mark
|
||||||
|
"(^|(, |\\. ))" + subject +
|
||||||
|
// support old wording, and exclude the "unless" case
|
||||||
|
" enters( the battlefield)? tapped(?! unless)",
|
||||||
|
QRegularExpression::MultilineOption);
|
||||||
|
|
||||||
|
return ciptPattern.match(text).hasMatch();
|
||||||
|
}
|
||||||
8
oracle/src/parsehelpers.h
Normal file
8
oracle/src/parsehelpers.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef PARSEHELPERS_H
|
||||||
|
#define PARSEHELPERS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
bool parseCipt(const QString &name, const QString &text);
|
||||||
|
|
||||||
|
#endif // PARSEHELPERS_H
|
||||||
|
|
@ -1,4 +1,27 @@
|
||||||
<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="it">
|
<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="it">
|
||||||
|
<context>
|
||||||
|
<name>BetaReleaseChannel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="210"/>
|
||||||
|
<source>Beta</source>
|
||||||
|
<translation>Beta</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="236"/>
|
||||||
|
<source>No reply received from the release update server.</source>
|
||||||
|
<translation>Nessuna risposta ricevuta dal server degli aggiornamenti di versione.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="245"/>
|
||||||
|
<source>Invalid reply received from the release update server.</source>
|
||||||
|
<translation>Ricevuta risposta non valida dal server degli aggiornamenti.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="278"/>
|
||||||
|
<source>No reply received from the file update server.</source>
|
||||||
|
<translation>Nessuna risposta ricevuta dal server degli aggiornamenti.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>IntroPage</name>
|
<name>IntroPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -62,8 +85,9 @@ e pedine che verranno usate da Cockatrice.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oraclewizard.cpp" line="287"/>
|
<location filename="src/oraclewizard.cpp" line="287"/>
|
||||||
<source>Sets JSON file (%1)</source>
|
<source>Sets file (%1)</source>
|
||||||
<translation>File dei set JSON (%1)</translation>
|
<oldsource>Sets JSON file (%1)</oldsource>
|
||||||
|
<translation>File dei set (%1)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oraclewizard.cpp" line="317"/>
|
<location filename="src/oraclewizard.cpp" line="317"/>
|
||||||
|
|
@ -246,7 +270,7 @@ e pedine che verranno usate da Cockatrice.</translation>
|
||||||
<context>
|
<context>
|
||||||
<name>OracleImporter</name>
|
<name>OracleImporter</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oracleimporter.cpp" line="465"/>
|
<location filename="src/oracleimporter.cpp" line="472"/>
|
||||||
<source>Dummy set containing tokens</source>
|
<source>Dummy set containing tokens</source>
|
||||||
<translation>Set finto contenente i token</translation>
|
<translation>Set finto contenente i token</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -282,6 +306,15 @@ e pedine che verranno usate da Cockatrice.</translation>
|
||||||
<translation>Se il database delle carte non si ricarica in automatico, riavvia il programma Cockatrice.</translation>
|
<translation>Se il database delle carte non si ricarica in automatico, riavvia il programma Cockatrice.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PictureLoader</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/ui/picture_loader/picture_to_load.cpp" line="219"/>
|
||||||
|
<source>en</source>
|
||||||
|
<comment>code for scryfall's language property, not available for all languages</comment>
|
||||||
|
<translation>it</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SaveSetsPage</name>
|
<name>SaveSetsPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -356,6 +389,23 @@ e pedine che verranno usate da Cockatrice.</translation>
|
||||||
<translation>Impossibile salvare il file su %1</translation>
|
<translation>Impossibile salvare il file su %1</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ShortcutsSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/settings/shortcuts_settings.cpp" line="54"/>
|
||||||
|
<source>Your configuration file contained invalid shortcuts.
|
||||||
|
Please check your shortcut settings!</source>
|
||||||
|
<translation>Il file di configurazione conteneva combinazioni di tasti non valide.
|
||||||
|
Controlla le impostazioni delle combinazioni!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/settings/shortcuts_settings.cpp" line="56"/>
|
||||||
|
<source>The following shortcuts have been set to default:
|
||||||
|
</source>
|
||||||
|
<translation>Le seguenti combinazioni di tasti sono state reimpostate al valore predefinito:
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SimpleDownloadFilePage</name>
|
<name>SimpleDownloadFilePage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -391,6 +441,34 @@ e pedine che verranno usate da Cockatrice.</translation>
|
||||||
<translation>Impossibile salvare il file su %1</translation>
|
<translation>Impossibile salvare il file su %1</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StableReleaseChannel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="104"/>
|
||||||
|
<source>Default</source>
|
||||||
|
<translation>Predefinito</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="120"/>
|
||||||
|
<source>No reply received from the release update server.</source>
|
||||||
|
<translation>Nessuna risposta ricevuta dal server degli aggiornamenti di versione.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="128"/>
|
||||||
|
<source>Invalid reply received from the release update server.</source>
|
||||||
|
<translation>Ricevuta risposta non valida dal server degli aggiornamenti.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="176"/>
|
||||||
|
<source>No reply received from the tag update server.</source>
|
||||||
|
<translation>Nessuna risposta ricevuta dal server dei tag di aggiornamento.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="183"/>
|
||||||
|
<source>Invalid reply received from the tag update server.</source>
|
||||||
|
<translation>Ricevuta risposta non valida dal server dei tag di aggiornamento.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>UnZip</name>
|
<name>UnZip</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -536,6 +614,7 @@ e pedine che verranno usate da Cockatrice.</translation>
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/oraclewizard.cpp" line="58"/>
|
<location filename="src/oraclewizard.cpp" line="58"/>
|
||||||
|
<location filename="../cockatrice/src/settings/cache_settings.cpp" line="167"/>
|
||||||
<source>English</source>
|
<source>English</source>
|
||||||
<translation>Italiano (Italian)</translation>
|
<translation>Italiano (Italian)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ from pypb.event_server_identification_pb2 import Event_ServerIdentification as S
|
||||||
from pypb.response_pb2 import Response
|
from pypb.response_pb2 import Response
|
||||||
|
|
||||||
HOST = "localhost"
|
HOST = "localhost"
|
||||||
PORT = 4747
|
PORT = 4748
|
||||||
|
|
||||||
CMD_ID = 1
|
CMD_ID = 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ id=1
|
||||||
|
|
||||||
host=any
|
host=any
|
||||||
|
|
||||||
; The TCP port number servatrice will listen on for clients; default is 4747
|
; The TCP port number Servatrice will listen on for clients; default is 4747;
|
||||||
|
; Will be removed in the future, use websocket connection instead
|
||||||
port=4747
|
port=4747
|
||||||
|
|
||||||
; Servatrice can scale up to serve big number of users using more than one parallel thread of execution;
|
; Servatrice can scale up to serve big number of users using more than one parallel thread of execution;
|
||||||
|
|
@ -421,7 +422,7 @@ enable_forgotpassword_audit=true
|
||||||
; "servers" table of the database. Default is 0 (disabled)
|
; "servers" table of the database. Default is 0 (disabled)
|
||||||
active=0
|
active=0
|
||||||
|
|
||||||
; The TCP port number servatrice will listen on for other servers; default is 14747
|
; The TCP port number Servatrice will listen on for other servers; default is 14747
|
||||||
port=14747
|
port=14747
|
||||||
|
|
||||||
; Server-to-server communication needs a valid certificate in PEM format. Enter its filename in this setting
|
; Server-to-server communication needs a valid certificate in PEM format. Enter its filename in this setting
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
# Build tools
|
# Build tools
|
||||||
cmake
|
cmake
|
||||||
cmake-format
|
cmake-format
|
||||||
|
ninja
|
||||||
bash
|
bash
|
||||||
curl
|
curl
|
||||||
git
|
git
|
||||||
|
|
@ -12,6 +13,7 @@
|
||||||
# Debug / Test
|
# Debug / Test
|
||||||
valgrind
|
valgrind
|
||||||
gdb
|
gdb
|
||||||
|
clang-tools
|
||||||
|
|
||||||
# Compiler
|
# Compiler
|
||||||
gcc
|
gcc
|
||||||
|
|
@ -23,4 +25,8 @@
|
||||||
qt6.full
|
qt6.full
|
||||||
qt6.wrapQtAppsHook
|
qt6.wrapQtAppsHook
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Make debug builds work
|
||||||
|
# https://github.com/NixOS/nixpkgs/issues/18995
|
||||||
|
hardeningDisable = [ "fortify" ];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,3 +51,4 @@ target_link_libraries(password_hash_test cockatrice_common Threads::Threads ${GT
|
||||||
|
|
||||||
add_subdirectory(carddatabase)
|
add_subdirectory(carddatabase)
|
||||||
add_subdirectory(loading_from_clipboard)
|
add_subdirectory(loading_from_clipboard)
|
||||||
|
add_subdirectory(oracle)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ add_executable(
|
||||||
../../cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp
|
../../cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp
|
||||||
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
||||||
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
||||||
|
../../cockatrice/src/game/cards/card_info.cpp
|
||||||
../../cockatrice/src/settings/settings_manager.cpp
|
../../cockatrice/src/settings/settings_manager.cpp
|
||||||
carddatabase_test.cpp
|
carddatabase_test.cpp
|
||||||
mocks.cpp
|
mocks.cpp
|
||||||
|
|
@ -35,6 +36,7 @@ add_executable(
|
||||||
../../cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp
|
../../cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp
|
||||||
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_3.cpp
|
||||||
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
../../cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp
|
||||||
|
../../cockatrice/src/game/cards/card_info.cpp
|
||||||
../../cockatrice/src/game/filters/filter_card.cpp
|
../../cockatrice/src/game/filters/filter_card.cpp
|
||||||
../../cockatrice/src/game/filters/filter_string.cpp
|
../../cockatrice/src/game/filters/filter_string.cpp
|
||||||
../../cockatrice/src/game/filters/filter_tree.cpp
|
../../cockatrice/src/game/filters/filter_tree.cpp
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,9 @@ void SettingsCache::setPrintingSelectorSortOrder(int /* _printingSelectorSortOrd
|
||||||
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
|
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setIncludeOnlineOnlyCards(bool /* _includeOnlineOnlyCards */)
|
||||||
|
{
|
||||||
|
}
|
||||||
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
|
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -391,6 +394,9 @@ void SettingsCache::setUpdateReleaseChannelIndex(int /* value */)
|
||||||
void SettingsCache::setMaxFontSize(int /* _max */)
|
void SettingsCache::setMaxFontSize(int /* _max */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setRoundCardCorners(bool /* _roundCardCorners */)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void PictureLoader::clearPixmapCache(CardInfoPtr /* card */)
|
void PictureLoader::clearPixmapCache(CardInfoPtr /* card */)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ void testEmpty(const QString &clipboard)
|
||||||
QString cp(clipboard);
|
QString cp(clipboard);
|
||||||
DeckList deckList;
|
DeckList deckList;
|
||||||
QTextStream stream(&cp); // text stream requires local copy
|
QTextStream stream(&cp); // text stream requires local copy
|
||||||
deckList.loadFromStream_Plain(stream);
|
deckList.loadFromStream_Plain(stream, false);
|
||||||
|
|
||||||
ASSERT_TRUE(deckList.getCardList().isEmpty());
|
ASSERT_TRUE(deckList.getCardList().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ void testDeck(const QString &clipboard, const Result &result)
|
||||||
QString cp(clipboard);
|
QString cp(clipboard);
|
||||||
DeckList deckList;
|
DeckList deckList;
|
||||||
QTextStream stream(&cp); // text stream requires local copy
|
QTextStream stream(&cp); // text stream requires local copy
|
||||||
deckList.loadFromStream_Plain(stream);
|
deckList.loadFromStream_Plain(stream, false);
|
||||||
|
|
||||||
ASSERT_EQ(result.name, deckList.getName().toStdString());
|
ASSERT_EQ(result.name, deckList.getName().toStdString());
|
||||||
ASSERT_EQ(result.comments, deckList.getComments().toStdString());
|
ASSERT_EQ(result.comments, deckList.getComments().toStdString());
|
||||||
|
|
|
||||||
11
tests/oracle/CMakeLists.txt
Normal file
11
tests/oracle/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
add_executable(parse_cipt_test ../../oracle/src/parsehelpers.cpp parse_cipt_test.cpp)
|
||||||
|
|
||||||
|
if(NOT GTEST_FOUND)
|
||||||
|
add_dependencies(parse_cipt_test gtest)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(TEST_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Widgets)
|
||||||
|
|
||||||
|
target_link_libraries(parse_cipt_test cockatrice_common Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES})
|
||||||
|
|
||||||
|
add_test(NAME parse_cipt_test COMMAND parse_cipt_test)
|
||||||
219
tests/oracle/parse_cipt_test.cpp
Normal file
219
tests/oracle/parse_cipt_test.cpp
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
#include "../../oracle/src/parsehelpers.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesThisEntersTapped)
|
||||||
|
{
|
||||||
|
auto name = "Boring Fields";
|
||||||
|
auto text = "This land enters tapped.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesThisEntersTheBattlefieldTapped)
|
||||||
|
{
|
||||||
|
auto name = "Boring Fields";
|
||||||
|
auto text = "This land enters the battlefield tapped.\n"
|
||||||
|
"{T}: Add {G}.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesItEntersTappedAtEndOfSentence)
|
||||||
|
{
|
||||||
|
auto name = "Shocking Fields";
|
||||||
|
auto text = "As this land enters, you may pay 2 life. If you don't, it enters tapped.\n"
|
||||||
|
"{T}: Add {G}.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesThisEntersTappedWhenNotOnFirstLine)
|
||||||
|
{
|
||||||
|
auto name = "Boring Fields";
|
||||||
|
auto text = "Flying\n"
|
||||||
|
"This land enters tapped.\n"
|
||||||
|
"{T}: Add {G}.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesFullNameWithUnderscoreAppendedText)
|
||||||
|
{
|
||||||
|
auto name = "Boring Fields_SL50";
|
||||||
|
auto text = "Boring Fields enters tapped.\n"
|
||||||
|
"{T}: Add {G}.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesFullNameWithBracketsAppendedText)
|
||||||
|
{
|
||||||
|
auto name = "Boring Fields (SL50)";
|
||||||
|
auto text = "Boring Fields enters tapped.\n"
|
||||||
|
"{T}: Add {G}.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesFullNameWithComma)
|
||||||
|
{
|
||||||
|
auto name = "Bob, the Legend";
|
||||||
|
auto text = "Bob, the Legend enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesFullNameWithCommaAtEndOfSentence)
|
||||||
|
{
|
||||||
|
auto name = "Bob, the Legend";
|
||||||
|
auto text = "As Bob, the Legend enters, you may pay 2 life. If you don't, Bob, the Legend enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesFullNameWithApostropheAtEndOfSentence)
|
||||||
|
{
|
||||||
|
auto name = "Bob's Bobber";
|
||||||
|
auto text = "As Bob's Bobber enters, you may pay 2 life. If you don't, Bob's Bobber enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesShortnameEndingWithComma)
|
||||||
|
{
|
||||||
|
auto name = "Bob, the Legend";
|
||||||
|
auto text = "Bob enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesShortnameEndingWithSpace)
|
||||||
|
{
|
||||||
|
auto name = "Bob the Legend";
|
||||||
|
auto text = "Bob enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesMultiWordShortnameEndingWithComma)
|
||||||
|
{
|
||||||
|
auto name = "Bob Dod, the Legend";
|
||||||
|
auto text = "Bob Dod enters tapped.\n"
|
||||||
|
"Whenever Bob Dod attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesMultiWordShortnameEndingWithSpace)
|
||||||
|
{
|
||||||
|
auto name = "Bob Dod the Legend";
|
||||||
|
auto text = "Bob Dod enters tapped.\n"
|
||||||
|
"Whenever Bob Dod attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesShortnameEndingWithSpaceWithUnderscoreAppendedText)
|
||||||
|
{
|
||||||
|
auto name = "Bob the Legend_SL50";
|
||||||
|
auto text = "Bob enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesShortnameEndingWithSpaceWithBracketsAppendedText)
|
||||||
|
{
|
||||||
|
auto name = "Bob the Legend (SL50)";
|
||||||
|
auto text = "Bob enters tapped.\n"
|
||||||
|
"Whenever Bob attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesMultiWordShortnameEndingWithSpaceWithUnderscoreAppendedText)
|
||||||
|
{
|
||||||
|
auto name = "Bob Dod the Legend_SL50";
|
||||||
|
auto text = "Bob Dod enters tapped.\n"
|
||||||
|
"Whenever Bob Dod attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesMultiWordShortnameEndingWithSpaceWithBracketsAppendedText)
|
||||||
|
{
|
||||||
|
auto name = "Bob Dod the Legend (SL50)";
|
||||||
|
auto text = "Bob Dod enters tapped.\n"
|
||||||
|
"Whenever Bob Dod attacks, you win the game.";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, rejectsEmptyText)
|
||||||
|
{
|
||||||
|
auto name = "Vanilla Dude";
|
||||||
|
auto text = "";
|
||||||
|
|
||||||
|
ASSERT_FALSE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, rejectsEntersTappedUnless)
|
||||||
|
{
|
||||||
|
auto name = "Fast Fields";
|
||||||
|
auto text = "This land enters tapped unless you control another land.";
|
||||||
|
|
||||||
|
ASSERT_FALSE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, rejectsWhenNameIsDifferent)
|
||||||
|
{
|
||||||
|
auto name = "Boring Fields";
|
||||||
|
auto text = "Fast Fields enters tapped.";
|
||||||
|
|
||||||
|
ASSERT_FALSE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, rejectsOtherCreaturesEnterTapped)
|
||||||
|
{
|
||||||
|
auto name = "Imposing Guy";
|
||||||
|
auto text = "Other creatures enter tapped.";
|
||||||
|
|
||||||
|
ASSERT_FALSE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, rejectsAbilityGrantingEntersTapped)
|
||||||
|
{
|
||||||
|
auto name = "Imposing Guy";
|
||||||
|
auto text = "Other creatures have \"This creature enters tapped\".";
|
||||||
|
|
||||||
|
ASSERT_FALSE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, parsesEntersTappedAndAbilityGrantingEntersTappedOnSameCard)
|
||||||
|
{
|
||||||
|
auto name = "Imposing Guy";
|
||||||
|
auto text = "This creature enters tapped."
|
||||||
|
"Other creatures have \"This creature enters tapped\".";
|
||||||
|
|
||||||
|
ASSERT_TRUE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ParseCiptTest, rejectsItEntersTappedAndAttacking)
|
||||||
|
{
|
||||||
|
auto name = "Token Maker";
|
||||||
|
auto text = "When Token Maker attacks, create a token. It enters tapped and attacking.";
|
||||||
|
|
||||||
|
ASSERT_FALSE(parseCipt(name, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue