mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-15 06:52:15 -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
153
.github/CONTRIBUTING.md
vendored
153
.github/CONTRIBUTING.md
vendored
|
|
@ -7,32 +7,33 @@
|
|||
<br>
|
||||
|
||||
# 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
|
||||
mostly guidelines, not rules. Use your best judgment, and feel free to propose
|
||||
changes to this document in a pull request.
|
||||
First off, thanks for taking the time and considering to lend a helping hand to our project! 🎉 ❤ ️✨
|
||||
|
||||
> [!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 #
|
||||
|
||||
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](
|
||||
https://www.jetbrains.com/clion/). The program's a great asset and one of the
|
||||
best tools you'll find on these systems, but you're welcomed to use any IDE
|
||||
you most enjoy.
|
||||
https://www.jetbrains.com/clion/). The program is a great asset and one of the
|
||||
best tools you'll find on these systems.
|
||||
|
||||
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://discord.gg/ZASRzKu)
|
||||
[](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.
|
||||
But you're welcomed to use any IDE you enjoy most of course!
|
||||
|
||||
|
||||
# Code Style Guide #
|
||||
|
|
@ -54,7 +55,7 @@ The message will look like this:
|
|||
*** Then commit and push those changes to this branch. ***
|
||||
*** Check our CONTRIBUTING.md file for more details. ***
|
||||
*** ***
|
||||
*** Thank you ❤️ ***
|
||||
*** Thank you ❤️ ***
|
||||
*** ***
|
||||
***********************************************************
|
||||
```
|
||||
|
|
@ -64,7 +65,7 @@ information on our formatting guidelines.
|
|||
|
||||
### 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
|
||||
to help convert it over!
|
||||
|
||||
|
|
@ -78,11 +79,12 @@ or other appropriate conversion.
|
|||
### Formatting ###
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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,
|
||||
`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.
|
||||
|
||||
#### Header files ####
|
||||
#### Header Files ####
|
||||
|
||||
Use header files with the extension `.h` and source files with the extension
|
||||
`.cpp`.
|
||||
|
|
@ -168,10 +170,10 @@ braces around single line statements is preferred.
|
|||
See the following example:
|
||||
```c++
|
||||
int main()
|
||||
{ // function or class: own line
|
||||
if (someCondition) { // control statement: same line
|
||||
doSomething(); // single line statement, braces preferred
|
||||
} else if (someOtherCondition1) { // else goes on the same line as a closing brace
|
||||
{ // function or class: own line
|
||||
if (someCondition) { // control statement: same line
|
||||
doSomething(); // single line statement, braces preferred
|
||||
} else if (someOtherCondition1) { // else goes on the same line as a closing brace
|
||||
for (int i = 0; i < 100; i++) {
|
||||
doSomethingElse();
|
||||
}
|
||||
|
|
@ -234,7 +236,7 @@ mutating objects.)
|
|||
When pointers can't be avoided, try to use a smart pointer of some sort, such
|
||||
as `QScopedPointer`, or, less preferably, `QSharedPointer`.
|
||||
|
||||
### Database migrations ###
|
||||
### Database Migrations ###
|
||||
|
||||
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
||||
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
|
||||
servatrice.sql.
|
||||
|
||||
### Protocol buffer ###
|
||||
### Protocol Buffer ###
|
||||
|
||||
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
|
||||
|
|
@ -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!](
|
||||
https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
||||
|
||||
|
||||
# Reviewing Pull Requests #
|
||||
|
||||
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
|
||||
be included in the next release 👍
|
||||
|
||||
|
||||
# Translations #
|
||||
|
||||
Basic workflow for translations:
|
||||
|
|
@ -294,16 +298,16 @@ Basic workflow for translations:
|
|||
3. Maintainer verifies and merges the change;
|
||||
4. Transifex picks up the new files from GitHub automatically;
|
||||
5. Translators translate the new untranslated strings on Transifex;
|
||||
6. Before a release, a maintainer fetches the updated translations from Transifex.
|
||||
6. Before a release, a maintainer fetches the newest translations from Transifex.
|
||||
|
||||
### Using Translations (for developers) ###
|
||||
|
||||
All user interface strings inside Cockatrice's source code must be written
|
||||
in English (US).
|
||||
Translations to other languages are managed using [Transifex](
|
||||
https://www.transifex.com/projects/p/cockatrice/).
|
||||
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
|
||||
and translated as needed.
|
||||
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
|
||||
the tr() call, also you can add an extra string as a hint for translators:
|
||||
```c++
|
||||
QString message = tr("Everyone draws %n cards", "pop up message", amount);
|
||||
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)
|
||||
|
||||
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>
|
||||
We have an automated process to update our language source files on a schedule
|
||||
and provide the translators on Transifex with the new contents.<br>
|
||||
Maintainers can also manually trigger this on demand.
|
||||
Maintainers can also manually trigger this workflow on demand via GitHub Actions.
|
||||
|
||||
### Maintaining Translations (for maintainers) ###
|
||||
|
||||
|
|
@ -389,27 +393,27 @@ Now you are ready to commit your changes and open a PR.
|
|||
</details>
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
This can be done manually from the Transifex web interface, but it's quite time
|
||||
consuming.
|
||||
|
||||
As an alternative, you can install the Transifex CLI:
|
||||
|
||||
http://docs.transifex.com/developer/client/
|
||||
We utilize the official GitHub integration to push all languages that are 100%
|
||||
translated from Transifex to our GitHub repo automatically.
|
||||
On top, it runs on a quarterly schedule to update changes for incomplete languages.
|
||||
A synchronisation/update can also be triggered manually from the Transifex web interface
|
||||
and a translation treshold can be set.
|
||||
|
||||
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
|
||||
from Transifex to the source code and vice versa.
|
||||
|
||||
### Adding Translations (for translators) ###
|
||||
|
||||
As a translator you can help translate the new strings on [Transifex](
|
||||
https://www.transifex.com/projects/p/cockatrice/).
|
||||
As a translator, you can help to translate new strings on [Transifex](
|
||||
https://www.transifex.com/projects/p/cockatrice/) to your native language.
|
||||
Please have a look at the specific [FAQ for translators](
|
||||
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
||||
|
||||
|
|
@ -419,9 +423,9 @@ https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
|||
### Publishing A New Release ###
|
||||
|
||||
We use [GitHub Releases](https://github.com/Cockatrice/Cockatrice/releases) to
|
||||
publish new stable versions and betas.
|
||||
Whenever a git tag is pushed to the repository github will create a draft
|
||||
release and upload binaries automatically.
|
||||
publish new stable versions and beta releases.
|
||||
Whenever a git tag is pushed to the repository, GitHub will create a draft
|
||||
release and upload binaries from our CI automatically.
|
||||
|
||||
To create a tag, simply do the following:
|
||||
```bash
|
||||
|
|
@ -433,18 +437,16 @@ git push $UPSTREAM $TAG_NAME
|
|||
```
|
||||
|
||||
You should define the variables as such:
|
||||
```
|
||||
`$UPSTREAM` - the remote for git@github.com:Cockatrice/Cockatrice.git
|
||||
`$TAG_NAME` should be formatted as:
|
||||
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
|
||||
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
|
||||
With *MAJ.MIN.PATCH* being the NEXT release version!
|
||||
```
|
||||
- `$UPSTREAM`: the remote for `git@github.com:Cockatrice/Cockatrice.git`
|
||||
- `$TAG_NAME` should be formatted as:
|
||||
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
|
||||
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
|
||||
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,
|
||||
with the binaries being added to the release whenever they are ready.
|
||||
The release is initially a draft, where the path notes can be edited and after
|
||||
all is good and ready it can be published on GitHub.
|
||||
with the binaries being added to the release whenever they are done building in CI.
|
||||
The release is initially a draft, where the release notes can be edited and after
|
||||
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
|
||||
GitHub will be marked as a "Pre-release" automatically.
|
||||
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 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](
|
||||
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
|
||||
release.
|
||||
The preferred flow of operation is:
|
||||
* Just before a release, make sure the version number in CMakeLists.txt is set
|
||||
to the same release version you are about to tag.
|
||||
* This is also the time to change the pretty name in CMakeLists.txt called
|
||||
GIT_TAG_RELEASENAME and commit and push these changes.
|
||||
* Tag the release following the previously described syntax in order to get it
|
||||
correctly built and deployed by CI.
|
||||
* Wait for the configure step to create the release and update the patch
|
||||
notes.
|
||||
* Check on the github actions page for build progress which should be the top
|
||||
listed [here](
|
||||
- Just before a release, make sure the version number in CMakeLists.txt is set
|
||||
to the same release version you are about to tag.
|
||||
- This is also the time to change the pretty name in CMakeLists.txt called
|
||||
`GIT_TAG_RELEASENAME` and commit and push these changes.
|
||||
- Tag the release following the previously described syntax in order to get it
|
||||
correctly built and deployed by CI.
|
||||
- Wait for the configuration step to create the release and update the patch
|
||||
notes.
|
||||
- Check on the GitHub Actions page for build progress which should be the top
|
||||
listed [here](
|
||||
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
|
||||
release are in order and hit the publish button.
|
||||
* After the release is complete, update the CMake version number again to the
|
||||
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
|
||||
one.
|
||||
- When the build has been completed, you can verify if all uploaded files on the
|
||||
draft release are included and hit the publish button.
|
||||
- After the release is complete, update the CMake version number again to the
|
||||
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
|
||||
one.
|
||||
|
||||
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"
|
||||
release channel correctly to the latest stable version as well.
|
||||
should be deleted as well.
|
||||
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
|
||||
|
||||
EXPOSE 4747 4748
|
||||
EXPOSE 4748
|
||||
|
||||
ENTRYPOINT [ "servatrice", "--log-to-console" ]
|
||||
|
|
|
|||
|
|
@ -128,9 +128,9 @@ First, create an image from the Dockerfile<br>
|
|||
`cd /path/to/Cockatrice-Repo/`
|
||||
`docker build -t servatrice .`<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.
|
||||
|
||||
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.
|
||||
```
|
||||
|
||||
>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.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,206 +4,9 @@
|
|||
|
||||
project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
|
||||
set(cockatrice_SOURCES
|
||||
src/game/cards/abstract_card_drag_item.cpp
|
||||
src/game/cards/abstract_card_item.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}
|
||||
)
|
||||
file(GLOB_RECURSE cockatrice_CPP_FILES CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp)
|
||||
|
||||
set(cockatrice_SOURCES ${cockatrice_CPP_FILES} ${VERSION_STRING_CPP})
|
||||
|
||||
add_subdirectory(sounds)
|
||||
add_subdirectory(themes)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -44,14 +44,13 @@
|
|||
# cockatrice_xml.* = false
|
||||
# cockatrice_xml.xml_3_parser = false
|
||||
# cockatrice_xml.xml_4_parser = false
|
||||
# card_info = false
|
||||
# card_list = false
|
||||
|
||||
# stack_zone = false
|
||||
|
||||
flow_layout.debug = false
|
||||
flow_widget.debug = false
|
||||
flow_widget.size.debug = false
|
||||
|
||||
# pixel_map_generator = false
|
||||
|
||||
# filter_string = false
|
||||
# filter_string = false
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
|
|||
aExportDeckDecklist = new QAction(QString(), this);
|
||||
connect(aExportDeckDecklist, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklist()));
|
||||
|
||||
aExportDeckDecklistXyz = new QAction(QString(), this);
|
||||
connect(aExportDeckDecklistXyz, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklistXyz()));
|
||||
|
||||
aAnalyzeDeckDeckstats = new QAction(QString(), this);
|
||||
connect(aAnalyzeDeckDeckstats, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckDeckstats()));
|
||||
|
||||
|
|
@ -63,6 +66,8 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
|
|||
|
||||
analyzeDeckMenu = new QMenu(this);
|
||||
analyzeDeckMenu->addAction(aExportDeckDecklist);
|
||||
analyzeDeckMenu->addAction(aExportDeckDecklistXyz);
|
||||
analyzeDeckMenu->addSeparator();
|
||||
analyzeDeckMenu->addAction(aAnalyzeDeckDeckstats);
|
||||
analyzeDeckMenu->addAction(aAnalyzeDeckTappedout);
|
||||
|
||||
|
|
@ -160,6 +165,7 @@ void DeckEditorMenu::retranslateUi()
|
|||
|
||||
analyzeDeckMenu->setTitle(tr("&Send deck to online service"));
|
||||
aExportDeckDecklist->setText(tr("Create decklist (decklist.org)"));
|
||||
aExportDeckDecklistXyz->setText(tr("Create decklist (decklist.xyz)"));
|
||||
aAnalyzeDeckDeckstats->setText(tr("Analyze deck (deckstats.net)"));
|
||||
aAnalyzeDeckTappedout->setText(tr("Analyze deck (tappedout.net)"));
|
||||
|
||||
|
|
@ -172,13 +178,17 @@ void DeckEditorMenu::refreshShortcuts()
|
|||
aNewDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aNewDeck"));
|
||||
aLoadDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeck"));
|
||||
aSaveDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeck"));
|
||||
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
|
||||
aSaveDeckAs->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckAs"));
|
||||
aLoadDeckFromClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeckFromClipboard"));
|
||||
aEditDeckInClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboard"));
|
||||
aEditDeckInClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboardRaw"));
|
||||
aPrintDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aPrintDeck"));
|
||||
|
||||
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
|
||||
aExportDeckDecklistXyz->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklistXyz"));
|
||||
aAnalyzeDeckDeckstats->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeck"));
|
||||
aAnalyzeDeckTappedout->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeckTappedout"));
|
||||
|
||||
aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose"));
|
||||
|
||||
aSaveDeckToClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboard"));
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public:
|
|||
QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard,
|
||||
*aEditDeckInClipboard, *aEditDeckInClipboardRaw, *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetInfo,
|
||||
*aSaveDeckToClipboardRaw, *aSaveDeckToClipboardRawNoSetInfo, *aPrintDeck, *aExportDeckDecklist,
|
||||
*aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
|
||||
*aExportDeckDecklistXyz, *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
|
||||
QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *editDeckInClipboardMenu, *saveDeckToClipboardMenu;
|
||||
|
||||
void setSaveStatus(bool newStatus);
|
||||
|
|
|
|||
|
|
@ -355,8 +355,8 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
|
|||
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.setDefaultSuffix("cod");
|
||||
dialog.setNameFilters(DeckLoader::fileNameFilters);
|
||||
dialog.selectFile(getDeckList()->getName().trimmed() + ".cod");
|
||||
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
||||
dialog.selectFile(getDeckList()->getName().trimmed());
|
||||
if (!dialog.exec())
|
||||
return false;
|
||||
|
||||
|
|
@ -455,17 +455,12 @@ void AbstractTabDeckEditor::actPrintDeck()
|
|||
dlg->exec();
|
||||
}
|
||||
|
||||
// Action called when export deck to decklist menu item is pressed.
|
||||
void AbstractTabDeckEditor::actExportDeckDecklist()
|
||||
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
|
||||
{
|
||||
// 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
|
||||
if (deck) {
|
||||
if (DeckLoader *const deck = getDeckList()) {
|
||||
// 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.
|
||||
if (QString::compare(decklistUrlString, "", Qt::CaseInsensitive) == 0) {
|
||||
// Show an error if the deck is empty, and return.
|
||||
|
|
@ -481,10 +476,26 @@ void AbstractTabDeckEditor::actExportDeckDecklist()
|
|||
QDesktopServices::openUrl(decklistUrlString);
|
||||
} else {
|
||||
// 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()
|
||||
{
|
||||
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ protected slots:
|
|||
void actSaveDeckToClipboardRawNoSetInfo();
|
||||
void actPrintDeck();
|
||||
void actExportDeckDecklist();
|
||||
void actExportDeckDecklistXyz();
|
||||
void actAnalyzeDeckDeckstats();
|
||||
void actAnalyzeDeckTappedout();
|
||||
|
||||
|
|
@ -119,6 +120,7 @@ protected slots:
|
|||
private:
|
||||
virtual void setDeck(DeckLoader *_deck);
|
||||
void editDeckInClipboard(bool annotated);
|
||||
void exportToDecklistWebsite(DeckLoader::DecklistWebsite website);
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
@ -147,7 +149,7 @@ protected:
|
|||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
||||
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
||||
|
||||
bool modified;
|
||||
bool modified = false;
|
||||
};
|
||||
|
||||
#endif // TAB_GENERIC_DECK_EDITOR_H
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
|||
refreshShortcuts();
|
||||
messageLog->logReplayStarted(gameInfo.game_id());
|
||||
|
||||
this->installEventFilter(this);
|
||||
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--)
|
||||
gameTypes.append(roomGameTypes.find(gameInfo.game_types(i)).value());
|
||||
|
||||
this->installEventFilter(this);
|
||||
QTimer::singleShot(0, this, SLOT(loadLayout()));
|
||||
}
|
||||
|
||||
|
|
@ -1753,6 +1751,27 @@ void TabGame::createMessageDock(bool bReplay)
|
|||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ private slots:
|
|||
void actResetLayout();
|
||||
void freeDocksSize();
|
||||
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
bool eventFilter(QObject *o, QEvent *e) override;
|
||||
void dockVisibleTriggered();
|
||||
void dockFloatingTriggered();
|
||||
|
|
|
|||
|
|
@ -232,22 +232,45 @@ void TabSupervisor::refreshShortcuts()
|
|||
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 (QMessageBox::question(this, tr("Are you sure?"),
|
||||
tr("There are still open games. Are you sure you want to quit?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
|
||||
return false;
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (AbstractTabDeckEditor *tab : deckEditorTabs) {
|
||||
if (!tab->confirmClose())
|
||||
return false;
|
||||
if (!tab->confirmClose()) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ public:
|
|||
return deckEditorTabs;
|
||||
}
|
||||
bool getAdminLocked() const;
|
||||
bool closeRequest();
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
bool switchToGameTabIfAlreadyExists(const int gameId);
|
||||
static void actShowPopup(const QString &message);
|
||||
signals:
|
||||
|
|
@ -192,4 +192,4 @@ private slots:
|
|||
void processNotifyUserEvent(const Event_NotifyUser &event);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -180,6 +180,12 @@ QMap<QString, QPixmap> CountryPixmapGenerator::pmCache;
|
|||
* @param idName id that the tag has to match
|
||||
* @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,
|
||||
const QString &tagName,
|
||||
const QString &attrName,
|
||||
|
|
|
|||
|
|
@ -120,10 +120,10 @@ void ThemeManager::themeChangedSlot()
|
|||
if (dirPath.isEmpty()) {
|
||||
// set default values
|
||||
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
|
||||
handBgBrush = HANDZONE_BG_DEFAULT;
|
||||
tableBgBrush = TABLEZONE_BG_DEFAULT;
|
||||
playerBgBrush = PLAYERZONE_BG_DEFAULT;
|
||||
stackBgBrush = STACKZONE_BG_DEFAULT;
|
||||
brushes[Role::Hand] = HANDZONE_BG_DEFAULT;
|
||||
brushes[Role::Table] = TABLEZONE_BG_DEFAULT;
|
||||
brushes[Role::Player] = PLAYERZONE_BG_DEFAULT;
|
||||
brushes[Role::Stack] = STACKZONE_BG_DEFAULT;
|
||||
} else {
|
||||
// resources
|
||||
QStringList resources;
|
||||
|
|
@ -132,73 +132,58 @@ void ThemeManager::themeChangedSlot()
|
|||
|
||||
// zones bg
|
||||
dir.cd("zones");
|
||||
handBgBrush = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
|
||||
tableBgBrush = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
|
||||
playerBgBrush = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_BG_DEFAULT);
|
||||
stackBgBrush = loadBrush(STACKZONE_BG_NAME, STACKZONE_BG_DEFAULT);
|
||||
brushes[Role::Hand] = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
|
||||
brushes[Role::Table] = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
|
||||
brushes[Role::Player] = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_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();
|
||||
|
||||
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())) {
|
||||
returnBrush = loadExtraBrush(TABLEZONE_BG_NAME + extraNumber, fallbackBrush);
|
||||
tableBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
||||
} else {
|
||||
returnBrush = tableBgBrushesCache.value(extraNumber.toInt());
|
||||
case ThemeManager::Player:
|
||||
return PLAYERZONE_BG_NAME;
|
||||
|
||||
case ThemeManager::Stack:
|
||||
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;
|
||||
|
||||
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;
|
||||
return brushes[role];
|
||||
}
|
||||
|
||||
QBrush ThemeManager::getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
||||
QBrush ThemeManager::getExtraBgBrush(Role role, int zoneId)
|
||||
{
|
||||
QBrush returnBrush;
|
||||
|
||||
if (!playerBgBrushesCache.contains(extraNumber.toInt())) {
|
||||
returnBrush = loadExtraBrush(PLAYERZONE_BG_NAME + extraNumber, fallbackBrush);
|
||||
playerBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
||||
} else {
|
||||
returnBrush = playerBgBrushesCache.value(extraNumber.toInt());
|
||||
if (zoneId <= 0) {
|
||||
return getBgBrush(role);
|
||||
}
|
||||
|
||||
return returnBrush;
|
||||
}
|
||||
QBrushMap &brushCache = brushesCache[role];
|
||||
|
||||
QBrush ThemeManager::getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
||||
{
|
||||
QBrush returnBrush;
|
||||
|
||||
if (!handBgBrushesCache.contains(extraNumber.toInt())) {
|
||||
returnBrush = loadExtraBrush(HANDZONE_BG_NAME + extraNumber, fallbackBrush);
|
||||
handBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
||||
} else {
|
||||
returnBrush = handBgBrushesCache.value(extraNumber.toInt());
|
||||
if (!brushCache.contains(zoneId)) {
|
||||
QBrush brush = loadExtraBrush(roleBgName(role) + QString::number(zoneId), getBgBrush(role));
|
||||
brushCache.insert(zoneId, brush);
|
||||
return brush;
|
||||
}
|
||||
|
||||
return returnBrush;
|
||||
return brushCache.value(zoneId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <QObject>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <array>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(ThemeManagerLog, "theme_manager");
|
||||
|
||||
|
|
@ -22,13 +23,23 @@ class ThemeManager : public QObject
|
|||
public:
|
||||
ThemeManager(QObject *parent = nullptr);
|
||||
|
||||
enum Role
|
||||
{
|
||||
MinRole = 0,
|
||||
Hand = MinRole,
|
||||
Stack,
|
||||
Table,
|
||||
Player,
|
||||
MaxRole = Player,
|
||||
};
|
||||
|
||||
private:
|
||||
QBrush handBgBrush, stackBgBrush, tableBgBrush, playerBgBrush;
|
||||
std::array<QBrush, Role::MaxRole + 1> brushes;
|
||||
QStringMap availableThemes;
|
||||
/*
|
||||
Internal cache for multiple backgrounds
|
||||
*/
|
||||
QBrushMap tableBgBrushesCache, stackBgBrushesCache, playerBgBrushesCache, handBgBrushesCache;
|
||||
std::array<QBrushMap, Role::MaxRole + 1> brushesCache;
|
||||
|
||||
protected:
|
||||
void ensureThemeDirectoryExists();
|
||||
|
|
@ -36,27 +47,10 @@ protected:
|
|||
QBrush loadExtraBrush(QString fileName, QBrush &fallbackBrush);
|
||||
|
||||
public:
|
||||
QBrush &getHandBgBrush()
|
||||
{
|
||||
return handBgBrush;
|
||||
}
|
||||
QBrush &getStackBgBrush()
|
||||
{
|
||||
return stackBgBrush;
|
||||
}
|
||||
QBrush &getTableBgBrush()
|
||||
{
|
||||
return tableBgBrush;
|
||||
}
|
||||
QBrush &getPlayerBgBrush()
|
||||
{
|
||||
return playerBgBrush;
|
||||
}
|
||||
QStringMap &getAvailableThemes();
|
||||
QBrush getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||
QBrush getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||
QBrush getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||
QBrush getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||
|
||||
QBrush &getBgBrush(Role zone);
|
||||
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
||||
protected slots:
|
||||
void themeChangedSlot();
|
||||
signals:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "color_identity_widget.h"
|
||||
|
||||
#include "../../../../../settings/cache_settings.h"
|
||||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
|
@ -17,18 +18,21 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, CardInfoPtr _card) : Q
|
|||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||
setLayout(layout);
|
||||
|
||||
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
|
||||
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
|
||||
|
||||
for (const QString &symbol : symbols) {
|
||||
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol, true);
|
||||
layout->addWidget(manaSymbol);
|
||||
}
|
||||
populateManaSymbolWidgets();
|
||||
}
|
||||
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->setSpacing(5); // Small spacing between icons
|
||||
|
|
@ -36,14 +40,43 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString manaCost) : QW
|
|||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||
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
|
||||
|
||||
for (const QString &symbol : symbols) {
|
||||
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol);
|
||||
layout->addWidget(manaSymbol);
|
||||
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()) {
|
||||
for (const QString symbol : fullColorIdentity) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||
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)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
|
|
|||
|
|
@ -12,13 +12,17 @@ class ColorIdentityWidget : public QWidget
|
|||
public:
|
||||
explicit ColorIdentityWidget(QWidget *parent, CardInfoPtr card);
|
||||
explicit ColorIdentityWidget(QWidget *parent, QString manaCost);
|
||||
void populateManaSymbolWidgets();
|
||||
|
||||
QStringList parseColorIdentity(const QString &manaString);
|
||||
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void toggleUnusedVisibility();
|
||||
|
||||
private:
|
||||
CardInfoPtr card;
|
||||
QString manaCost;
|
||||
QHBoxLayout *layout;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include "../../../../../settings/cache_settings.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
|
||||
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);
|
||||
setGraphicsEffect(opacityEffect);
|
||||
updateOpacity();
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageUnusedColorIdentitiesOpacityChanged, this,
|
||||
&ManaSymbolWidget::updateOpacity);
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::setColorActive(bool active)
|
||||
|
|
@ -26,7 +31,14 @@ void ManaSymbolWidget::setColorActive(bool active)
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "card_info_picture_enlarged_widget.h"
|
||||
|
||||
#include "../../../../settings/cache_settings.h"
|
||||
#include "../../picture_loader/picture_loader.h"
|
||||
|
||||
#include <QPainterPath>
|
||||
|
|
@ -17,6 +18,12 @@ CardInfoPictureEnlargedWidget::CardInfoPictureEnlargedWidget(QWidget *parent)
|
|||
{
|
||||
setWindowFlags(Qt::ToolTip); // Keeps this widget on top of everything
|
||||
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};
|
||||
|
||||
// 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);
|
||||
// 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_item.h"
|
||||
#include "../../../../settings/cache_settings.h"
|
||||
#include "../../../tabs/tab_deck_editor.h"
|
||||
#include "../../../tabs/tab_supervisor.h"
|
||||
#include "../../picture_loader/picture_loader.h"
|
||||
#include "../../window_main.h"
|
||||
|
|
@ -44,6 +43,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool hoverTo
|
|||
hoverTimer = new QTimer(this);
|
||||
hoverTimer->setSingleShot(true);
|
||||
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};
|
||||
|
||||
// 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
|
||||
QStylePainter painter(this);
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
|||
|
||||
auto *upperLayout = new QGridLayout;
|
||||
upperLayout->setObjectName("upperLayout");
|
||||
upperLayout->setContentsMargins(11, 11, 11, 0);
|
||||
|
||||
upperLayout->addWidget(nameLabel, 0, 0);
|
||||
upperLayout->addWidget(nameEdit, 0, 1);
|
||||
|
||||
|
|
@ -314,12 +316,17 @@ DeckLoader *DeckEditorDeckDockWidget::getDeckList()
|
|||
return deckModel->getDeckList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the tab to the state for a blank new tab.
|
||||
*/
|
||||
void DeckEditorDeckDockWidget::cleanDeck()
|
||||
{
|
||||
deckModel->cleanList();
|
||||
nameEdit->setText(QString());
|
||||
commentsEdit->setText(QString());
|
||||
hashLabel->setText(QString());
|
||||
updateBannerCardComboBox();
|
||||
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
||||
}
|
||||
|
||||
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ void DeckEditorFilterDockWidget::filterViewCustomContextMenu(const QPoint &point
|
|||
|
||||
action = menu.addAction(QString("delete"));
|
||||
action->setData(point);
|
||||
connect(&menu, SIGNAL(triggered(QAction *)), this, SLOT(filterRemove(QAction *)));
|
||||
connect(&menu, &QMenu::triggered, this, &DeckEditorFilterDockWidget::filterRemove);
|
||||
menu.exec(filterView->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void DeckEditorFilterDockWidget::filterRemove(QAction *action)
|
||||
void DeckEditorFilterDockWidget::filterRemove(const QAction *action)
|
||||
{
|
||||
QPoint point;
|
||||
QModelIndex idx;
|
||||
|
|
|
|||
|
|
@ -28,10 +28,9 @@ private:
|
|||
KeySignals filterViewKeySignals;
|
||||
QWidget *filterBox;
|
||||
|
||||
void filterRemove(QAction *action);
|
||||
|
||||
private slots:
|
||||
void filterViewCustomContextMenu(const QPoint &point);
|
||||
void filterRemove(const QAction *action);
|
||||
void actClearFilterAll();
|
||||
void actClearFilterOne();
|
||||
void refreshShortcuts();
|
||||
|
|
|
|||
|
|
@ -14,22 +14,21 @@
|
|||
#include <QLabel>
|
||||
|
||||
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
|
||||
: QWidget(_parent), deckList(_deckList)
|
||||
: QWidget(_parent), deckList(nullptr)
|
||||
{
|
||||
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
// Create layout
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(5, 5, 5, 5);
|
||||
layout->setSpacing(5);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setFixedHeight(100);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
|
||||
if (deckList) {
|
||||
connectDeckList(deckList);
|
||||
if (_deckList) {
|
||||
connectDeckList(_deckList);
|
||||
}
|
||||
|
||||
layout->addWidget(flowWidget);
|
||||
|
|
@ -37,10 +36,20 @@ DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_par
|
|||
|
||||
void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
|
||||
{
|
||||
flowWidget->clearLayout();
|
||||
if (deckList) {
|
||||
disconnect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
||||
}
|
||||
|
||||
deckList = _deckList;
|
||||
connect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
|
||||
|
||||
refreshTags();
|
||||
}
|
||||
|
||||
void DeckPreviewDeckTagsDisplayWidget::refreshTags()
|
||||
{
|
||||
flowWidget->clearLayout();
|
||||
|
||||
for (const QString &tag : deckList->getTags()) {
|
||||
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
|
||||
}
|
||||
|
|
@ -51,16 +60,6 @@ void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
|
|||
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
|
||||
*/
|
||||
|
|
@ -161,4 +160,4 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,11 +298,11 @@ QMenu *DeckPreviewWidget::createRightClickMenu()
|
|||
|
||||
connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this,
|
||||
[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); });
|
||||
connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this,
|
||||
[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); });
|
||||
|
||||
menu->addSeparator();
|
||||
|
|
|
|||
|
|
@ -58,6 +58,12 @@ void VisualDeckStorageFolderDisplayWidget::refreshUi()
|
|||
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)
|
||||
{
|
||||
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)
|
||||
auto flags =
|
||||
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()) {
|
||||
allFiles << it.next(); // Add each file path to the list
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <QComboBox>
|
||||
#include <QDirIterator>
|
||||
#include <QMouseEvent>
|
||||
#include <QSpinBox>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), folderWidget(nullptr)
|
||||
|
|
@ -40,6 +41,7 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
|||
refreshButton->setFixedSize(32, 32);
|
||||
connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible);
|
||||
|
||||
// quick settings menu
|
||||
showFoldersCheckBox = new QCheckBox(this);
|
||||
showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
|
||||
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(),
|
||||
&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
|
||||
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
|
||||
|
||||
|
|
@ -84,9 +109,10 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
|||
quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(tagFilterVisibilityCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(tagsOnWidgetsVisibilityCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(bannerCardComboBoxVisibilityCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(searchFolderNamesCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
|
||||
quickSettingsWidget->addSettingsWidget(unusedColorIdentityOpacityWidget);
|
||||
quickSettingsWidget->addSettingsWidget(cardSizeWidget);
|
||||
|
||||
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
|
||||
|
|
@ -159,9 +185,11 @@ void VisualDeckStorageWidget::retranslateUi()
|
|||
showFoldersCheckBox->setText(tr("Show Folders"));
|
||||
tagFilterVisibilityCheckBox->setText(tr("Show Tag Filter"));
|
||||
tagsOnWidgetsVisibilityCheckBox->setText(tr("Show Tags On Deck Previews"));
|
||||
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw not contained Color Identities"));
|
||||
bannerCardComboBoxVisibilityCheckBox->setText(tr("Show Banner Card Selection Option"));
|
||||
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 <QFileSystemModel>
|
||||
|
||||
class QSpinBox;
|
||||
class VisualDeckStorageSearchWidget;
|
||||
class VisualDeckStorageSortWidget;
|
||||
class VisualDeckStorageTagFilterWidget;
|
||||
|
|
@ -64,6 +65,8 @@ private:
|
|||
QCheckBox *tagFilterVisibilityCheckBox;
|
||||
QCheckBox *tagsOnWidgetsVisibilityCheckBox;
|
||||
QCheckBox *searchFolderNamesCheckBox;
|
||||
QLabel *unusedColorIdentitiesOpacityLabel;
|
||||
QSpinBox *unusedColorIdentitiesOpacitySpinBox;
|
||||
QScrollArea *scrollArea;
|
||||
VisualDeckStorageFolderDisplayWidget *folderWidget;
|
||||
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||
return;
|
||||
bClosingDown = true;
|
||||
|
||||
if (!tabSupervisor->closeRequest()) {
|
||||
if (!tabSupervisor->close()) {
|
||||
event->ignore();
|
||||
bClosingDown = false;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
#include <QStringList>
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
const QStringList DeckLoader::fileNameFilters = QStringList()
|
||||
<< QObject::tr("Common deck formats (*.cod *.dec *.dek *.txt *.mwDeck)")
|
||||
<< QObject::tr("All files (*.*)");
|
||||
const QStringList DeckLoader::ACCEPTED_FILE_EXTENSIONS = {"*.cod", "*.dec", "*.dek", "*.txt", "*.mwDeck"};
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -225,6 +226,19 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, FileFormat f
|
|||
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
|
||||
// requires a function to be called for each card, and passes an inner node and a card for
|
||||
// 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
|
||||
QString deckString = "https://www.decklist.org/?";
|
||||
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
|
||||
// Create two strings to pass to function
|
||||
QString mainBoardCards, sideBoardCards;
|
||||
// Set up the struct to call.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,22 @@ public:
|
|||
PlainTextFormat,
|
||||
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:
|
||||
QString lastFileName;
|
||||
|
|
@ -62,7 +77,7 @@ public:
|
|||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
||||
bool saveToFile(const QString &fileName, FileFormat fmt);
|
||||
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
||||
QString exportDeckToDecklist();
|
||||
QString exportDeckToDecklist(DecklistWebsite website);
|
||||
|
||||
void resolveSetNameAndNumberToProviderID();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ DlgLoadDeck::DlgLoadDeck(QWidget *parent) : QFileDialog(parent, tr("Load Deck"))
|
|||
}
|
||||
|
||||
setDirectory(startingDir);
|
||||
setNameFilters(DeckLoader::fileNameFilters);
|
||||
setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
||||
|
||||
connect(this, &DlgLoadDeck::accepted, this, &DlgLoadDeck::actAccepted);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const
|
|||
|
||||
QTextStream stream(&buffer);
|
||||
|
||||
if (deckLoader->loadFromStream_Plain(stream)) {
|
||||
if (deckLoader->loadFromStream_Plain(stream, true)) {
|
||||
if (loadSetNameAndNumberCheckBox->isChecked()) {
|
||||
deckLoader->resolveSetNameAndNumberToProviderID();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "../settings/cache_settings.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QCheckBox>
|
||||
#include <QDebug>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
|
|
@ -162,6 +163,11 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
|||
sortWarning->setLayout(sortWarningLayout);
|
||||
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);
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actSave()));
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(actRestore()));
|
||||
|
|
@ -175,8 +181,9 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
|||
mainLayout->addWidget(enableSomeButton, 2, 1);
|
||||
mainLayout->addWidget(disableSomeButton, 2, 2);
|
||||
mainLayout->addWidget(sortWarning, 3, 1, 1, 2);
|
||||
mainLayout->addWidget(hintsGroupBox, 4, 1, 1, 2);
|
||||
mainLayout->addWidget(buttonBox, 5, 1, 1, 2);
|
||||
mainLayout->addWidget(onlineOnly, 4, 1, 1, 2);
|
||||
mainLayout->addWidget(hintsGroupBox, 5, 1, 1, 2);
|
||||
mainLayout->addWidget(buttonBox, 6, 1, 1, 2);
|
||||
mainLayout->setColumnStretch(1, 1);
|
||||
mainLayout->setColumnStretch(2, 1);
|
||||
|
||||
|
|
@ -239,9 +246,15 @@ void WndSets::rebuildMainLayout(int actionToTake)
|
|||
}
|
||||
}
|
||||
|
||||
void WndSets::includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCards)
|
||||
{
|
||||
includeOnlineOnlyCards = _includeOnlineOnlyCards;
|
||||
}
|
||||
|
||||
void WndSets::actSave()
|
||||
{
|
||||
model->save(CardDatabaseManager::getInstance());
|
||||
SettingsCache::instance().setIncludeOnlineOnlyCards(includeOnlineOnlyCards);
|
||||
PictureLoader::clearPixmapCache();
|
||||
close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ private:
|
|||
void saveHeaderState();
|
||||
void rebuildMainLayout(int actionToTake);
|
||||
bool setOrderIsSorted;
|
||||
bool includeOnlineOnlyCards;
|
||||
enum
|
||||
{
|
||||
NO_SETS_SELECTED,
|
||||
|
|
@ -73,6 +74,7 @@ private slots:
|
|||
void actDisableResetButton(const QString &filterText);
|
||||
void actSort(int index);
|
||||
void actIgnoreWarning();
|
||||
void includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCardsChanged);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "../game/cards/card_database.h"
|
||||
#include "../game/cards/card_database_manager.h"
|
||||
#include "../game/filters/filter_string.h"
|
||||
#include "trice_limits.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
|
|
@ -14,15 +13,17 @@
|
|||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QString _expr, uint _numberOfHits, bool autoPlay)
|
||||
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QStringList exprs, uint _numberOfHits, bool autoPlay)
|
||||
: QDialog(parent)
|
||||
{
|
||||
exprLabel = new QLabel(tr("Card name (or search expressions):"));
|
||||
|
||||
exprEdit = new QLineEdit(this);
|
||||
exprEdit->setFocus();
|
||||
exprEdit->setText(_expr);
|
||||
exprLabel->setBuddy(exprEdit);
|
||||
exprComboBox = new QComboBox(this);
|
||||
exprComboBox->setFocus();
|
||||
exprComboBox->setEditable(true);
|
||||
exprComboBox->setInsertPolicy(QComboBox::InsertAtTop);
|
||||
exprComboBox->insertItems(0, exprs);
|
||||
exprLabel->setBuddy(exprComboBox);
|
||||
|
||||
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
|
||||
numberOfHitsEdit = new QSpinBox(this);
|
||||
|
|
@ -43,7 +44,7 @@ DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QString _expr, uint
|
|||
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(exprLabel);
|
||||
mainLayout->addWidget(exprEdit);
|
||||
mainLayout->addWidget(exprComboBox);
|
||||
mainLayout->addItem(grid);
|
||||
mainLayout->addWidget(autoPlayCheckBox);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
|
|
@ -92,7 +93,7 @@ bool DlgMoveTopCardsUntil::validateMatchExists(const FilterString &filterString)
|
|||
|
||||
void DlgMoveTopCardsUntil::validateAndAccept()
|
||||
{
|
||||
auto movingCardsUntilFilter = FilterString(exprEdit->text());
|
||||
auto movingCardsUntilFilter = FilterString(exprComboBox->currentText());
|
||||
if (!movingCardsUntilFilter.valid()) {
|
||||
QMessageBox::warning(this, tr("Invalid filter"), movingCardsUntilFilter.error(), QMessageBox::Ok);
|
||||
return;
|
||||
|
|
@ -102,12 +103,29 @@ void DlgMoveTopCardsUntil::validateAndAccept()
|
|||
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();
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
#define DLG_MOVE_TOP_CARDS_UNTIL_H
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
|
||||
class FilterString;
|
||||
|
|
@ -15,7 +15,7 @@ class DlgMoveTopCardsUntil : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
QLabel *exprLabel, *numberOfHitsLabel;
|
||||
QLineEdit *exprEdit;
|
||||
QComboBox *exprComboBox;
|
||||
QSpinBox *numberOfHitsEdit;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QCheckBox *autoPlayCheckBox;
|
||||
|
|
@ -25,10 +25,11 @@ class DlgMoveTopCardsUntil : public QDialog
|
|||
|
||||
public:
|
||||
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr,
|
||||
QString expr = QString(),
|
||||
QStringList exprs = QStringList(),
|
||||
uint numberOfHits = 1,
|
||||
bool autoPlay = false);
|
||||
QString getExpr() const;
|
||||
QStringList getExprs() const;
|
||||
uint getNumberOfHits() const;
|
||||
bool isAutoPlay() const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <QStackedWidget>
|
||||
#include <QToolBar>
|
||||
#include <QTranslator>
|
||||
#include <qabstractbutton.h>
|
||||
|
||||
#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"
|
||||
|
|
@ -358,25 +359,8 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
showShortcutsCheckBox.setChecked(settings.getShowShortcuts());
|
||||
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;
|
||||
menuGrid->addWidget(&showShortcutsCheckBox, 0, 0);
|
||||
menuGrid->addWidget(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, 1, 0);
|
||||
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacityLabel, 2, 0);
|
||||
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, 2, 1);
|
||||
|
||||
menuGroupBox = new QGroupBox;
|
||||
menuGroupBox->setLayout(menuGrid);
|
||||
|
|
@ -400,6 +384,9 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
cardScalingCheckBox.setChecked(settings.getScaleCards());
|
||||
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.setRange(0, 80);
|
||||
connect(&verticalCardOverlapPercentBox, SIGNAL(valueChanged(int)), &settings,
|
||||
|
|
@ -419,14 +406,15 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
|
||||
cardsGrid->addWidget(&autoRotateSidewaysLayoutCardsCheckBox, 1, 0, 1, 2);
|
||||
cardsGrid->addWidget(&cardScalingCheckBox, 2, 0, 1, 2);
|
||||
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 3, 0, 1, 2);
|
||||
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 4, 0, 1, 2);
|
||||
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 5, 0, 1, 1);
|
||||
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 5, 1, 1, 1);
|
||||
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 6, 0);
|
||||
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 6, 1);
|
||||
cardsGrid->addWidget(&cardViewExpandedRowsMaxLabel, 7, 0);
|
||||
cardsGrid->addWidget(&cardViewExpandedRowsMaxBox, 7, 1);
|
||||
cardsGrid->addWidget(&roundCardCornersCheckBox, 3, 0, 1, 2);
|
||||
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 4, 0, 1, 2);
|
||||
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 5, 0, 1, 2);
|
||||
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 6, 0, 1, 1);
|
||||
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 6, 1, 1, 1);
|
||||
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 7, 0);
|
||||
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 7, 1);
|
||||
cardsGrid->addWidget(&cardViewExpandedRowsMaxLabel, 8, 0);
|
||||
cardsGrid->addWidget(&cardViewExpandedRowsMaxBox, 8, 1);
|
||||
|
||||
cardsGroupBox = new QGroupBox;
|
||||
cardsGroupBox->setLayout(cardsGrid);
|
||||
|
|
@ -547,10 +535,6 @@ void AppearanceSettingsPage::retranslateUi()
|
|||
|
||||
menuGroupBox->setTitle(tr("Menu settings"));
|
||||
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"));
|
||||
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
||||
|
|
@ -561,6 +545,7 @@ void AppearanceSettingsPage::retranslateUi()
|
|||
bumpSetsWithCardsInDeckToTopCheckBox.setText(
|
||||
tr("Bump sets that the deck contains cards from to the top in the printing selector"));
|
||||
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
|
||||
roundCardCornersCheckBox.setText(tr("Use rounded card corners"));
|
||||
verticalCardOverlapPercentLabel.setText(
|
||||
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));
|
||||
cardViewInitialRowsMaxLabel.setText(tr("Maximum initial height for card view window:"));
|
||||
|
|
|
|||
|
|
@ -102,14 +102,12 @@ private:
|
|||
QLabel minPlayersForMultiColumnLayoutLabel;
|
||||
QLabel maxFontSizeForCardsLabel;
|
||||
QCheckBox showShortcutsCheckBox;
|
||||
QCheckBox visualDeckStorageDrawUnusedColorIdentitiesCheckBox;
|
||||
QLabel visualDeckStorageUnusedColorIdentitiesOpacityLabel;
|
||||
QSpinBox visualDeckStorageUnusedColorIdentitiesOpacitySpinBox;
|
||||
QCheckBox displayCardNamesCheckBox;
|
||||
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
||||
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
||||
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
|
||||
QCheckBox cardScalingCheckBox;
|
||||
QCheckBox roundCardCornersCheckBox;
|
||||
QLabel verticalCardOverlapPercentLabel;
|
||||
QSpinBox verticalCardOverlapPercentBox;
|
||||
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 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
|
||||
"</a>)<br><br>" +
|
||||
tr("Unfortunately there are no download packages available for your operating system. \nYou may have "
|
||||
"to build from source yourself.") +
|
||||
tr("Unfortunately, the automatic updater failed to find a compatible download. \nYou may have to "
|
||||
"manually download the new version.") +
|
||||
"<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)
|
||||
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
|
||||
{
|
||||
setFlag(ItemSendsScenePositionChanges);
|
||||
}
|
||||
|
||||
ArrowTarget::~ArrowTarget()
|
||||
|
|
@ -25,3 +26,16 @@ void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
|
|||
beingPointedAt = _beingPointedAt;
|
||||
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);
|
||||
}
|
||||
|
||||
protected:
|
||||
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "abstract_card_drag_item.h"
|
||||
|
||||
#include "card_database.h"
|
||||
#include "../../settings/cache_settings.h"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QDebug>
|
||||
|
|
@ -32,6 +32,13 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
|||
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
||||
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
prepareGeometryChange();
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
AbstractCardDragItem::~AbstractCardDragItem()
|
||||
|
|
@ -43,7 +50,8 @@ AbstractCardDragItem::~AbstractCardDragItem()
|
|||
QPainterPath AbstractCardDragItem::shape() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
|
|||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::displayCardNamesChanged, this, [this] { update(); });
|
||||
refreshCardInfo();
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
prepareGeometryChange();
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
AbstractCardItem::~AbstractCardItem()
|
||||
|
|
@ -41,7 +48,8 @@ QRectF AbstractCardItem::boundingRect() const
|
|||
QPainterPath AbstractCardItem::shape() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -325,5 +333,5 @@ QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change,
|
|||
update();
|
||||
return value;
|
||||
} else
|
||||
return QGraphicsItem::itemChange(change, value);
|
||||
return ArrowTarget::itemChange(change, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
#include "card_database.h"
|
||||
|
||||
#include "../../client/network/spoiler_background_updater.h"
|
||||
#include "../../client/ui/picture_loader/picture_loader.h"
|
||||
#include "../../settings/cache_settings.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_4.h"
|
||||
|
||||
|
|
@ -20,351 +18,6 @@
|
|||
|
||||
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)
|
||||
{
|
||||
qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
|
||||
|
|
@ -884,64 +537,3 @@ bool CardDatabase::saveCustomTokensToFile()
|
|||
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
|
||||
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
|
||||
#define CARDDATABASE_H
|
||||
|
||||
#include "card_info.h"
|
||||
|
||||
#include <QBasicMutex>
|
||||
#include <QDate>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QSharedPointer>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#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(CardDatabaseLoadingSuccessOrFailureLog, "card_database.loading.success_or_failure");
|
||||
|
||||
class CardDatabase;
|
||||
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);
|
||||
};
|
||||
|
||||
enum LoadStatus
|
||||
{
|
||||
Ok,
|
||||
|
|
@ -523,79 +123,4 @@ signals:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "cockatrice_xml_4.h"
|
||||
|
||||
#include "../../../settings/cache_settings.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
|
@ -124,6 +126,7 @@ QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &x
|
|||
|
||||
void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||
{
|
||||
bool includeOnlineOnlyCards = SettingsCache::instance().getIncludeOnlineOnlyCards();
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
|
|
@ -183,7 +186,17 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
|||
attrName = "picurl";
|
||||
setInfo.setProperty(attrName, attr.value().toString());
|
||||
}
|
||||
_sets[setName].append(setInfo);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
// related cards
|
||||
} else if (xmlName == "related" || xmlName == "reverse-related") {
|
||||
|
|
|
|||
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 &_providerId,
|
||||
int _cardid,
|
||||
bool _revealedCard,
|
||||
CardZone *_zone)
|
||||
: AbstractCardItem(parent, _name, _providerId, _owner, _cardid), zone(_zone), revealedCard(_revealedCard),
|
||||
attacking(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
|
||||
: AbstractCardItem(parent, _name, _providerId, _owner, _cardid), zone(_zone), attacking(false),
|
||||
destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
|
||||
{
|
||||
owner->addCard(this);
|
||||
|
||||
|
|
@ -483,11 +482,9 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
|||
owner->setCardMenu(cardMenu);
|
||||
owner->getGame()->setActiveCard(this);
|
||||
} else if (owner->getCardMenu() == cardMenu) {
|
||||
if (scene() && scene()->selectedItems().isEmpty()) {
|
||||
owner->setCardMenu(nullptr);
|
||||
}
|
||||
owner->setCardMenu(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
|
||||
private:
|
||||
CardZone *zone;
|
||||
bool revealedCard;
|
||||
bool attacking;
|
||||
QMap<int, int> counters;
|
||||
QString annotation;
|
||||
|
|
@ -55,7 +54,6 @@ public:
|
|||
const QString &_name = QString(),
|
||||
const QString &_providerId = QString(),
|
||||
int _cardid = -1,
|
||||
bool revealedCard = false,
|
||||
CardZone *_zone = nullptr);
|
||||
~CardItem() override;
|
||||
void retranslateUi();
|
||||
|
|
@ -85,10 +83,6 @@ public:
|
|||
{
|
||||
owner = _owner;
|
||||
}
|
||||
bool getRevealedCard() const
|
||||
{
|
||||
return revealedCard;
|
||||
}
|
||||
bool getAttacking() const
|
||||
{
|
||||
return attacking;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ DeckViewCard::DeckViewCard(QGraphicsItem *parent,
|
|||
: AbstractCardItem(parent, _name, _providerId, 0, -1), originZone(_originZone), dragItem(0)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
DeckViewCard::~DeckViewCard()
|
||||
|
|
@ -91,7 +97,7 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
|||
pen.setJoinStyle(Qt::MiterJoin);
|
||||
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
||||
painter->setPen(pen);
|
||||
qreal cardRadius = 0.05 * (CARD_WIDTH - 3);
|
||||
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->restore();
|
||||
}
|
||||
|
|
@ -178,7 +184,7 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI
|
|||
{
|
||||
qreal totalTextWidth = getCardTypeTextWidth();
|
||||
|
||||
painter->fillRect(boundingRect(), themeManager->getTableBgBrush());
|
||||
painter->fillRect(boundingRect(), themeManager->getBgBrush(ThemeManager::Table));
|
||||
painter->setPen(QColor(255, 255, 255, 100));
|
||||
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
|
||||
|
||||
|
|
@ -525,4 +531,4 @@ void DeckView::clearDeck()
|
|||
void DeckView::resetSideboardPlan()
|
||||
{
|
||||
deckViewScene->resetSideboardPlan();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,12 +93,7 @@ void PlayerArea::updateBg()
|
|||
|
||||
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QBrush brush = themeManager->getPlayerBgBrush();
|
||||
|
||||
if (playerZoneId > 0) {
|
||||
// If the extra image is not found, load the default one
|
||||
brush = themeManager->getExtraPlayerBgBrush(QString::number(playerZoneId), brush);
|
||||
}
|
||||
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Player, playerZoneId);
|
||||
painter->fillRect(boundingRect(), brush);
|
||||
}
|
||||
|
||||
|
|
@ -1448,19 +1443,20 @@ void Player::actMoveTopCardsUntil()
|
|||
{
|
||||
stopMoveTopCardsUntil();
|
||||
|
||||
DlgMoveTopCardsUntil dlg(game, movingCardsUntilExpr, movingCardsUntilNumberOfHits, movingCardsUntilAutoPlay);
|
||||
DlgMoveTopCardsUntil dlg(game, movingCardsUntilExprs, movingCardsUntilNumberOfHits, movingCardsUntilAutoPlay);
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
movingCardsUntilExpr = dlg.getExpr();
|
||||
auto expr = dlg.getExpr();
|
||||
movingCardsUntilExprs = dlg.getExprs();
|
||||
movingCardsUntilNumberOfHits = dlg.getNumberOfHits();
|
||||
movingCardsUntilAutoPlay = dlg.isAutoPlay();
|
||||
|
||||
if (zones.value("deck")->getCards().empty()) {
|
||||
stopMoveTopCardsUntil();
|
||||
} else {
|
||||
movingCardsUntilFilter = FilterString(movingCardsUntilExpr);
|
||||
movingCardsUntilFilter = FilterString(expr);
|
||||
movingCardsUntilCounter = movingCardsUntilNumberOfHits;
|
||||
movingCardsUntil = true;
|
||||
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_card_id(sourceCard->getId());
|
||||
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
||||
cmd.set_card_provider_id(sourceCard->getProviderId().toStdString());
|
||||
break;
|
||||
|
||||
case CardRelation::TransformInto:
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ private:
|
|||
|
||||
bool movingCardsUntil;
|
||||
QTimer *moveTopCardTimer;
|
||||
QString movingCardsUntilExpr = {};
|
||||
QStringList movingCardsUntilExprs = {};
|
||||
int movingCardsUntilNumberOfHits = 1;
|
||||
bool movingCardsUntilAutoPlay = false;
|
||||
FilterString movingCardsUntilFilter;
|
||||
|
|
|
|||
|
|
@ -78,12 +78,7 @@ QRectF HandZone::boundingRect() const
|
|||
|
||||
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QBrush brush = themeManager->getHandBgBrush();
|
||||
|
||||
if (player->getZoneId() > 0) {
|
||||
// If the extra image is not found, load the default one
|
||||
brush = themeManager->getExtraHandBgBrush(QString::number(player->getZoneId()), brush);
|
||||
}
|
||||
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Hand, player->getZoneId());
|
||||
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)
|
||||
.rotate(90)
|
||||
.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
|
||||
|
|
@ -31,7 +38,8 @@ QRectF PileZone::boundingRect() const
|
|||
QPainterPath PileZone::shape() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,12 +49,7 @@ QRectF StackZone::boundingRect() const
|
|||
|
||||
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QBrush brush = themeManager->getStackBgBrush();
|
||||
|
||||
if (player->getZoneId() > 0) {
|
||||
// If the extra image is not found, load the default one
|
||||
brush = themeManager->getExtraStackBgBrush(QString::number(player->getZoneId()), brush);
|
||||
}
|
||||
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Stack, player->getZoneId());
|
||||
painter->fillRect(boundingRect(), brush);
|
||||
}
|
||||
|
||||
|
|
@ -71,26 +66,25 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
|
|||
cmd.set_target_zone(getName().toStdString());
|
||||
|
||||
int index = 0;
|
||||
if (cards.isEmpty()) {
|
||||
index = 0;
|
||||
} else {
|
||||
|
||||
if (!cards.isEmpty()) {
|
||||
const auto cardCount = static_cast<int>(cards.size());
|
||||
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(),
|
||||
card->boundingRect().height(), true));
|
||||
}
|
||||
|
||||
if (startZone == this) {
|
||||
const auto &dragItem = dragItems.at(0);
|
||||
const auto &card = cards.at(index);
|
||||
if (card != nullptr && dragItem != nullptr && card->getId() == dragItem->getId()) {
|
||||
return;
|
||||
// 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) {
|
||||
const auto &dragItem = dragItems.at(0);
|
||||
const auto &card = cards.at(index);
|
||||
|
||||
if (card->getId() == dragItem->getId()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,8 +103,6 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
|
|||
void StackZone::reorganizeCards()
|
||||
{
|
||||
if (!cards.isEmpty()) {
|
||||
QSet<ArrowItem *> arrowsToUpdate;
|
||||
|
||||
const auto cardCount = static_cast<int>(cards.size());
|
||||
qreal totalWidth = 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());
|
||||
card->setPos(x, y);
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "select_zone.h"
|
||||
|
||||
inline Q_LOGGING_CATEGORY(StackZoneLog, "stack_zone");
|
||||
|
||||
class StackZone : public SelectZone
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
|||
|
|
@ -54,12 +54,7 @@ bool TableZone::isInverted() const
|
|||
|
||||
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QBrush brush = themeManager->getTableBgBrush();
|
||||
|
||||
if (player->getZoneId() > 0) {
|
||||
// If the extra image is not found, load the default one
|
||||
brush = themeManager->getExtraTableBgBrush(QString::number(player->getZoneId()), brush);
|
||||
}
|
||||
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Table, player->getZoneId());
|
||||
painter->fillRect(boundingRect(), brush);
|
||||
|
||||
if (active) {
|
||||
|
|
@ -157,8 +152,6 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
|
|||
|
||||
void TableZone::reorganizeCards()
|
||||
{
|
||||
QSet<ArrowItem *> arrowsToUpdate;
|
||||
|
||||
// Calculate card stack widths so mapping functions work properly
|
||||
computeCardStackWidths();
|
||||
|
||||
|
|
@ -189,23 +182,7 @@ void TableZone::reorganizeCards()
|
|||
qreal childY = y + 5;
|
||||
attachedCard->setPos(childX, childY);
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
|||
if (!cardList.isEmpty()) {
|
||||
for (int i = 0; i < cardList.size(); ++i)
|
||||
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);
|
||||
reorganizeCards();
|
||||
} 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());
|
||||
for (int i = 0; i < number; i++) {
|
||||
CardItem *card = c.at(i);
|
||||
addCard(new CardItem(player, this, card->getName(), card->getProviderId(), card->getId(), revealZone),
|
||||
false, i);
|
||||
addCard(new CardItem(player, this, card->getName(), card->getProviderId(), card->getId()), false, i);
|
||||
}
|
||||
reorganizeCards();
|
||||
}
|
||||
|
|
@ -103,7 +102,7 @@ void ZoneViewZone::zoneDumpReceived(const Response &r)
|
|||
const ServerInfo_Card &cardInfo = resp.zone_info().card_list(i);
|
||||
auto cardName = QString::fromStdString(cardInfo.name());
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,11 +254,13 @@ SettingsCache::SettingsCache()
|
|||
|
||||
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
|
||||
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
|
||||
roundCardCorners = settings->value("cards/roundcardcorners", true).toBool();
|
||||
overrideAllCardArtWithPersonalPreference =
|
||||
settings->value("cards/overrideallcardartwithpersonalpreference", false).toBool();
|
||||
bumpSetsWithCardsInDeckToTop = settings->value("cards/bumpsetswithcardsindecktotop", true).toBool();
|
||||
printingSelectorSortOrder = settings->value("cards/printingselectorsortorder", 1).toInt();
|
||||
printingSelectorCardSize = settings->value("cards/printingselectorcardsize", 100).toInt();
|
||||
includeOnlineOnlyCards = settings->value("cards/includeonlineonlycards", false).toBool();
|
||||
printingSelectorNavigationButtonsVisible =
|
||||
settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
|
||||
visualDeckStorageCardSize = settings->value("interface/visualdeckstoragecardsize", 100).toInt();
|
||||
|
|
@ -661,6 +663,13 @@ void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
|
|||
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)
|
||||
{
|
||||
printingSelectorNavigationButtonsVisible = _navigationButtonsVisible;
|
||||
|
|
@ -728,6 +737,7 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visual
|
|||
visualDeckStorageUnusedColorIdentitiesOpacity = _visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||
settings->setValue("interface/visualdeckstorageunusedcoloridentitiesopacity",
|
||||
visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||
emit visualDeckStorageUnusedColorIdentitiesOpacityChanged(visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||
}
|
||||
|
||||
void SettingsCache::setVisualDeckStoragePromptForConversion(QT_STATE_CHANGED_T _visualDeckStoragePromptForConversion)
|
||||
|
|
@ -1292,6 +1302,16 @@ void SettingsCache::setMaxFontSize(int _max)
|
|||
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()
|
||||
{
|
||||
QString dataPath = getDataPath();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class QSettings;
|
|||
class SettingsCache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void langChanged();
|
||||
void picsPathChanged();
|
||||
|
|
@ -58,12 +59,14 @@ signals:
|
|||
void bumpSetsWithCardsInDeckToTopChanged();
|
||||
void printingSelectorSortOrderChanged();
|
||||
void printingSelectorCardSizeChanged();
|
||||
void includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCards);
|
||||
void printingSelectorNavigationButtonsVisibleChanged();
|
||||
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
||||
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
||||
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
||||
void visualDeckStorageCardSizeChanged();
|
||||
void visualDeckStorageDrawUnusedColorIdentitiesChanged(bool _visible);
|
||||
void visualDeckStorageUnusedColorIdentitiesOpacityChanged(bool value);
|
||||
void visualDeckStorageInGameChanged(bool enabled);
|
||||
void horizontalHandChanged();
|
||||
void handJustificationChanged();
|
||||
|
|
@ -81,6 +84,7 @@ signals:
|
|||
void downloadSpoilerTimeIndexChanged();
|
||||
void downloadSpoilerStatusChanged();
|
||||
void useTearOffMenusChanged(bool state);
|
||||
void roundCardCornersChanged(bool roundCardCorners);
|
||||
|
||||
private:
|
||||
QSettings *settings;
|
||||
|
|
@ -127,6 +131,7 @@ private:
|
|||
bool bumpSetsWithCardsInDeckToTop;
|
||||
int printingSelectorSortOrder;
|
||||
int printingSelectorCardSize;
|
||||
bool includeOnlineOnlyCards;
|
||||
bool printingSelectorNavigationButtonsVisible;
|
||||
int visualDeckStorageSortingOrder;
|
||||
bool visualDeckStorageShowFolders;
|
||||
|
|
@ -201,6 +206,7 @@ private:
|
|||
QList<ReleaseChannel *> releaseChannels;
|
||||
bool isPortableBuild;
|
||||
bool localTime;
|
||||
bool roundCardCorners;
|
||||
|
||||
public:
|
||||
SettingsCache();
|
||||
|
|
@ -401,6 +407,10 @@ public:
|
|||
{
|
||||
return printingSelectorCardSize;
|
||||
}
|
||||
bool getIncludeOnlineOnlyCards() const
|
||||
{
|
||||
return includeOnlineOnlyCards;
|
||||
}
|
||||
bool getPrintingSelectorNavigationButtonsVisible() const
|
||||
{
|
||||
return printingSelectorNavigationButtonsVisible;
|
||||
|
|
@ -731,6 +741,10 @@ public:
|
|||
{
|
||||
return mbDownloadSpoilers;
|
||||
}
|
||||
bool getRoundCardCorners() const
|
||||
{
|
||||
return roundCardCorners;
|
||||
}
|
||||
|
||||
static SettingsCache &instance();
|
||||
void resetPaths();
|
||||
|
|
@ -778,6 +792,7 @@ public slots:
|
|||
void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
|
||||
void setPrintingSelectorSortOrder(int _printingSelectorSortOrder);
|
||||
void setPrintingSelectorCardSize(int _printingSelectorCardSize);
|
||||
void setIncludeOnlineOnlyCards(bool _includeOnlineOnlyCards);
|
||||
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
|
||||
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
|
||||
void setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value);
|
||||
|
|
@ -839,6 +854,7 @@ public slots:
|
|||
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
||||
void setUpdateReleaseChannelIndex(int value);
|
||||
void setMaxFontSize(int _max);
|
||||
void setRoundCardCorners(bool _roundCardCorners);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -173,9 +173,13 @@ private:
|
|||
{"MainWindow/aWatchReplay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Watch Replay..."),
|
||||
parseSequenceString(""),
|
||||
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(""),
|
||||
ShortcutGroup::Deck_Editor)},
|
||||
{"TabDeckEditor/aClearFilterAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Clear All Filters"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Deck_Editor)},
|
||||
|
|
@ -193,9 +197,14 @@ private:
|
|||
{"TabDeckEditor/aEditTokens", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Edit Custom Tokens..."),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Deck_Editor)},
|
||||
{"TabDeckEditor/aExportDeckDecklist", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Deck_Editor)},
|
||||
{"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(""),
|
||||
ShortcutGroup::Deck_Editor)},
|
||||
{"TabDeckEditor/aIncrement", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Card"),
|
||||
parseSequenceString("+"),
|
||||
ShortcutGroup::Deck_Editor)},
|
||||
|
|
|
|||
|
|
@ -548,7 +548,14 @@ bool DeckList::saveToFile_Native(QIODevice *device)
|
|||
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 reEmpty("^\\s*$");
|
||||
|
|
@ -577,7 +584,7 @@ bool DeckList::loadFromStream_Plain(QTextStream &in)
|
|||
{QRegularExpression("æ"), QString("ae")},
|
||||
{QRegularExpression(" ?[|/]+ ?"), QString(" // ")}};
|
||||
|
||||
cleanList();
|
||||
cleanList(preserveMetadata);
|
||||
|
||||
auto inputs = in.readAll().trimmed().split('\n');
|
||||
auto max_line = inputs.size();
|
||||
|
|
@ -752,7 +759,7 @@ InnerDecklistNode *DeckList::getZoneObjFromName(const QString &zoneName)
|
|||
bool DeckList::loadFromFile_Plain(QIODevice *device)
|
||||
{
|
||||
QTextStream in(device);
|
||||
return loadFromStream_Plain(in);
|
||||
return loadFromStream_Plain(in, false);
|
||||
}
|
||||
|
||||
struct WriteToStream
|
||||
|
|
@ -801,12 +808,19 @@ QString DeckList::writeToString_Plain(bool prefixSideboardCards, bool slashTappe
|
|||
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();
|
||||
setName();
|
||||
setComments();
|
||||
setTags();
|
||||
if (!preserveMetadata) {
|
||||
setName();
|
||||
setComments();
|
||||
setTags();
|
||||
}
|
||||
refreshDeckHash();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -351,13 +351,13 @@ public:
|
|||
QString writeToString_Native();
|
||||
bool loadFromFile_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 saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards);
|
||||
bool saveToFile_Plain(QIODevice *device, 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
|
||||
{
|
||||
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/cockatrice_xml_3.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
|
||||
${VERSION_STRING_CPP}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -202,6 +202,9 @@ void SettingsCache::setPrintingSelectorSortOrder(int /* _printingSelectorSortOrd
|
|||
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setIncludeOnlineOnlyCards(bool /* _includeOnlineOnlyCards */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
|
||||
{
|
||||
}
|
||||
|
|
@ -387,6 +390,9 @@ void SettingsCache::setUpdateReleaseChannelIndex(int /* value */)
|
|||
void SettingsCache::setMaxFontSize(int /* _max */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setRoundCardCorners(bool /* _roundCardCorners */)
|
||||
{
|
||||
}
|
||||
|
||||
void PictureLoader::clearPixmapCache(CardInfoPtr /* card */)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
<xs:attribute type="xs:anyURI" name="picURL" use="optional" />
|
||||
<xs:attribute type="xs:string" name="num" use="optional" />
|
||||
<xs:attribute type="xs:string" name="rarity" use="optional" />
|
||||
<xs:attribute type="xs:boolean" name="onlineOnly" use="optional" />
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ services:
|
|||
depends_on:
|
||||
- mysql
|
||||
ports:
|
||||
- "4747:4747"
|
||||
- "4748:4748"
|
||||
entrypoint: "/bin/bash -c 'sleep 10; servatrice --config /tmp/servatrice.ini --log-to-console'"
|
||||
restart: always
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ services:
|
|||
depends_on:
|
||||
- mysql
|
||||
ports:
|
||||
- "4747:4747"
|
||||
- "4748:4748"
|
||||
entrypoint: "/bin/bash -c 'sleep 10; servatrice --config /tmp/servatrice.ini --log-to-console'"
|
||||
restart: always
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ set(oracle_SOURCES
|
|||
src/oraclewizard.cpp
|
||||
src/oracleimporter.cpp
|
||||
src/pagetemplates.cpp
|
||||
src/parsehelpers.cpp
|
||||
src/qt-json/json.cpp
|
||||
../cockatrice/src/game/cards/card_database.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_worker.cpp
|
||||
../cockatrice/src/client/ui/picture_loader/picture_to_load.cpp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<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>
|
||||
<name>IntroPage</name>
|
||||
<message>
|
||||
|
|
@ -63,7 +86,8 @@
|
|||
</message>
|
||||
<message>
|
||||
<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>
|
||||
</message>
|
||||
<message>
|
||||
|
|
@ -247,7 +271,7 @@
|
|||
<context>
|
||||
<name>OracleImporter</name>
|
||||
<message>
|
||||
<location filename="src/oracleimporter.cpp" line="465"/>
|
||||
<location filename="src/oracleimporter.cpp" line="472"/>
|
||||
<source>Dummy set containing tokens</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
@ -283,6 +307,15 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>SaveSetsPage</name>
|
||||
<message>
|
||||
|
|
@ -357,6 +390,21 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>SimpleDownloadFilePage</name>
|
||||
<message>
|
||||
|
|
@ -392,6 +440,34 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>UnZip</name>
|
||||
<message>
|
||||
|
|
@ -537,6 +613,7 @@
|
|||
<name>i18n</name>
|
||||
<message>
|
||||
<location filename="src/oraclewizard.cpp" line="58"/>
|
||||
<location filename="../cockatrice/src/settings/cache_settings.cpp" line="167"/>
|
||||
<source>English</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "oracleimporter.h"
|
||||
|
||||
#include "game/cards/card_database_parser/cockatrice_xml_4.h"
|
||||
#include "parsehelpers.h"
|
||||
#include "qt-json/json.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
|
@ -157,9 +158,7 @@ CardInfoPtr OracleImporter::addCard(QString name,
|
|||
// DETECT CARD POSITIONING INFO
|
||||
|
||||
// cards that enter the field tapped
|
||||
QRegularExpression ciptRegex("( it|" + QRegularExpression::escape(name) +
|
||||
") enters( the battlefield)? tapped(?! unless)");
|
||||
bool cipt = ciptRegex.match(text).hasMatch();
|
||||
bool cipt = parseCipt(name, text);
|
||||
|
||||
bool landscapeOrientation = properties.value("maintype").toString() == "Battle" ||
|
||||
properties.value("layout").toString() == "split" ||
|
||||
|
|
@ -207,12 +206,14 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
|
|||
{
|
||||
// mtgjson name => xml name
|
||||
static const QMap<QString, QString> cardProperties{
|
||||
{"manaCost", "manacost"}, {"manaValue", "cmc"}, {"type", "type"},
|
||||
{"loyalty", "loyalty"}, {"layout", "layout"}, {"side", "side"},
|
||||
{"manaCost", "manacost"}, {"manaValue", "cmc"}, {"type", "type"},
|
||||
{"loyalty", "loyalty"}, {"layout", "layout"}, {"side", "side"},
|
||||
{"convertedManaCost", "cmc"}, // old name for manaValue, for backwards compatibility
|
||||
};
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
static const QRegularExpression meldNameRegex{"then meld them into ([^\\.]*)"};
|
||||
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">
|
||||
<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>
|
||||
<name>IntroPage</name>
|
||||
<message>
|
||||
|
|
@ -62,8 +85,9 @@ e pedine che verranno usate da Cockatrice.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<location filename="src/oraclewizard.cpp" line="287"/>
|
||||
<source>Sets JSON file (%1)</source>
|
||||
<translation>File dei set JSON (%1)</translation>
|
||||
<source>Sets file (%1)</source>
|
||||
<oldsource>Sets JSON file (%1)</oldsource>
|
||||
<translation>File dei set (%1)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/oraclewizard.cpp" line="317"/>
|
||||
|
|
@ -246,7 +270,7 @@ e pedine che verranno usate da Cockatrice.</translation>
|
|||
<context>
|
||||
<name>OracleImporter</name>
|
||||
<message>
|
||||
<location filename="src/oracleimporter.cpp" line="465"/>
|
||||
<location filename="src/oracleimporter.cpp" line="472"/>
|
||||
<source>Dummy set containing tokens</source>
|
||||
<translation>Set finto contenente i token</translation>
|
||||
</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>
|
||||
</message>
|
||||
</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>
|
||||
<name>SaveSetsPage</name>
|
||||
<message>
|
||||
|
|
@ -356,6 +389,23 @@ e pedine che verranno usate da Cockatrice.</translation>
|
|||
<translation>Impossibile salvare il file su %1</translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>SimpleDownloadFilePage</name>
|
||||
<message>
|
||||
|
|
@ -391,6 +441,34 @@ e pedine che verranno usate da Cockatrice.</translation>
|
|||
<translation>Impossibile salvare il file su %1</translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>UnZip</name>
|
||||
<message>
|
||||
|
|
@ -536,6 +614,7 @@ e pedine che verranno usate da Cockatrice.</translation>
|
|||
<name>i18n</name>
|
||||
<message>
|
||||
<location filename="src/oraclewizard.cpp" line="58"/>
|
||||
<location filename="../cockatrice/src/settings/cache_settings.cpp" line="167"/>
|
||||
<source>English</source>
|
||||
<translation>Italiano (Italian)</translation>
|
||||
</message>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from pypb.event_server_identification_pb2 import Event_ServerIdentification as S
|
|||
from pypb.response_pb2 import Response
|
||||
|
||||
HOST = "localhost"
|
||||
PORT = 4747
|
||||
PORT = 4748
|
||||
|
||||
CMD_ID = 1
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ id=1
|
|||
|
||||
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
|
||||
|
||||
; 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)
|
||||
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
|
||||
|
||||
; Server-to-server communication needs a valid certificate in PEM format. Enter its filename in this setting
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
# Build tools
|
||||
cmake
|
||||
cmake-format
|
||||
ninja
|
||||
bash
|
||||
curl
|
||||
git
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
# Debug / Test
|
||||
valgrind
|
||||
gdb
|
||||
clang-tools
|
||||
|
||||
# Compiler
|
||||
gcc
|
||||
|
|
@ -23,4 +25,8 @@
|
|||
qt6.full
|
||||
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(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/cockatrice_xml_3.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
|
||||
carddatabase_test.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/cockatrice_xml_3.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_string.cpp
|
||||
../../cockatrice/src/game/filters/filter_tree.cpp
|
||||
|
|
|
|||
|
|
@ -203,6 +203,9 @@ void SettingsCache::setPrintingSelectorSortOrder(int /* _printingSelectorSortOrd
|
|||
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setIncludeOnlineOnlyCards(bool /* _includeOnlineOnlyCards */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
|
||||
{
|
||||
}
|
||||
|
|
@ -391,6 +394,9 @@ void SettingsCache::setUpdateReleaseChannelIndex(int /* value */)
|
|||
void SettingsCache::setMaxFontSize(int /* _max */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setRoundCardCorners(bool /* _roundCardCorners */)
|
||||
{
|
||||
}
|
||||
|
||||
void PictureLoader::clearPixmapCache(CardInfoPtr /* card */)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ void testEmpty(const QString &clipboard)
|
|||
QString cp(clipboard);
|
||||
DeckList deckList;
|
||||
QTextStream stream(&cp); // text stream requires local copy
|
||||
deckList.loadFromStream_Plain(stream);
|
||||
deckList.loadFromStream_Plain(stream, false);
|
||||
|
||||
ASSERT_TRUE(deckList.getCardList().isEmpty());
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ void testDeck(const QString &clipboard, const Result &result)
|
|||
QString cp(clipboard);
|
||||
DeckList deckList;
|
||||
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.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