Compare commits

..

105 Commits

Author SHA1 Message Date
tooomm
4373ab5e89 typo 2026-01-03 14:09:48 +01:00
tooomm
b748009b52 colon + space 2026-01-03 13:43:15 +01:00
tooomm
0fef7c149b space 2026-01-03 13:31:20 +01:00
tooomm
69a3cecfe7 colon 2026-01-03 13:05:31 +01:00
tooomm
089342ee75 colon + space 2026-01-03 13:00:56 +01:00
RickyRister
4fbb9d9682 [PrintingSelector] optimize amount calculation (#6478) 2026-01-03 01:04:56 -08:00
RickyRister
84aefda486 [DeckListModel] add getCardNodes method (#6484)
* [DeckListModel] add getCardNodes method

* Update one usage
2026-01-02 18:55:27 -08:00
BruebachL
73cc0541f5 [Game] Add shortcuts for same size and hand size - 1 mulligans (#6483)
Took 21 minutes

Took 3 seconds

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-01-03 00:03:11 +01:00
transifex-integration[bot]
bcf3939fee Translate cockatrice/cockatrice_en@source.ts in fr (#6480) 2026-01-02 16:26:16 +01:00
tooomm
2e6f1128bb Docs: Fix search help rendering and open external link in new tab (#6440)
* Use HTML link to open webpage in new tab

* Fix rendering for doxygen
2026-01-02 14:38:25 +01:00
RickyRister
bbd8671e6e [DeckDockWidget] Fix VDE crash due to not mapping proxy index (#6479) 2026-01-02 14:32:22 +01:00
RickyRister
84e6907fa9 [DeckList] Store sideboardPlans by value to fix crash (#6475) 2026-01-02 09:10:41 +01:00
RickyRister
93a4647b04 [DeckList] move SideboardPlan into separate file (#6474) 2026-01-01 16:24:47 -08:00
BruebachL
c1f93b37ab [TabRoom] Add a setting to hide the new filter toolbar (#6469)
* [TabRoom] Add a setting to hide the new filter toolbar

Took 56 minutes

Took 4 seconds

* Proper macro.

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-01-01 14:49:09 +01:00
BruebachL
e7a1f86cbb [View Zone Widget] Properly calculate titleBar close rect on Windows. (#6468) 2026-01-01 14:17:34 +01:00
RickyRister
987fe9c9e2 [DeckDockWidget] clean up grouping and format sync (#6467)
* [DeckDockWidget] clean up grouping and format sync

* refresh legalities in rebuildTree

* extract applyActiveGroupCriteria

* Fix build failure
2025-12-31 23:35:43 -08:00
BruebachL
df9a8b2272 [VDE] Deck Analytics Widgets overhaul (#6463)
* [VDE] Deck Analytics Widgets overhaul

Took 2 minutes

Took 3 minutes

Took 3 minutes

* Qt5 version guards.

Took 33 minutes


Took 3 seconds

* Include QtMath

Took 3 minutes

Took 8 seconds

* Use getCards()

Took 4 minutes

* Non pointer stuff

Took 52 seconds

* Add a newline to the tooltip

Took 2 minutes

Took 27 seconds

* Fix build failure on macOS 15

* Rename some things.

Took 17 minutes

Took 11 seconds


Took 18 seconds

* Address overloads, fix default configuration.

Took 1 hour 9 minutes

Took 8 seconds

* Fix mana curve default config.

Took 4 minutes

* Namespace to Qt libs

Took 5 minutes

* Selection overlay is transparent for mouse events.

Took 2 minutes

* Brace initialize.

Took 8 minutes

* Debian 11.

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: RickyRister <ricky.rister.wang@gmail.com>
2025-12-31 19:45:49 +01:00
tooomm
36d8280765 Readme: Reorder Contribute section (#6435)
* Reorder contribute section

* fix

* Wording updates in related section
2025-12-31 17:57:19 +01:00
tooomm
28c800dd37 Docs: Add & link xsd schema information (#6439)
* Add xsd scheme information

* further references as list
2025-12-31 17:56:24 +01:00
ebbit1q
9f90de2242 change the release channel based on version string (#6447)
* change the release channel based on version string

* Apply suggestions from code review

* format
2025-12-31 17:55:31 +01:00
RickyRister
b2dd8eed3f [TabDeckEditor] Create class to centralize deck state (#6459)
* create new file

* use QSharedPointer in DeckListModel

* [TabDeckEditor] Create class to centralize deck state

* delete method

* update docs
2025-12-31 17:54:47 +01:00
Alex Okonechnikov
0085015ebe manual drag override (#6461)
* manual drag override

* fix styles

* pr comments

* better close button rect calc
2025-12-31 17:48:30 +01:00
RickyRister
db3bdb586b [CardInfo] clean up signatures (#6462) 2025-12-31 04:13:32 -08:00
RickyRister
d722b2569c [DeckListModel] Refactor: general code cleanup (#6460)
* change one usage

* move method

* move format check code

* make group criteria method static

* move method

* make method private

* more comments
2025-12-31 12:01:49 +01:00
RickyRister
968be8a06f Fix bug with next/prev buttons in PrintingSelector (#6453)
* Hacky fix and debug messages

* remove debug

* add todo
2025-12-31 12:00:23 +01:00
RickyRister
daa7db7ce3 [DeckDockWidget] Fix tree unexpanding when changing group by (#6458) 2025-12-29 22:43:34 -08:00
RickyRister
cb2cf31cec [DeckListModel] Clean up recursive updates (#6457) 2025-12-29 22:13:34 -08:00
ebbit1q
ce4a3bf118 compile in debug mode on ubuntu 22.04 (#6418)
* compile in debug mode on ubuntu 22.04

* Update card_info_display_widget.cpp

Use c++ instead of c-style cast

---------

Co-authored-by: BruebachL <44814898+BruebachL@users.noreply.github.com>
2025-12-30 00:16:02 -05:00
Bruno Alexandre Rosa
9d0bb0d51a fix: manage ccache caches manually on macos (#6449)
* fix: manage ccache caches manually on macos

* install ccache

* fix issues shown by bugbot

* readd cache size limit
2025-12-29 17:21:59 +01:00
RickyRister
296866a675 [DeckListModel] Refactor api for offset count (#6454) 2025-12-29 17:19:03 +01:00
RickyRister
96c82a0377 [Refactor] Clean up some PrintingSelector widgets (#6451)
* remove currentZone from PrintingSelector

* don't store constructor args in fields if they're just passed

* simplify some methods

* refactor

* clean up initializeFormats

* more refactoring in CardAmountWidget
2025-12-29 12:03:44 +01:00
RickyRister
ca3f6bba02 [Refactor] Move prev/next card logic out of PrintingSelector (#6450) 2025-12-26 13:29:35 +01:00
RickyRister
70f9982c29 Bump minimum Qt version from 5.8 to 5.15 (#6442)
* Bump minimum Qt version from 5.8 to 5.15

* remove version check

* remove version checks
2025-12-23 09:58:23 -08:00
ebbit1q
521046fb09 Hashing tests (#5026)
* add deck hashing tests

* format

* fix header

* fix cmakelists

* fix test

* add 5 second timeout to test

let the optimising begin

* expand tests

* remove debug message

* manually format

* I installed cmake format from the aur

* use decklist library

* format
2025-12-23 17:48:10 +01:00
RickyRister
421d6b334a [DeckDockWidget] Correctly handle auto-expanding tree (#6446)
* move method

* remove expandAll calls

* update recursiveExpand

* Refactor DeckModel access

* [DeckDockWidget] Correctly handle auto-expand
2025-12-23 16:21:47 +01:00
BruebachL
e7af1bbec9 [EDHRec] New layout for commander details (#6405)
* Stuff

Took 22 minutes

* New layout for commander details.

Took 1 hour 18 minutes

* Update plate to encompass everything, update font sizes.

Took 10 minutes

* Include map.

Took 2 minutes

* Include QSet

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-23 16:00:07 +01:00
RickyRister
01e8e4d589 [DeckDockWidget] Fix swap not auto-expanding tree (#6443) 2025-12-23 15:45:27 +01:00
RickyRister
be17ee1902 [DeckListModel] Refactor to use column num constants (#6441) 2025-12-23 06:07:39 -08:00
dependabot[bot]
e557ae0f2a Bump actions/upload-artifact from 5 to 6 (#6445) 2025-12-22 18:09:50 +01:00
RickyRister
e80f13b78e [DeckDockWidget] Refactor to move down some methods in AbstractTabDeckEditor (#6444)
* move actSwapCard down

* rename method

* move actAddCard down
2025-12-22 05:48:55 -08:00
RickyRister
c12f4e9d2a [DeckListModel] remove more access to underlying decklist for iteration (#6436)
* [DeckListModel] remove more access to underlying decklist for iteration

* remove one last direct iteration of decklist
2025-12-21 16:19:57 -08:00
RickyRister
a0f977e80c [DeckList] refactor: pass DeckList by const ref (#6437)
* [DeckList] refactor: pass DeckList by const ref

* Change getDeckList to return a const ref
2025-12-21 16:19:33 -08:00
tooomm
73a90bdf38 Doxygen: Add bullet points to subpages lists & link webpage on welcome page (#6377)
* add bullet points to subpages

* Link to webpage from welcome page

* Add bullet points to subpages

* grouping

* Add TODO note to card database documentation

Added a TODO note for future updates.

* Fix GH alerts commands to be doxygen compatible
2025-12-20 17:46:13 +01:00
BruebachL
7f1d891e26 [Deprecation] Remove DBConverter from sources. (#6431)
Took 10 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-20 15:25:13 +01:00
RickyRister
d6db21419c [Refactor] Pass around LoadedDeck instead of DeckLoader (#6422) 2025-12-20 13:39:00 +01:00
RickyRister
367507e054 [DeckListModel] Refactor: Don't access underlying decklist for iteration (#6427)
* [DeckListModel] Refactor: Don't access underlying decklist for iteration

* add docs

* extract method
2025-12-20 13:25:30 +01:00
BruebachL
715ee1d6fe Revert "Enable internal documentation in Doxyfile (#6432)" (#6433)
This reverts commit ad06a81765.
2025-12-19 23:55:19 +01:00
tooomm
ad06a81765 Enable internal documentation in Doxyfile (#6432) 2025-12-19 23:51:56 +01:00
BruebachL
ebb02b27b2 [Card DB] Properly pass along set priority controller to parsers (#6430)
* [Card DB] Properly pass along set priority controller to parsers

Took 16 minutes

Took 35 seconds

* More adjustments.

Took 13 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-18 09:01:06 +01:00
BruebachL
d47dc35885 [TabArchidekt] Set game format when importing (#6416)
* [TabArchidekt] Set game format when importing

Took 5 minutes

* Move formats to file.

Took 9 minutes

Took 4 seconds

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-16 13:39:19 +01:00
BruebachL
41aca8467a [CardInfoPicture] Defer enlargedPixmap creation until needed (#6426)
* [CardInfoPicture] Defer enlargedPixmap creation until needed

Took 4 minutes


Took 1 minute

* Disregard const_cast

Took 2 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-16 13:12:51 +01:00
BruebachL
cd44392866 Static helpers. (#6425)
Took 2 minutes


Took 29 seconds

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-16 13:03:14 +01:00
dependabot[bot]
64bb5355ff Bump peter-evans/create-pull-request from 7 to 8 (#6423) 2025-12-15 23:38:49 +01:00
dependabot[bot]
1198db8891 Bump actions/cache from 4 to 5 (#6424) 2025-12-15 23:35:18 +01:00
tooomm
9471adb4f7 Add repo activity with top contributors acknowledgment (#6420) 2025-12-15 22:55:57 +01:00
RickyRister
b29909bdbe [DeckList] Refactor: Create class to RAII underlying tree (#6412)
* [DeckList] Create class to RAII underlying tree

* Update usages

* fixes after rebase

* update docs
2025-12-14 15:56:58 -08:00
RickyRister
589e9a15a6 [DeckFilterString] Add search query for format (#6414)
* [DeckFilterString] Rename file search expression

* [DeckFilterString] Add search query for format
2025-12-15 00:14:19 +01:00
RickyRister
c218a66bcd [DeckFilterString] Rename file search expression (#6413) 2025-12-15 00:14:11 +01:00
tooomm
8485bbe575 Docs: Use Doxygen \todo comments (#6421)
* format todo comments for doxygen

* Mention Todo List & link search
2025-12-15 00:13:16 +01:00
RickyRister
5d9d7d3aa5 [DeckLoader] remove unused private methods (#6417) 2025-12-14 14:26:06 -08:00
BruebachL
ccdda39e78 Deck format legality checker (#6166)
* Deck legality checker.

Took 51 seconds

Took 1 minute

Took 1 minute

Took 5 minutes

Took 3 minutes

* Adjust format parsing.

Took 8 minutes


Took 3 seconds

* toString() the xmlName

Took 4 minutes

* more toStrings()

Took 5 minutes

* Comments

Took 3 minutes

* Layout

Took 2 minutes

* Layout part 2: Electric boogaloo

Took 59 seconds

* Update cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp

Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>

* Move layout.

Took 4 minutes


Took 10 seconds

* Emit deckModified

Took 6 minutes

* Fix qOverloads

Took 4 minutes

* Fix qOverloads

Took 12 seconds

* Consider text and name in a special way.

Took 11 minutes

* Adjust "Any number of" oracle text

Took 5 minutes

* Store allowedCounts by format

Took 15 minutes

Took 6 seconds

* Only restrict vintage.

Took 2 minutes

* Adjust for DBConverter.

Took 6 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
2025-12-13 15:17:55 +01:00
RickyRister
2e2682aad4 [DeckList] Refactor and cleanup methods that iterate over nodes (#6407)
* remove helpers

* create getZoneNodes method

* replace direct calls to getRoot and forEachCard

* remove more non-const uses of forEachCard

* make node getter return const lists

* one more usage

* address comment

* address comment again

* fix hash

* fix hashes (for real this time)
2025-12-12 12:37:44 -08:00
BruebachL
a390c8ada7 [NetworkManager] Set Version string as user agent (#6411)
* [NetworkManager] Set Version string as user agent

Took 13 minutes

* Update in oracle.

Took 14 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-12 11:29:18 +01:00
BruebachL
da70344547 [VDD] Implement ExactMatch Name filter (#6409)
* [VDD] Implement ExactMatch Name filter

Took 7 minutes

Took 4 minutes

* Update cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp

Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
2025-12-12 03:57:18 +01:00
RickyRister
2b690f8c87 [DeckLoader] Extract cardNode functions to own file (#6408)
* [DeckLoader] Extract cardNode functions to own file

* update usages
2025-12-08 00:47:24 -08:00
RickyRister
c8b419888a [DeckLoader] Extract LoadedDeck struct (#6406)
* [DeckLoader] Extract LoadedDeck struct

* update usages

* Move enum to separate namespace

* format

* format

* format
2025-12-07 15:03:52 +01:00
Lily Huang
d3302d521f Fix flipped svg for donator/judge/vip (#6400) 2025-12-06 14:09:55 +01:00
tooomm
5c1bb27d5c README: Add code docs + flathub repo links (#6384)
* Add code docs + flathub repo links

* Update README.md
2025-12-05 23:28:25 +01:00
BruebachL
dde36183ce [VDE] Proper parent lookup syncs group-by box again (#6396)
* [VDE] Proper parent lookup syncs group-by box again

* [VDE] Proper lib inclusion.

* [VDE] Lint.
2025-12-05 23:27:27 +01:00
BruebachL
7c7f2dd8d5 [Doxygen] Logging (#6399)
* [Doxygen] Logging

Took 50 minutes

Took 36 seconds

* [Doxygen] Newline.

Took 2 minutes

* [Doxygen] Add another example.

Took 7 minutes

* [Doxygen] \note and \warning

Took 4 minutes

Took 32 seconds

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-05 18:42:45 +01:00
BruebachL
edb0a954e2 [GameInformation] Check for existence of room for create as judge checkbox (#6398) 2025-12-05 17:26:35 +01:00
BruebachL
0a239712dd [VDD] Add search bar for filters. (#6389)
* [VDD] Add search bar for filters.

* Update cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp

Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>

---------

Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
2025-12-04 23:14:19 +01:00
RickyRister
95c3434205 [TagDisplayWidget] Refactor to just store tags and use signals (#6395) 2025-12-04 10:26:39 -08:00
RickyRister
f0be6972cc [TagsDisplayWidget] cleanup refactor (#6394)
* Make fields private

* Move method to static

* clean up code

* move code
2025-12-04 09:40:24 -08:00
BruebachL
a799cd097a [PrintingSelector] Sync modified and history state on bulk selection (#6379)
* [PrintingSelector] Emit deckModified when using bulk selection

* [PrintingSelector] Hook up history manager.

* [PrintingSelector] Remember card amount.

* Return early.

Took 18 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-12-03 08:23:34 +01:00
RickyRister
b4e3f2cba9 [Oracle] Support importing tokens and spoilers from local file (#6387) 2025-12-03 00:19:56 -05:00
RickyRister
658ae83157 [DeckList] Make DeckList not a QObject (#6383) 2025-12-03 00:18:46 -05:00
BruebachL
d29e72ce72 [CardInfo] Display set short name and collector number in info widget. (#6378)
* [CardInfo] Display set short name and collector number in info widget.

* Lint.

* Use reference.
2025-12-02 22:24:39 +01:00
BruebachL
30cc8ad6f9 [DeckEditor] Expand DeckDock TreeView when adding card through deck editor (#6388)
* [DeckEditor] Expand DeckDock TreeView when adding card through deck editor

* [DeckEditor] Expand first, then set selection.
2025-12-02 22:19:44 +01:00
BruebachL
f0ebd28148 [VDE] Consolidate statistical analysis into a separate object (#6392)
* [VDE] Consolidate statistical analysis into a separate object so multiple widgets can re-use calculations and calculation is only performed once on data change.

* [VDE] Lint.

* [VDE] Move struct up to not confuse compiler.

* [VDE] NoDiscards

* [VDE] Move variables

* [VDE] Lint.
2025-12-02 13:51:08 +01:00
BruebachL
364d0ca52b [EDHRec] Add background plate and "selection highlight" to card display widgets (#6390) 2025-12-01 09:37:48 +01:00
RickyRister
3ff2df2796 [DeckList] Move metadata into struct (#6380)
* [DeckList] Move metadata into struct

* wipe metadata if preserveMetadata is false
2025-11-30 13:09:09 +01:00
RickyRister
d57bec8ec6 [DeckList] Move decklist node classes into new folder (#6381)
* [DeckList] Move decklist node classes into new folder

* reformat

* fix
2025-11-30 13:05:49 +01:00
BruebachL
2b64e65f45 [CardInfoPictureEnlargedWidget] Fix DPR scaling. (#6382) 2025-11-30 13:03:18 +01:00
BruebachL
eab4d435f8 [Feature] TabArchidekt and Archidekt API integration (#6348)
* TabArchidekt and Archidekt API integration.


Took 37 seconds

Took 4 minutes

Took 40 seconds

Took 4 minutes

* Lint.

* Lont.

* Search bar, fancier display, resolve providerId

* Delegate click to base.

* Be explicit for pedantic compilers.

* Liiint.

* Leave them default I guess

* Leave them default I guess

* Small fixes.

* New utility display widgets.

* New style for deck listing.

* Lint.

* Lont.

* Scale things.

* Delegate paint to base.

* Use default Archidekt preview image for decks without featured.

* Consistent sizes.

* Increase font size, qt version guard.

* More version guards.

* Clean up filter layout, use mana symbols.

* Set content margins.

* Refresh on filter change.

* Lint.

* Better elision.

* Query actual new endpoints, new query parameters.

* Doxygen, reorder fields in constructor, readability.

* Update page size doc to min size.

* Update initial min deck size value.

* Add label to page selection.

* Okay, so, people upload a lot of 1 card decks frequently.

* Whoops.

* Add a selection combobox for sorting logic.

* Debounce and limit searches.

* Include.

* Lint.

* Don't imply that Archidekt supports multiple cards/commander names.

* Let's not lambda it and slot it instead.

* Overload.

* Add button to home tab.

Took 8 minutes

* Adjust to selection model change.

Took 5 minutes

* Cleanup auto-generated comments.

Took 8 minutes

* Remember card sizes.

Took 1 minute

* Initialize with correct size.

Took 3 minutes

* Use correct placeholders.

Took 2 minutes

* Style lint.

Took 16 minutes

* Parse double-faced cards correctly.

* Parse double-faced cards correctly.

* Allow TabArchidekt to use VDE group/sort/display buttons

* Lint.

* Indicate that things are clickable.

* Min treshold for nicer display.

* Lint.

* We have good labels at home.

* We do a little linting.

* Qt version guards.

* Qt5 is the devil.

* Update comments.

* Lint comments.

* More doxys.

* One more doxy.

* Lint.

* Update.

* Small fixes.

Took 7 minutes

Took 13 seconds

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-30 08:41:01 +01:00
BruebachL
de13c22552 [Fix-Warnings] Suppress C4100: unreferenced parameter for protobuf files (#6373)
* [Fix-Warnings] Suppress C4100: unreferenced parameter for protobuf files.

* [Fix-Warnings] Compiler specific options.

* [Fix-Warnings] Lint.
2025-11-29 18:58:39 +01:00
BruebachL
8ee7163014 [Printing Selector] Notify deck editor about history changes. (#6364)
Took 44 minutes

Took 2 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-29 18:56:06 +01:00
BruebachL
c5fde071e7 [Cleanup] Unused #includes (#6367)
* [Cleanup] Unused #includes

Took 44 minutes

* [Cleanup] More unused #includes

Took 55 minutes

* [Cleanup] Include QSet

Took 4 minutes

* [Cleanup] Include QDebug in deck_list.cpp

Took 3 minutes

* [Cleanup] Include protocol stuff in servatrice_database_interface.h

Took 3 minutes

* [Cleanup] Include QDialogButtonBox

Took 8 minutes

* [Cleanup] Include QUrl

Took 8 minutes

* [Cleanup] Include QTextOption in header.

Took 3 minutes

* [Cleanup] Include QMap in user_list_manager.h

Took 8 minutes

* [Cleanup] Adjust qjson

Took 8 minutes

* [Cleanup] include button box.

Took 3 minutes

* [Cleanup] Redo fwd declarations.

* [Cleanup] Redo last removed fwd declarations.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-29 18:53:11 +01:00
BruebachL
8abd04dab1 [Fix-Warnings] Remove more redundant empty declarations. (extra semicolons) (#6374) 2025-11-29 14:19:11 +01:00
RickyRister
858361e6d3 [DeckLoader] Refactor last load info into struct (#6366)
* [DeckLoader] Refactor last load info into struct

* Use constant

* [[nodiscard]]

* do discard, I guess.

---------

Co-authored-by: Brübach, Lukas <lukas.bruebach@student.fhws.de>
2025-11-28 23:41:11 +01:00
BruebachL
9ece4bfd9b [Fix-Warnings] Mark const getters as [[nodiscard]] (#6365)
Took 45 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-28 21:38:54 +01:00
BruebachL
a1a3b02d3a Add clearer labeling, more tooltips, condense layout. (#6361)
Took 17 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-28 00:42:46 +01:00
BruebachL
bc2ae6c486 Remember more card sizes. (#6360)
Took 22 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-27 23:41:44 +01:00
BruebachL
587a8bc524 [VDD] Add sorting (#6355)
* [VDD] Add sorting

Took 17 seconds

Took 3 minutes

* Adjust to contents.

Took 13 minutes

* Adjust sort order as well.

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-27 23:31:40 +01:00
BruebachL
122926c6cd Deck Editor owns DeckHistoryManager (#6359)
Took 4 minutes
2025-11-27 23:11:43 +01:00
BruebachL
bac6beeb50 [VDE] Allow visual database display to toggle to table based display. (#6357) 2025-11-27 23:03:30 +01:00
BruebachL
c75a483ee6 [VDE] Add selection model (#6354)
Took 22 minutes

Took 1 minute


Took 17 seconds

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-27 22:16:12 +01:00
BruebachL
1c5bfdbabe Rebuild tree any time setDeckList is called. (#6353)
Took 2 hours 5 minutes

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-27 22:02:27 +01:00
BruebachL
553952132f [Game] Fix CardZoneLogic::clearContents() (#6356)
Took 6 minutes

Took 28 seconds

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-11-27 22:00:35 +01:00
BruebachL
1931eb11a9 [VDD] Change 'filter to most recent sets' default to false (#6358) 2025-11-27 21:56:49 +01:00
ebbit1q
65aef396fb do not allow other players to know which cards are in a player's hand (#6125) 2025-11-26 09:16:50 -05:00
ebbit1q
a21e45ed36 add phase to delete arrows in to protocol (#6159)
* protocol changes

* servatrice changes

* add new setting

* implement client side with static 4 phases

* reading the code explains the code

* add subphases to phase.cpp

* use new subphase definition
2025-11-26 09:16:10 -05:00
dependabot[bot]
adee67115c Bump actions/checkout from 5 to 6 (#6347) 2025-11-24 19:42:21 +01:00
tooomm
aea468bc7f Doxygen: Use newer version (#6345)
* readd properties

* use newer doxygen version + print config update diff

* readd config options

* fix config

* revert cache change

* GITHUB md

* graphviz version

* Add doxygen output to .gitignore
2025-11-23 19:06:00 +01:00
tooomm
621c6a8d73 Doxygen: Improve file structure and includes (#6344) 2025-11-22 19:38:39 +01:00
586 changed files with 14878 additions and 5491 deletions

View File

@@ -122,7 +122,7 @@ if [[ $MAKE_SERVER ]]; then
flags+=("-DWITH_SERVER=1")
fi
if [[ $MAKE_NO_CLIENT ]]; then
flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0" "-DWITH_DBCONVERTER=0")
flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0")
fi
if [[ $MAKE_TEST ]]; then
flags+=("-DTEST=1")
@@ -246,7 +246,7 @@ fi
if [[ $RUNNER_OS == macOS ]]; then
echo "::group::Inspect Mach-O binaries"
for app in cockatrice oracle servatrice dbconverter; do
for app in cockatrice oracle servatrice; do
binary="$GITHUB_WORKSPACE/build/$app/$app.app/Contents/MacOS/$app"
echo "Inspecting $app..."
vtool -show-build "$binary"

View File

@@ -70,7 +70,7 @@ jobs:
- name: Checkout
if: steps.configure.outputs.tag != null
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -142,7 +142,6 @@ jobs:
- distro: Ubuntu
version: 22.04
package: DEB
test: skip # Running tests on all distros is superfluous
- distro: Ubuntu
version: 24.04
@@ -162,11 +161,11 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Restore compiler cache (ccache)
id: ccache_restore
uses: actions/cache/restore@v4
uses: actions/cache/restore@v5
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
@@ -205,7 +204,7 @@ jobs:
- name: Save compiler cache (ccache)
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
path: ${{env.CACHE}}
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
@@ -213,7 +212,7 @@ jobs:
- name: Upload artifact
id: upload_artifact
if: matrix.package != 'skip'
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: ${{matrix.distro}}${{matrix.version}}-package
path: ${{steps.build.outputs.path}}
@@ -342,10 +341,15 @@ jobs:
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
needs: configure
runs-on: ${{matrix.runner}}
env:
CCACHE_DIR: ${{github.workspace}}/.cache/
# Cache size over the entire repo is 10Gi:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CCACHE_SIZE: 500M
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
submodules: recursive
@@ -356,16 +360,20 @@ jobs:
with:
msbuild-architecture: x64
# Using jianmingyong/ccache-action to setup ccache without using brew
# It tries to download a binary of ccache from GitHub Release and falls back to building from source if it fails
- name: Setup ccache
if: matrix.use_ccache == 1 && matrix.os == 'macOS'
run: brew install ccache
- name: Restore compiler cache (ccache)
if: matrix.use_ccache == 1
uses: jianmingyong/ccache-action@v1
id: ccache_restore
uses: actions/cache/restore@v5
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
install-type: "binary"
ccache-key-prefix: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}
max-size: 500M
gh-token: ${{ secrets.GITHUB_TOKEN }}
path: ${{env.CCACHE_DIR}}
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
restore-keys: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-
- name: Install Qt ${{matrix.qt_version}}
uses: jurplel/install-qt-action@v4
@@ -403,6 +411,15 @@ jobs:
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
run: .ci/compile.sh --server --test --vcpkg
- name: Save compiler cache (ccache)
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
uses: actions/cache/save@v5
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
path: ${{env.CCACHE_DIR}}
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
- name: Sign app bundle
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
env:
@@ -450,7 +467,7 @@ jobs:
- name: Upload artifact
id: upload_artifact
if: matrix.make_package
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: ${{matrix.artifact_name}}
path: ${{steps.build.outputs.path}}
@@ -458,7 +475,7 @@ jobs:
- name: Upload pdb database
if: matrix.os == 'Windows'
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: Windows${{matrix.target}}-debug-pdbs
path: |

View File

@@ -24,7 +24,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 20 # should be enough to find merge base

View File

@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Docker metadata
id: metadata

View File

@@ -6,9 +6,9 @@ on:
- '*' # Only re-generate docs when a new tagged version is pushed
pull_request:
paths:
- 'doc/doxygen/**'
- '.github/workflows/documentation-build.yml'
- 'Doxyfile'
- 'doxygen_style.css'
workflow_dispatch:
env:
@@ -21,12 +21,33 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install Doxygen and Graphviz
run: sudo apt-get install -y doxygen graphviz
- name: Install Graphviz
run: |
sudo apt-get install -y graphviz
dot -V
- name: Install Doxygen
uses: ssciwr/doxygen-install@v1
with:
version: "1.14.0"
- name: Update Doxygen Configuration
run: |
git diff Doxyfile
doxygen -u Doxyfile
if git diff --quiet Doxyfile; then
echo "::notice::No config changes in Doxyfile detected."
else
echo "::error::Config changes in Doxyfile detected! Please update the file by running 'doxygen -u Doxyfile'."
echo ""
git diff --color=always Doxyfile
exit 1
fi
- name: Generate Documentation
if: always()
run: doxygen Doxyfile
- name: Deploy to cockatrice.github.io

View File

@@ -20,7 +20,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Pull translated strings from Transifex
uses: transifex/cli-action@v2
@@ -33,7 +33,7 @@ jobs:
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
with:
add-paths: |
cockatrice/translations/*.ts

View File

@@ -20,7 +20,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install lupdate
shell: bash
@@ -57,7 +57,7 @@ jobs:
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
with:
add-paths: |
cockatrice/cockatrice_en@source.ts

View File

@@ -35,7 +35,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6

View File

@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@ compile_commands.json
.cache
.gdb_history
cockatrice/resources/config/qtlogging.ini
docs/

View File

@@ -20,8 +20,6 @@ option(WITH_SERVER "build servatrice" OFF)
option(WITH_CLIENT "build cockatrice" ON)
# Compile oracle
option(WITH_ORACLE "build oracle" ON)
# Compile dbconverter
option(WITH_DBCONVERTER "build dbconverter" ON)
# Compile tests
option(TEST "build tests" OFF)
# Use vcpkg regardless of OS
@@ -356,11 +354,6 @@ if(WITH_ORACLE)
set(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
if(WITH_DBCONVERTER)
add_subdirectory(dbconverter)
set(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
if(TEST)
include(CTest)
add_subdirectory(tests)

View File

@@ -20,7 +20,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /src
COPY . .
RUN mkdir build && cd build && \
cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 && \
cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 && \
make -j$(nproc) && \
make install

View File

@@ -1,5 +1,4 @@
# Doxyfile 1.14.0
# Doxygen Docs: https://www.doxygen.nl/manual
# This file describes the settings to be used by the documentation system
# Doxygen (www.doxygen.org) for a project.
@@ -43,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "Cockatrice"
PROJECT_NAME = Cockatrice
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
@@ -55,7 +54,7 @@ PROJECT_NUMBER = $(COCKATRICE_REF)
# for a project that appears at the top of each page and should give viewers a
# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = A cross-platform virtual tabletop for multiplayer card games
PROJECT_BRIEF = "A cross-platform virtual tabletop for multiplayer card games"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@@ -380,7 +379,7 @@ TOC_INCLUDE_HEADINGS = 6
# The default value is: DOXYGEN.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
MARKDOWN_ID_STYLE = DOXYGEN
MARKDOWN_ID_STYLE = GITHUB
# When enabled Doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
@@ -992,7 +991,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = cockatrice doc/doxygen-extra-pages doc/doxygen-groups libcockatrice_card libcockatrice_deck_list libcockatrice_filters libcockatrice_interfaces libcockatrice_models libcockatrice_network libcockatrice_protocol libcockatrice_rng libcockatrice_settings libcockatrice_utility
INPUT = .
# This tag can be used to specify the character encoding of the source files
# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1032,8 +1031,7 @@ INPUT_FILE_ENCODING =
# provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
FILE_PATTERNS = *.cc \
*.cxx \
*.cxxm \
*.cpp \
@@ -1041,47 +1039,19 @@ FILE_PATTERNS = *.c \
*.ccm \
*.c++ \
*.c++m \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.l \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f18 \
*.f \
*.for \
*.vhd \
*.vhdl \
*.ucf \
*.qsf \
*.ice
*.dox
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
@@ -1096,7 +1066,10 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which Doxygen is
# run.
EXCLUDE = common/lib
EXCLUDE = build/ \
cmake/ \
vcpkg/ \
webclient/
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@@ -1112,7 +1085,8 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
EXCLUDE_PATTERNS = .* \
.*/
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
@@ -1146,7 +1120,7 @@ EXAMPLE_RECURSIVE = NO
# that contain images that are to be included in the documentation (see the
# \image command).
IMAGE_PATH = doc/doxygen-images
IMAGE_PATH = doc/doxygen/images
# The INPUT_FILTER tag can be used to specify a program that Doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -1314,6 +1288,46 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then Doxygen will use the
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which Doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not Doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
# tag is set to YES then Doxygen will add the directory of each input to the
# include path.
# The default value is: YES.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by Doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not Doxygen was
# generated with the -Duse_libclang=ON option for CMake.
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@@ -2608,7 +2622,7 @@ DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10,arrowhead=open, arrowtail=open, arrowsize=0.5"
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10,arrowhead=open, arrowtail=open, arrowsize=0.5"
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
# around nodes set 'shape=plain' or 'shape=plaintext' <a
@@ -2616,7 +2630,7 @@ DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10,arrowhead=open, arrow
# The default value is: shape=box,height=0.2,width=0.4.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
# You can set the path where dot can find font specified with fontname in
# DOT_COMMON_ATTR and others dot attributes.

View File

@@ -44,9 +44,10 @@ Latest <kbd>beta</kbd> version:
# Related Repositories
- [Magic-Token](https://github.com/Cockatrice/Magic-Token): MtG token data to use in Cockatrice
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Script to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) to use in Cockatrice
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official webpage of the Cockatrice project
- [Magic-Token](https://github.com/Cockatrice/Magic-Token): File with MtG token data for use in Cockatrice
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Code to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) for use in Cockatrice
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official Cockatrice webpage
- [io.github.Cockatrice.cockatrice](https://github.com/flathub/io.github.Cockatrice.cockatrice): Configuration of our Linux `flatpak` package hosted at [Flathub](https://flathub.org/en/apps/io.github.Cockatrice.cockatrice)
# Community Resources [![Discord](https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white)](https://discord.gg/3Z9yzmA)
@@ -57,11 +58,28 @@ Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other p
- [Official Discord](https://discord.gg/3Z9yzmA)
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
>[!IMPORTANT]
>For support regarding specific servers, please contact that server's admin/mods and use their dedicated communication channels rather than contacting the team building the software.
> [!IMPORTANT]
> For support regarding specific servers, please contact that server's admin/mods and use their dedicated communication channels rather than contacting the team building the software.
# Contribute
<p>
<a href="#code">Code</a> <b>|</b>
<a href="#documentation-">Documentation</a> <b>|</b>
<a href="#translation-">Translation</a>
</p>
#### Repository Activity
![Cockatrice Repo Analytics](https://repobeats.axiom.co/api/embed/c7cec938789a5bbaeb4182a028b4dbb96db8f181.svg "Cockatrice Repo Analytics by Repobeats")
<details>
<summary><b>Kudos to all our amazing contributors ❤️</b></summary>
<br>
<a href="https://github.com/Cockatrice/Cockatrice/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Cockatrice/Cockatrice" />
</a><br>
<sub><i>Made with <a href="https://contrib.rocks">contrib.rocks</a></i></sub>
</details>
### Code
@@ -75,18 +93,19 @@ This tag is used for issues that we are looking for somebody to pick up. Often t
For both tags, we're willing to provide help to contributors in showing them where and how they can make changes, as well as code reviews for submitted changes.<br>
We'll happily advice on how best to implement a feature, or we can show you where the codebase is doing something similar before you get too far along - put a note on an issue you want to discuss more on!
You can also have a look at our `Todo List` in our [Code Documentation](https://cockatrice.github.io/docs) or search the repo for [`\todo` comments](https://github.com/search?q=repo%3ACockatrice%2FCockatrice%20%5Ctodo&type=code).
### Documentation [![CI Docs](https://github.com/Cockatrice/Cockatrice/actions/workflows/documentation-build.yml/badge.svg?event=push)](https://github.com/Cockatrice/Cockatrice/actions/workflows/documentation-build.yml?query=event%3Apush)
There are various places where useful information for different needs are maintained:
- [Official Code Documentation](https://cockatrice.github.io/docs/)
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki) `Community supported`
- [Official Webpage](https://cockatrice.github.io/)
- [Official README](https://github.com/Cockatrice/Cockatrice/blob/master/README.md) `This file`
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation. We encourage you to improve the documentation by suggesting edits based on this guide.
<details>
<summary><b>Kudos to our amazing contributors ❤️</b></summary>
<br>
<a href="https://github.com/Cockatrice/Cockatrice/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Cockatrice/Cockatrice" />
</a><br>
<sub><i>Made with <a href="https://contrib.rocks">contrib.rocks</a></i></sub>
</details>
### Translations [![Transifex Project](https://img.shields.io/badge/translate-on%20transifex-brightgreen)](https://explore.transifex.com/cockatrice/cockatrice/)
### Translation [![Transifex Project](https://img.shields.io/badge/translate-on%20transifex-brightgreen)](https://explore.transifex.com/cockatrice/cockatrice/)
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd>, <kbd>Oracle</kbd> and <kbd>Webatrice</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/).<br>
@@ -124,8 +143,8 @@ You can then
make package
```
>[!NOTE]
>Detailed compiling instructions can be found in the Cockatrice wiki at [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)
> [!NOTE]
> Detailed compiling instructions can be found in the Cockatrice wiki at [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)
<br>

View File

@@ -42,7 +42,6 @@ tell disk image_name
set position of item "Cockatrice.app" to { 139, 214 }
set position of item "Oracle.app" to { 139, 414 }
set position of item "Servatrice.app" to { 139, 614 }
set position of item "dbconverter.app" to { 1400, 1400 }
set position of item "Applications" to { 861, 414 }
end tell
update without registering applications

View File

@@ -1,12 +1,11 @@
# Find a compatible Qt version
# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, WITH_DBCONVERTER, FORCE_USE_QT5
# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, FORCE_USE_QT5
# Optional Input: QT6_DIR -- Hint as to where Qt6 lives on the system
# Optional Input: QT5_DIR -- Hint as to where Qt5 lives on the system
# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt5, Qt6
# Output: SERVATRICE_QT_MODULES
# Output: COCKATRICE_QT_MODULES
# Output: ORACLE_QT_MODULES
# Output: DBCONVERTER_QT_MODULES
# Output: TEST_QT_MODULES
set(REQUIRED_QT_COMPONENTS Core)
@@ -29,15 +28,12 @@ endif()
if(WITH_ORACLE)
set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
endif()
if(WITH_DBCONVERTER)
set(_DBCONVERTER_NEEDED Network Widgets)
endif()
if(TEST)
set(_TEST_NEEDED Widgets)
endif()
set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_COCKATRICE_NEEDED} ${_ORACLE_NEEDED}
${_DBCONVERTER_NEEDED} ${_TEST_NEEDED}
${_TEST_NEEDED}
)
list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS)
@@ -63,7 +59,7 @@ if(Qt6_FOUND)
endif()
else()
find_package(
Qt5 5.8.0
Qt5 5.15.2
COMPONENTS ${REQUIRED_QT_COMPONENTS}
QUIET HINTS ${Qt5_DIR}
)
@@ -112,7 +108,6 @@ message(DEBUG "QT_LIBRARY_DIR = ${QT_LIBRARY_DIR}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" SERVATRICE_QT_MODULES "${_SERVATRICE_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" COCKATRICE_QT_MODULES "${_COCKATRICE_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" ORACLE_QT_MODULES "${_ORACLE_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" DB_CONVERTER_QT_MODULES "${_DBCONVERTER_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" TEST_QT_MODULES "${_TEST_NEEDED}")
# Core-only export (useful for headless libs)

View File

@@ -213,7 +213,6 @@ ${AndIf} ${FileExists} "$INSTDIR\portable.dat"
Delete "$INSTDIR\uninstall.exe"
Delete "$INSTDIR\cockatrice.exe"
Delete "$INSTDIR\oracle.exe"
Delete "$INSTDIR\dbconverter.exe"
Delete "$INSTDIR\servatrice.exe"
Delete "$INSTDIR\Qt*.dll"
Delete "$INSTDIR\libmysql.dll"

View File

@@ -3,7 +3,7 @@
string(LENGTH "$ENV{MACOS_CERTIFICATE_NAME}" MACOS_CERTIFICATE_NAME_LEN)
if(APPLE AND MACOS_CERTIFICATE_NAME_LEN GREATER 0)
set(APPLICATIONS "cockatrice" "servatrice" "oracle" "dbconverter")
set(APPLICATIONS "cockatrice" "servatrice" "oracle")
foreach(app_name IN LISTS APPLICATIONS)
set(FULL_APP_PATH "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/${app_name}.app")

View File

@@ -19,7 +19,10 @@ set(cockatrice_SOURCES
src/client/settings/card_counter_settings.cpp
src/client/settings/shortcut_treeview.cpp
src/client/settings/shortcuts_settings.cpp
src/interface/deck_loader/card_node_function.cpp
src/interface/deck_loader/deck_file_format.cpp
src/interface/deck_loader/deck_loader.cpp
src/interface/deck_loader/loaded_deck.cpp
src/interface/widgets/dialogs/dlg_connect.cpp
src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp
src/interface/widgets/dialogs/dlg_create_game.cpp
@@ -141,10 +144,31 @@ set(cockatrice_SOURCES
src/interface/widgets/cards/card_size_widget.cpp
src/interface/widgets/cards/deck_card_zone_display_widget.cpp
src/interface/widgets/cards/deck_preview_card_picture_widget.cpp
src/interface/widgets/deck_analytics/abstract_analytics_panel_widget.cpp
src/interface/widgets/deck_analytics/add_analytics_panel_dialog.cpp
src/interface/widgets/deck_analytics/analytics_panel_widget_factory.cpp
src/interface/widgets/deck_analytics/analytics_panel_widget_registrar.cpp
src/interface/widgets/deck_analytics/deck_analytics_widget.cpp
src/interface/widgets/deck_analytics/mana_base_widget.cpp
src/interface/widgets/deck_analytics/mana_curve_widget.cpp
src/interface/widgets/deck_analytics/mana_devotion_widget.cpp
src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp
src/interface/widgets/deck_analytics/resizable_panel.cpp
src/interface/widgets/deck_analytics/analyzer_modules/draw_probability/draw_probability_config.cpp
src/interface/widgets/deck_analytics/analyzer_modules/draw_probability/draw_probability_config_dialog.cpp
src/interface/widgets/deck_analytics/analyzer_modules/draw_probability/draw_probability_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_base/mana_base_config.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_base/mana_base_config_dialog.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_base/mana_base_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_config.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_config_dialog.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_devotion/mana_devotion_config.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_devotion/mana_devotion_config_dialog.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_devotion/mana_devotion_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_config.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_config_dialog.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_single_display_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
@@ -152,14 +176,21 @@ set(cockatrice_SOURCES
src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
src/interface/widgets/deck_editor/deck_state_manager.cpp
src/interface/widgets/general/background_sources.cpp
src/interface/widgets/general/display/background_plate_widget.cpp
src/interface/widgets/general/display/banner_widget.cpp
src/interface/widgets/general/display/bar_widget.cpp
src/interface/widgets/general/display/dynamic_font_size_label.cpp
src/interface/widgets/general/display/dynamic_font_size_push_button.cpp
src/interface/widgets/general/display/labeled_input.cpp
src/interface/widgets/general/display/percent_bar_widget.cpp
src/interface/widgets/general/display/shadow_background_label.cpp
src/interface/widgets/general/display/charts/bars/bar_widget.cpp
src/interface/widgets/general/display/charts/bars/color_bar.cpp
src/interface/widgets/general/display/charts/bars/percent_bar_widget.cpp
src/interface/widgets/general/display/charts/bars/bar_chart_widget.cpp
src/interface/widgets/general/display/charts/bars/bar_chart_background_widget.cpp
src/interface/widgets/general/display/charts/bars/segmented_bar_widget.cpp
src/interface/widgets/general/display/charts/pies/color_pie.cpp
src/interface/widgets/general/home_styled_button.cpp
src/interface/widgets/general/home_widget.cpp
src/interface/widgets/general/layout_containers/flow_widget.cpp
@@ -196,12 +227,14 @@ set(cockatrice_SOURCES
src/interface/widgets/utility/sequence_edit.cpp
src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp
src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp
src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
@@ -220,6 +253,20 @@ set(cockatrice_SOURCES
src/interface/window_main.cpp
src/main.cpp
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp
src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
@@ -265,6 +312,10 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
src/interface/key_signals.cpp
src/interface/logger.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
)
add_subdirectory(sounds)

View File

@@ -1,6 +1,10 @@
[Rules]
# The default log level is info
*.debug = false
#*.info = true
#*.warning = true
#*.critical = true
#*.fatal = true
# Uncomment a rule to see debug level logs for that category,
# or set <category> = false to disable logging

View File

@@ -1,11 +1,13 @@
@page deck_search_syntax_help Deck Search Syntax Help
## Deck Search Syntax Help
-----
The search bar recognizes a set of special commands.<br>
In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all
searches are case insensitive.
<dl>
<dt>Display Name (The deck name, or the filename if the deck name isn't set):</dt>
<dd>[red deck wins](#red deck wins) <small>(Any deck with a display name containing the words red, deck, and wins)</small></dd>
<dd>["red deck wins"](#%22red deck wins%22) <small>(Any deck with a display name containing the exact phrase "red deck wins")</small></dd>
@@ -15,15 +17,18 @@ searches are case insensitive.
<dd>[n:red n:deck n:wins](#n:red n:deck n:wins) <small>(Any deck with a name containing the words red, deck, and wins)</small></dd>
<dd>[n:"red deck wins"](#n:%22red deck wins%22) <small>(Any deck with a name containing the exact phrase "red deck wins")</small></dd>
<dt><u>F</u>ile Name:</dt>
<dd>[f:aggro](#f:aggro) <small>(Any deck with a filename containing the word aggro)</small></dd>
<dd>[f:red f:deck f:wins](#f:red f:deck f:wins) <small>(Any deck with a filename containing the words red, deck, and wins)</small></dd>
<dd>[f:"red deck wins"](#f:%22red deck wins%22) <small>(Any deck with a filename containing the exact phrase "red deck wins")</small></dd>
<dt><u>F</u>ile <u>N</u>ame:</dt>
<dd>[fn:aggro](#fn:aggro) <small>(Any deck with a filename containing the word aggro)</small></dd>
<dd>[fn:red fn:deck fn:wins](#fn:red fn:deck fn:wins) <small>(Any deck with a filename containing the words red, deck, and wins)</small></dd>
<dd>[fn:"red deck wins"](#fn:%22red deck wins%22) <small>(Any deck with a filename containing the exact phrase "red deck wins")</small></dd>
<dt>Relative <u>P</u>ath (starting from the deck folder):</dt>
<dd>[p:aggro](#p:aggro) <small>(Any deck that has "aggro" somewhere in its relative path)</small></dd>
<dd>[p:edh/](#p:edh/) <small>(Any deck with "edh/" in its relative path, A.K.A. decks in the "edh" folder)</small></dd>
<dt><u>F</u>ormat:</dt>
<dd>[f:standard](#f:standard) <small>(Any deck with format set to standard)</small></dd>
<dt>Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):</dt>
<dd><a href="#[[plains]]">[[plains]]</a> <small>(Any deck that contains at least one card with "plains" in its name)</small></dd>
<dd><a href="#[[t:legendary]]">[[t:legendary]]</a> <small>(Any deck that contains at least one legendary)</small></dd>

View File

@@ -1,10 +1,12 @@
@page search_syntax_help Search Syntax Help
## Search Syntax Help
-----
The search bar recognizes a set of special commands similar to some other card databases.<br>
In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all searches are case insensitive.
<dl>
<dt>Name:</dt>
<dd>[birds of paradise](#birds of paradise) <small>(Any card name containing the words birds, of, and paradise)</small></dd>
<dd>["birds of paradise"](#%22birds of paradise%22) <small>(Any card name containing the exact phrase "birds of paradise")</small></dd>

View File

@@ -350,11 +350,11 @@
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="right" />
id="left" />
<path
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="left"
id="right"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient3);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.77952756;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -321,11 +321,11 @@
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="right" />
id="left" />
<path
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="left"
id="right"
inkscape:connector-curvature="0" />
<path
d="m 46.656521,12.167234 18.055171,18.054184 a 6.6081919,6.6078288 0 0 1 -0.126303,9.352065 6.6804126,6.6800456 0 0 1 -8.233169,1.011048 l -7.944268,7.943843 6.463762,6.445343 a 6.9331851,6.9328042 0 0 1 5.741536,2.022073 l 28.057729,28.092294 a 6.9962797,6.9958953 0 0 1 -9.894222,9.893685 L 50.719018,66.907526 A 7.0595711,7.0591833 0 0 1 49.18433,59.270613 l -5.741527,-5.741238 -7.944298,7.943843 A 6.716523,6.7161541 0 0 1 25.134866,69.832263 L 7.079684,51.778091 a 6.716523,6.7161541 0 0 1 8.39566,-10.345064 L 36.31101,20.59853 a 6.716523,6.7161541 0 0 1 10.345612,-8.431329 z"

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -340,11 +340,11 @@
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="right" />
id="left" />
<path
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="left"
id="right"
inkscape:connector-curvature="0" />
<path
sodipodi:type="star"

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -2,13 +2,13 @@
#include <QDesktopServices>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QUrlQuery>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <version_string.h>
DeckStatsInterface::DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent)
: QObject(parent), cardDatabase(_cardDatabase)
@@ -43,31 +43,32 @@ void DeckStatsInterface::queryFinished(QNetworkReply *reply)
deleteLater();
}
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
void DeckStatsInterface::getAnalyzeRequestData(const DeckList &deck, QByteArray &data)
{
DeckList deckWithoutTokens;
copyDeckWithoutTokens(*deck, deckWithoutTokens);
copyDeckWithoutTokens(deck, deckWithoutTokens);
QUrl params;
QUrlQuery urlQuery;
urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
urlQuery.addQueryItem("decktitle", deck->getName());
urlQuery.addQueryItem("decktitle", deck.getName());
params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved).toUtf8());
data.append(params.query(QUrl::EncodeReserved).toUtf8());
}
void DeckStatsInterface::analyzeDeck(DeckList *deck)
void DeckStatsInterface::analyzeDeck(const DeckList &deck)
{
QByteArray data;
getAnalyzeRequestData(deck, &data);
getAnalyzeRequestData(deck, data);
QNetworkRequest request(QUrl("https://deckstats.net/index.php"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
manager->post(request, data);
}
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
void DeckStatsInterface::copyDeckWithoutTokens(const DeckList &source, DeckList &destination)
{
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());

View File

@@ -7,7 +7,6 @@
#ifndef DECKSTATS_INTERFACE_H
#define DECKSTATS_INTERFACE_H
#include <QObject>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/deck_list/deck_list.h>
@@ -29,15 +28,15 @@ private:
* closest non-token card instead. So we construct a new deck which has no
* tokens.
*/
void copyDeckWithoutTokens(DeckList &source, DeckList &destination);
void copyDeckWithoutTokens(const DeckList &source, DeckList &destination);
private slots:
void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
public:
explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(DeckList *deck);
void analyzeDeck(const DeckList &deck);
};
#endif

View File

@@ -2,13 +2,13 @@
#include <QDesktopServices>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QUrlQuery>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <version_string.h>
TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent)
: QObject(parent), cardDatabase(_cardDatabase)
@@ -67,32 +67,33 @@ void TappedOutInterface::queryFinished(QNetworkReply *reply)
deleteLater();
}
void TappedOutInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
void TappedOutInterface::getAnalyzeRequestData(const DeckList &deck, QByteArray &data)
{
DeckList mainboard, sideboard;
copyDeckSplitMainAndSide(*deck, mainboard, sideboard);
copyDeckSplitMainAndSide(deck, mainboard, sideboard);
QUrl params;
QUrlQuery urlQuery;
urlQuery.addQueryItem("name", deck->getName());
urlQuery.addQueryItem("name", deck.getName());
urlQuery.addQueryItem("mainboard", mainboard.writeToString_Plain(false, true));
urlQuery.addQueryItem("sideboard", sideboard.writeToString_Plain(false, true));
params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved).toUtf8());
data.append(params.query(QUrl::EncodeReserved).toUtf8());
}
void TappedOutInterface::analyzeDeck(DeckList *deck)
void TappedOutInterface::analyzeDeck(const DeckList &deck)
{
QByteArray data;
getAnalyzeRequestData(deck, &data);
getAnalyzeRequestData(deck, data);
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
manager->post(request, data);
}
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard)
{
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());

View File

@@ -7,8 +7,6 @@
#ifndef TAPPEDOUT_INTERFACE_H
#define TAPPEDOUT_INTERFACE_H
#include <QLoggingCategory>
#include <QObject>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/deck_list/deck_list.h>
@@ -32,14 +30,14 @@ private:
QNetworkAccessManager *manager;
CardDatabase &cardDatabase;
void copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard);
void copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard);
private slots:
void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
public:
explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(DeckList *deck);
void analyzeDeck(const DeckList &deck);
};
#endif

View File

@@ -6,6 +6,8 @@
#ifndef INTERFACE_JSON_DECK_PARSER_H
#define INTERFACE_JSON_DECK_PARSER_H
#include "../../../interface/deck_loader/card_node_function.h"
#include "../../../interface/deck_loader/deck_loader.h"
#include <QJsonArray>
@@ -16,21 +18,21 @@ class IJsonDeckParser
public:
virtual ~IJsonDeckParser() = default;
virtual DeckLoader *parse(const QJsonObject &obj) = 0;
virtual DeckList parse(const QJsonObject &obj) = 0;
};
class ArchidektJsonParser : public IJsonDeckParser
{
public:
DeckLoader *parse(const QJsonObject &obj) override
DeckList parse(const QJsonObject &obj) override
{
DeckLoader *loader = new DeckLoader(nullptr);
DeckList deckList;
QString deckName = obj.value("name").toString();
QString deckDescription = obj.value("description").toString();
loader->getDeckList()->setName(deckName);
loader->getDeckList()->setComments(deckDescription);
deckList.setName(deckName);
deckList.setComments(deckDescription);
QString outputText;
QTextStream outStream(&outputText);
@@ -47,25 +49,25 @@ public:
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
}
loader->getDeckList()->loadFromStream_Plain(outStream, false);
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
deckList.loadFromStream_Plain(outStream, false);
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
return loader;
return deckList;
}
};
class MoxfieldJsonParser : public IJsonDeckParser
{
public:
DeckLoader *parse(const QJsonObject &obj) override
DeckList parse(const QJsonObject &obj) override
{
DeckLoader *loader = new DeckLoader(nullptr);
DeckList deckList;
QString deckName = obj.value("name").toString();
QString deckDescription = obj.value("description").toString();
loader->getDeckList()->setName(deckName);
loader->getDeckList()->setComments(deckDescription);
deckList.setName(deckName);
deckList.setComments(deckDescription);
QString outputText;
QTextStream outStream(&outputText);
@@ -94,8 +96,8 @@ public:
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
}
loader->getDeckList()->loadFromStream_Plain(outStream, false);
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
deckList.loadFromStream_Plain(outStream, false);
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
QJsonObject commandersObj = obj.value("commanders").toObject();
if (!commandersObj.isEmpty()) {
@@ -106,12 +108,12 @@ public:
QString collectorNumber = cardData.value("cn").toString();
QString providerId = cardData.value("scryfall_id").toString();
loader->getDeckList()->setBannerCard({commanderName, providerId});
loader->getDeckList()->addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
deckList.setBannerCard({commanderName, providerId});
deckList.addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
}
}
return loader;
return deckList;
}
};

View File

@@ -4,18 +4,17 @@
#include "../../../../main.h"
#include "../../../settings/cache_settings.h"
#include <QApplication>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QLocale>
#include <QMessageBox>
#include <QNetworkReply>
#include <QUrl>
#include <QtConcurrent>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <version_string.h>
#define SPOILERS_STATUS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/SpoilerSeasonEnabled"
#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml"
@@ -41,7 +40,9 @@ void SpoilerBackgroundUpdater::startSpoilerDownloadProcess(QString url, bool sav
void SpoilerBackgroundUpdater::downloadFromURL(QUrl url, bool saveResults)
{
auto *nam = new QNetworkAccessManager(this);
QNetworkReply *reply = nam->get(QNetworkRequest(url));
auto request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
QNetworkReply *reply = nam->get(request);
if (saveResults) {
// This will write out to the file (used for spoiler.xml)

View File

@@ -22,7 +22,7 @@ public:
inline QString getCardUpdaterBinaryName()
{
return "oracle";
};
}
QByteArray getHash(const QString fileName);
QByteArray getHash(QByteArray data);
static bool deleteSpoilerFile();

View File

@@ -1,6 +1,5 @@
#include "update_downloader.h"
#include <QDebug>
#include <QUrl>
UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(nullptr)

View File

@@ -7,9 +7,7 @@
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
#define COCKATRICE_UPDATEDOWNLOADER_H
#include <QDate>
#include <QObject>
#include <QUrl>
#include <QtNetwork>
class UpdateDownloader : public QObject

View File

@@ -2,6 +2,7 @@
#include "../network/update/client/release_channel.h"
#include "card_counter_settings.h"
#include "version_string.h"
#include <QAbstractListModel>
#include <QApplication>
@@ -198,7 +199,13 @@ SettingsCache::SettingsCache()
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
if (settings->contains("personal/startupUpdateCheck")) {
checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
} else if (QString(VERSION_STRING).contains("custom", Qt::CaseInsensitive)) {
checkUpdatesOnStartup = false; // do not run auto updater on custom version
} else {
checkUpdatesOnStartup = true; // default to run auto updater
}
startupCardUpdateCheckPromptForUpdate =
settings->value("personal/startupCardUpdateCheckPromptForUpdate", true).toBool();
startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
@@ -206,7 +213,15 @@ SettingsCache::SettingsCache()
lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt();
if (settings->contains("personal/updatereleasechannel")) {
updateReleaseChannel = settings->value("personal/updatereleasechannel").toInt();
} else if (QString(VERSION_STRING).contains("beta", Qt::CaseInsensitive)) {
// default to beta if this is a beta release
updateReleaseChannel = 1;
} else {
updateReleaseChannel = 0; // stable
}
lang = settings->value("personal/lang").toString();
keepalive = settings->value("personal/keepalive", 3).toInt();
@@ -261,6 +276,7 @@ SettingsCache::SettingsCache()
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
clickPlaysAllSelected = settings->value("interface/clickPlaysAllSelected", true).toBool();
playToStack = settings->value("interface/playtostack", true).toBool();
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray();
@@ -272,6 +288,7 @@ SettingsCache::SettingsCache()
focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
showGameSelectorFilterToolbar = settings->value("menu/showgameselectorfiltertoolbar", true).toBool();
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
roundCardCorners = settings->value("cards/roundcardcorners", true).toBool();
overrideAllCardArtWithPersonalPreference =
@@ -309,10 +326,15 @@ SettingsCache::SettingsCache()
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
visualDatabaseDisplayFilterToMostRecentSetsEnabled =
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", false).toBool();
visualDatabaseDisplayFilterToMostRecentSetsAmount =
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
visualDeckEditorCardSize = settings->value("interface/visualdeckeditorcardsize", 100).toInt();
visualDatabaseDisplayCardSize = settings->value("interface/visualdatabasedisplaycardsize", 100).toInt();
edhrecCardSize = settings->value("interface/edhreccardsize", 100).toInt();
archidektPreviewSize = settings->value("interface/archidektpreviewsize", 100).toInt();
horizontalHand = settings->value("hand/horizontal", true).toBool();
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
@@ -664,6 +686,12 @@ void SettingsCache::setPlayToStack(QT_STATE_CHANGED_T _playToStack)
settings->setValue("interface/playtostack", playToStack);
}
void SettingsCache::setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases)
{
doNotDeleteArrowsInSubPhases = static_cast<bool>(_doNotDeleteArrowsInSubPhases);
settings->setValue("interface/doNotDeleteArrowsInSubPhases", doNotDeleteArrowsInSubPhases);
}
void SettingsCache::setStartingHandSize(int _startingHandSize)
{
startingHandSize = _startingHandSize;
@@ -688,6 +716,13 @@ void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
settings->setValue("menu/showshortcuts", showShortcuts);
}
void SettingsCache::setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar)
{
showGameSelectorFilterToolbar = static_cast<bool>(_showGameSelectorFilterToolbar);
settings->setValue("menu/showgameselectorfiltertoolbar", showGameSelectorFilterToolbar);
emit showGameSelectorFilterToolbarChanged(showGameSelectorFilterToolbar);
}
void SettingsCache::setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames)
{
displayCardNames = static_cast<bool>(_displayCardNames);
@@ -856,6 +891,34 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
}
void SettingsCache::setVisualDeckEditorCardSize(int _visualDeckEditorCardSize)
{
visualDeckEditorCardSize = _visualDeckEditorCardSize;
settings->setValue("interface/visualdeckeditorcardsize", visualDeckEditorCardSize);
emit visualDeckEditorCardSizeChanged();
}
void SettingsCache::setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize)
{
visualDatabaseDisplayCardSize = _visualDatabaseDisplayCardSize;
settings->setValue("interface/visualdatabasedisplaycardsize", visualDatabaseDisplayCardSize);
emit visualDatabaseDisplayCardSizeChanged();
}
void SettingsCache::setEDHRecCardSize(int _edhrecCardSize)
{
edhrecCardSize = _edhrecCardSize;
settings->setValue("interface/edhreccardsize", edhrecCardSize);
emit edhRecCardSizeChanged();
}
void SettingsCache::setArchidektPreviewCardSize(int _archidektPreviewCardSize)
{
archidektPreviewSize = _archidektPreviewCardSize;
settings->setValue("interface/archidektpreviewsize", archidektPreviewSize);
emit archidektPreviewSizeChanged();
}
void SettingsCache::setDefaultDeckEditorType(int value)
{
defaultDeckEditorType = value;

View File

@@ -11,7 +11,6 @@
#include <QDate>
#include <QLoggingCategory>
#include <QObject>
#include <QSize>
#include <QStringList>
#include <libcockatrice/interfaces/interface_card_database_path_provider.h>
@@ -146,6 +145,7 @@ signals:
void homeTabBackgroundShuffleFrequencyChanged();
void picDownloadChanged();
void showStatusBarChanged(bool state);
void showGameSelectorFilterToolbarChanged(bool state);
void displayCardNamesChanged();
void overrideAllCardArtWithPersonalPreferenceChanged(bool _overrideAllCardArtWithPersonalPreference);
void bumpSetsWithCardsInDeckToTopChanged();
@@ -167,6 +167,10 @@ signals:
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
void visualDeckEditorSampleHandSizeAmountChanged(int amount);
void visualDeckEditorCardSizeChanged();
void visualDatabaseDisplayCardSizeChanged();
void edhRecCardSizeChanged();
void archidektPreviewSizeChanged();
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@@ -228,10 +232,12 @@ private:
bool doubleClickToPlay;
bool clickPlaysAllSelected;
bool playToStack;
bool doNotDeleteArrowsInSubPhases;
int startingHandSize;
bool annotateTokens;
QByteArray tabGameSplitterSizes;
bool showShortcuts;
bool showGameSelectorFilterToolbar;
bool displayCardNames;
bool overrideAllCardArtWithPersonalPreference;
bool bumpSetsWithCardsInDeckToTop;
@@ -249,6 +255,10 @@ private:
QStringList visualDeckStorageDefaultTagsList;
bool visualDeckStorageSearchFolderNames;
int visualDeckStorageCardSize;
int visualDeckEditorCardSize;
int visualDatabaseDisplayCardSize;
int edhrecCardSize;
int archidektPreviewSize;
bool visualDeckStorageDrawUnusedColorIdentities;
int visualDeckStorageUnusedColorIdentitiesOpacity;
int visualDeckStorageTooltipType;
@@ -316,8 +326,8 @@ private:
int keepalive;
int timeout;
void translateLegacySettings();
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
[[nodiscard]] QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
void loadPaths();
bool rememberGameSettings;
QList<ReleaseChannel *> releaseChannels;
@@ -329,137 +339,137 @@ public:
SettingsCache();
QString getDataPath();
QString getSettingsPath();
QString getCachePath() const;
QString getNetworkCachePath() const;
const QByteArray &getMainWindowGeometry() const
[[nodiscard]] QString getCachePath() const;
[[nodiscard]] QString getNetworkCachePath() const;
[[nodiscard]] const QByteArray &getMainWindowGeometry() const
{
return mainWindowGeometry;
}
const QByteArray &getTokenDialogGeometry() const
[[nodiscard]] const QByteArray &getTokenDialogGeometry() const
{
return tokenDialogGeometry;
}
const QByteArray &getSetsDialogGeometry() const
[[nodiscard]] const QByteArray &getSetsDialogGeometry() const
{
return setsDialogGeometry;
}
QString getLang() const
[[nodiscard]] QString getLang() const
{
return lang;
}
QString getDeckPath() const
[[nodiscard]] QString getDeckPath() const
{
return deckPath;
}
QString getFiltersPath() const
[[nodiscard]] QString getFiltersPath() const
{
return filtersPath;
}
QString getReplaysPath() const
[[nodiscard]] QString getReplaysPath() const
{
return replaysPath;
}
QString getThemesPath() const
[[nodiscard]] QString getThemesPath() const
{
return themesPath;
}
QString getPicsPath() const
[[nodiscard]] QString getPicsPath() const
{
return picsPath;
}
QString getRedirectCachePath() const
[[nodiscard]] QString getRedirectCachePath() const
{
return redirectCachePath;
}
QString getCustomPicsPath() const
[[nodiscard]] QString getCustomPicsPath() const
{
return customPicsPath;
}
QString getCustomCardDatabasePath() const override
[[nodiscard]] QString getCustomCardDatabasePath() const override
{
return customCardDatabasePath;
}
QString getCardDatabasePath() const override
[[nodiscard]] QString getCardDatabasePath() const override
{
return cardDatabasePath;
}
QString getSpoilerCardDatabasePath() const override
[[nodiscard]] QString getSpoilerCardDatabasePath() const override
{
return spoilerDatabasePath;
}
QString getTokenDatabasePath() const override
[[nodiscard]] QString getTokenDatabasePath() const override
{
return tokenDatabasePath;
}
QString getThemeName() const
[[nodiscard]] QString getThemeName() const
{
return themeName;
}
QString getHomeTabBackgroundSource() const
[[nodiscard]] QString getHomeTabBackgroundSource() const
{
return homeTabBackgroundSource;
}
int getHomeTabBackgroundShuffleFrequency() const
[[nodiscard]] int getHomeTabBackgroundShuffleFrequency() const
{
return homeTabBackgroundShuffleFrequency;
}
bool getTabVisualDeckStorageOpen() const
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
{
return tabVisualDeckStorageOpen;
}
bool getTabServerOpen() const
[[nodiscard]] bool getTabServerOpen() const
{
return tabServerOpen;
}
bool getTabAccountOpen() const
[[nodiscard]] bool getTabAccountOpen() const
{
return tabAccountOpen;
}
bool getTabDeckStorageOpen() const
[[nodiscard]] bool getTabDeckStorageOpen() const
{
return tabDeckStorageOpen;
}
bool getTabReplaysOpen() const
[[nodiscard]] bool getTabReplaysOpen() const
{
return tabReplaysOpen;
}
bool getTabAdminOpen() const
[[nodiscard]] bool getTabAdminOpen() const
{
return tabAdminOpen;
}
bool getTabLogOpen() const
[[nodiscard]] bool getTabLogOpen() const
{
return tabLogOpen;
}
QString getChatMentionColor() const
[[nodiscard]] QString getChatMentionColor() const
{
return chatMentionColor;
}
QString getChatHighlightColor() const
[[nodiscard]] QString getChatHighlightColor() const
{
return chatHighlightColor;
}
bool getPicDownload() const
[[nodiscard]] bool getPicDownload() const
{
return picDownload;
}
bool getShowStatusBar() const
[[nodiscard]] bool getShowStatusBar() const
{
return showStatusBar;
}
bool getNotificationsEnabled() const
[[nodiscard]] bool getNotificationsEnabled() const
{
return notificationsEnabled;
}
bool getSpectatorNotificationsEnabled() const
[[nodiscard]] bool getSpectatorNotificationsEnabled() const
{
return spectatorNotificationsEnabled;
}
bool getBuddyConnectNotificationsEnabled() const
[[nodiscard]] bool getBuddyConnectNotificationsEnabled() const
{
return buddyConnectNotificationsEnabled;
}
bool getCheckUpdatesOnStartup() const
[[nodiscard]] bool getCheckUpdatesOnStartup() const
{
return checkUpdatesOnStartup;
}
@@ -471,243 +481,267 @@ public:
{
return startupCardUpdateCheckAlwaysUpdate;
}
int getCardUpdateCheckInterval() const
[[nodiscard]] int getCardUpdateCheckInterval() const
{
return cardUpdateCheckInterval;
}
QDate getLastCardUpdateCheck() const
[[nodiscard]] QDate getLastCardUpdateCheck() const
{
return lastCardUpdateCheck;
}
bool getCardUpdateCheckRequired() const
[[nodiscard]] bool getCardUpdateCheckRequired() const
{
return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() &&
getLastCardUpdateCheck() != QDateTime::currentDateTime().date();
}
bool getNotifyAboutUpdates() const override
[[nodiscard]] bool getNotifyAboutUpdates() const override
{
return notifyAboutUpdates;
}
bool getNotifyAboutNewVersion() const
[[nodiscard]] bool getNotifyAboutNewVersion() const
{
return notifyAboutNewVersion;
}
bool getShowTipsOnStartup() const
[[nodiscard]] bool getShowTipsOnStartup() const
{
return showTipsOnStartup;
}
QList<int> getSeenTips() const
[[nodiscard]] QList<int> getSeenTips() const
{
return seenTips;
}
int getUpdateReleaseChannelIndex() const
[[nodiscard]] int getUpdateReleaseChannelIndex() const
{
return updateReleaseChannel;
}
ReleaseChannel *getUpdateReleaseChannel() const
[[nodiscard]] ReleaseChannel *getUpdateReleaseChannel() const
{
return releaseChannels.at(qMax(0, updateReleaseChannel));
}
QList<ReleaseChannel *> getUpdateReleaseChannels() const
[[nodiscard]] QList<ReleaseChannel *> getUpdateReleaseChannels() const
{
return releaseChannels;
}
bool getDoubleClickToPlay() const
[[nodiscard]] bool getDoubleClickToPlay() const
{
return doubleClickToPlay;
}
bool getClickPlaysAllSelected() const
[[nodiscard]] bool getClickPlaysAllSelected() const
{
return clickPlaysAllSelected;
}
bool getPlayToStack() const
[[nodiscard]] bool getPlayToStack() const
{
return playToStack;
}
int getStartingHandSize() const
[[nodiscard]] bool getDoNotDeleteArrowsInSubPhases() const
{
return doNotDeleteArrowsInSubPhases;
}
[[nodiscard]] int getStartingHandSize() const
{
return startingHandSize;
}
bool getAnnotateTokens() const
[[nodiscard]] bool getAnnotateTokens() const
{
return annotateTokens;
}
QByteArray getTabGameSplitterSizes() const
[[nodiscard]] QByteArray getTabGameSplitterSizes() const
{
return tabGameSplitterSizes;
}
bool getShowShortcuts() const
[[nodiscard]] bool getShowShortcuts() const
{
return showShortcuts;
}
bool getDisplayCardNames() const
[[nodiscard]] bool getShowGameSelectorFilterToolbar() const
{
return showGameSelectorFilterToolbar;
}
[[nodiscard]] bool getDisplayCardNames() const
{
return displayCardNames;
}
bool getOverrideAllCardArtWithPersonalPreference() const
[[nodiscard]] bool getOverrideAllCardArtWithPersonalPreference() const
{
return overrideAllCardArtWithPersonalPreference;
}
bool getBumpSetsWithCardsInDeckToTop() const
[[nodiscard]] bool getBumpSetsWithCardsInDeckToTop() const
{
return bumpSetsWithCardsInDeckToTop;
}
int getPrintingSelectorSortOrder() const
[[nodiscard]] int getPrintingSelectorSortOrder() const
{
return printingSelectorSortOrder;
}
int getPrintingSelectorCardSize() const
[[nodiscard]] int getPrintingSelectorCardSize() const
{
return printingSelectorCardSize;
}
bool getIncludeRebalancedCards() const
[[nodiscard]] bool getIncludeRebalancedCards() const
{
return includeRebalancedCards;
}
bool getPrintingSelectorNavigationButtonsVisible() const
[[nodiscard]] bool getPrintingSelectorNavigationButtonsVisible() const
{
return printingSelectorNavigationButtonsVisible;
}
bool getDeckEditorBannerCardComboBoxVisible() const
[[nodiscard]] bool getDeckEditorBannerCardComboBoxVisible() const
{
return deckEditorBannerCardComboBoxVisible;
}
bool getDeckEditorTagsWidgetVisible() const
[[nodiscard]] bool getDeckEditorTagsWidgetVisible() const
{
return deckEditorTagsWidgetVisible;
}
int getVisualDeckStorageSortingOrder() const
[[nodiscard]] int getVisualDeckStorageSortingOrder() const
{
return visualDeckStorageSortingOrder;
}
bool getVisualDeckStorageShowFolders() const
[[nodiscard]] bool getVisualDeckStorageShowFolders() const
{
return visualDeckStorageShowFolders;
}
bool getVisualDeckStorageShowTagFilter() const
[[nodiscard]] bool getVisualDeckStorageShowTagFilter() const
{
return visualDeckStorageShowTagFilter;
}
QStringList getVisualDeckStorageDefaultTagsList() const
[[nodiscard]] QStringList getVisualDeckStorageDefaultTagsList() const
{
return visualDeckStorageDefaultTagsList;
}
bool getVisualDeckStorageSearchFolderNames() const
[[nodiscard]] bool getVisualDeckStorageSearchFolderNames() const
{
return visualDeckStorageSearchFolderNames;
}
bool getVisualDeckStorageShowBannerCardComboBox() const
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
{
return visualDeckStorageShowBannerCardComboBox;
}
bool getVisualDeckStorageShowTagsOnDeckPreviews() const
[[nodiscard]] bool getVisualDeckStorageShowTagsOnDeckPreviews() const
{
return visualDeckStorageShowTagsOnDeckPreviews;
}
int getVisualDeckStorageCardSize() const
[[nodiscard]] int getVisualDeckStorageCardSize() const
{
return visualDeckStorageCardSize;
}
bool getVisualDeckStorageDrawUnusedColorIdentities() const
[[nodiscard]] bool getVisualDeckStorageDrawUnusedColorIdentities() const
{
return visualDeckStorageDrawUnusedColorIdentities;
}
int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
[[nodiscard]] int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
{
return visualDeckStorageUnusedColorIdentitiesOpacity;
}
int getVisualDeckStorageTooltipType() const
[[nodiscard]] int getVisualDeckStorageTooltipType() const
{
return visualDeckStorageTooltipType;
}
bool getVisualDeckStoragePromptForConversion() const
[[nodiscard]] bool getVisualDeckStoragePromptForConversion() const
{
return visualDeckStoragePromptForConversion;
}
bool getVisualDeckStorageAlwaysConvert() const
[[nodiscard]] bool getVisualDeckStorageAlwaysConvert() const
{
return visualDeckStorageAlwaysConvert;
}
bool getVisualDeckStorageInGame() const
[[nodiscard]] bool getVisualDeckStorageInGame() const
{
return visualDeckStorageInGame;
}
bool getVisualDeckStorageSelectionAnimation() const
[[nodiscard]] bool getVisualDeckStorageSelectionAnimation() const
{
return visualDeckStorageSelectionAnimation;
}
int getDefaultDeckEditorType() const
[[nodiscard]] int getVisualDeckEditorCardSize() const
{
return visualDeckEditorCardSize;
}
[[nodiscard]] int getVisualDatabaseDisplayCardSize() const
{
return visualDatabaseDisplayCardSize;
}
[[nodiscard]] int getEDHRecCardSize() const
{
return edhrecCardSize;
}
[[nodiscard]] int getArchidektPreviewSize() const
{
return archidektPreviewSize;
}
[[nodiscard]] int getDefaultDeckEditorType() const
{
return defaultDeckEditorType;
}
bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
[[nodiscard]] bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
{
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
}
int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
[[nodiscard]] int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
{
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
}
int getVisualDeckEditorSampleHandSize() const
[[nodiscard]] int getVisualDeckEditorSampleHandSize() const
{
return visualDeckEditorSampleHandSize;
}
bool getHorizontalHand() const
[[nodiscard]] bool getHorizontalHand() const
{
return horizontalHand;
}
bool getInvertVerticalCoordinate() const
[[nodiscard]] bool getInvertVerticalCoordinate() const
{
return invertVerticalCoordinate;
}
int getMinPlayersForMultiColumnLayout() const
[[nodiscard]] int getMinPlayersForMultiColumnLayout() const
{
return minPlayersForMultiColumnLayout;
}
bool getTapAnimation() const
[[nodiscard]] bool getTapAnimation() const
{
return tapAnimation;
}
bool getAutoRotateSidewaysLayoutCards() const
[[nodiscard]] bool getAutoRotateSidewaysLayoutCards() const
{
return autoRotateSidewaysLayoutCards;
}
bool getOpenDeckInNewTab() const
[[nodiscard]] bool getOpenDeckInNewTab() const
{
return openDeckInNewTab;
}
int getRewindBufferingMs() const
[[nodiscard]] int getRewindBufferingMs() const
{
return rewindBufferingMs;
}
bool getChatMention() const
[[nodiscard]] bool getChatMention() const
{
return chatMention;
}
bool getChatMentionCompleter() const
[[nodiscard]] bool getChatMentionCompleter() const
{
return chatMentionCompleter;
}
bool getChatMentionForeground() const
[[nodiscard]] bool getChatMentionForeground() const
{
return chatMentionForeground;
}
bool getChatHighlightForeground() const
[[nodiscard]] bool getChatHighlightForeground() const
{
return chatHighlightForeground;
}
/**
* Currently selected index for the `Group by X` QComboBox
*/
int getZoneViewGroupByIndex() const
[[nodiscard]] int getZoneViewGroupByIndex() const
{
return zoneViewGroupByIndex;
}
/**
* Currently selected index for the `Sort by X` QComboBox
*/
int getZoneViewSortByIndex() const
[[nodiscard]] int getZoneViewSortByIndex() const
{
return zoneViewSortByIndex;
}
@@ -715,136 +749,136 @@ public:
Returns if the view should be sorted into pile view.
@return zoneViewPileView if the view should be sorted into pile view.
*/
bool getZoneViewPileView() const
[[nodiscard]] bool getZoneViewPileView() const
{
return zoneViewPileView;
}
bool getSoundEnabled() const
[[nodiscard]] bool getSoundEnabled() const
{
return soundEnabled;
}
QString getSoundThemeName() const
[[nodiscard]] QString getSoundThemeName() const
{
return soundThemeName;
}
bool getIgnoreUnregisteredUsers() const
[[nodiscard]] bool getIgnoreUnregisteredUsers() const
{
return ignoreUnregisteredUsers;
}
bool getIgnoreUnregisteredUserMessages() const
[[nodiscard]] bool getIgnoreUnregisteredUserMessages() const
{
return ignoreUnregisteredUserMessages;
}
int getPixmapCacheSize() const
[[nodiscard]] int getPixmapCacheSize() const
{
return pixmapCacheSize;
}
int getNetworkCacheSizeInMB() const
[[nodiscard]] int getNetworkCacheSizeInMB() const
{
return networkCacheSize;
}
int getRedirectCacheTtl() const
[[nodiscard]] int getRedirectCacheTtl() const
{
return redirectCacheTtl;
}
bool getScaleCards() const
[[nodiscard]] bool getScaleCards() const
{
return scaleCards;
}
int getStackCardOverlapPercent() const
[[nodiscard]] int getStackCardOverlapPercent() const
{
return verticalCardOverlapPercent;
}
bool getShowMessagePopup() const
[[nodiscard]] bool getShowMessagePopup() const
{
return showMessagePopups;
}
bool getShowMentionPopup() const
[[nodiscard]] bool getShowMentionPopup() const
{
return showMentionPopups;
}
bool getRoomHistory() const
[[nodiscard]] bool getRoomHistory() const
{
return roomHistory;
}
bool getLeftJustified() const
[[nodiscard]] bool getLeftJustified() const
{
return leftJustified;
}
int getMasterVolume() const
[[nodiscard]] int getMasterVolume() const
{
return masterVolume;
}
int getCardInfoViewMode() const
[[nodiscard]] int getCardInfoViewMode() const
{
return cardInfoViewMode;
}
QStringList getCountries() const;
QString getHighlightWords() const
[[nodiscard]] QStringList getCountries() const;
[[nodiscard]] QString getHighlightWords() const
{
return highlightWords;
}
QString getGameDescription() const
[[nodiscard]] QString getGameDescription() const
{
return gameDescription;
}
int getMaxPlayers() const
[[nodiscard]] int getMaxPlayers() const
{
return maxPlayers;
}
QString getGameTypes() const
[[nodiscard]] QString getGameTypes() const
{
return gameTypes;
}
bool getOnlyBuddies() const
[[nodiscard]] bool getOnlyBuddies() const
{
return onlyBuddies;
}
bool getOnlyRegistered() const
[[nodiscard]] bool getOnlyRegistered() const
{
return onlyRegistered;
}
bool getSpectatorsAllowed() const
[[nodiscard]] bool getSpectatorsAllowed() const
{
return spectatorsAllowed;
}
bool getSpectatorsNeedPassword() const
[[nodiscard]] bool getSpectatorsNeedPassword() const
{
return spectatorsNeedPassword;
}
bool getSpectatorsCanTalk() const
[[nodiscard]] bool getSpectatorsCanTalk() const
{
return spectatorsCanTalk;
}
bool getSpectatorsCanSeeEverything() const
[[nodiscard]] bool getSpectatorsCanSeeEverything() const
{
return spectatorsCanSeeEverything;
}
int getDefaultStartingLifeTotal() const
[[nodiscard]] int getDefaultStartingLifeTotal() const
{
return defaultStartingLifeTotal;
}
bool getShareDecklistsOnLoad() const
[[nodiscard]] bool getShareDecklistsOnLoad() const
{
return shareDecklistsOnLoad;
}
bool getCreateGameAsSpectator() const
[[nodiscard]] bool getCreateGameAsSpectator() const
{
return createGameAsSpectator;
}
bool getRememberGameSettings() const
[[nodiscard]] bool getRememberGameSettings() const
{
return rememberGameSettings;
}
int getKeepAlive() const override
[[nodiscard]] int getKeepAlive() const override
{
return keepalive;
}
int getTimeOut() const override
[[nodiscard]] int getTimeOut() const override
{
return timeout;
}
int getMaxFontSize() const
[[nodiscard]] int getMaxFontSize() const
{
return maxFontSize;
}
@@ -872,73 +906,73 @@ public:
{
return useTearOffMenus;
}
int getCardViewInitialRowsMax() const
[[nodiscard]] int getCardViewInitialRowsMax() const
{
return cardViewInitialRowsMax;
}
int getCardViewExpandedRowsMax() const
[[nodiscard]] int getCardViewExpandedRowsMax() const
{
return cardViewExpandedRowsMax;
}
bool getCloseEmptyCardView() const
[[nodiscard]] bool getCloseEmptyCardView() const
{
return closeEmptyCardView;
}
bool getFocusCardViewSearchBar() const
[[nodiscard]] bool getFocusCardViewSearchBar() const
{
return focusCardViewSearchBar;
}
ShortcutsSettings &shortcuts() const
[[nodiscard]] ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
}
CardDatabaseSettings *cardDatabase() const
[[nodiscard]] CardDatabaseSettings *cardDatabase() const
{
return cardDatabaseSettings;
}
ServersSettings &servers() const
[[nodiscard]] ServersSettings &servers() const
{
return *serversSettings;
}
MessageSettings &messages() const
[[nodiscard]] MessageSettings &messages() const
{
return *messageSettings;
}
GameFiltersSettings &gameFilters() const
[[nodiscard]] GameFiltersSettings &gameFilters() const
{
return *gameFiltersSettings;
}
LayoutsSettings &layouts() const
[[nodiscard]] LayoutsSettings &layouts() const
{
return *layoutsSettings;
}
DownloadSettings &downloads() const
[[nodiscard]] DownloadSettings &downloads() const
{
return *downloadSettings;
}
RecentsSettings &recents() const
[[nodiscard]] RecentsSettings &recents() const
{
return *recentsSettings;
}
CardOverrideSettings &cardOverrides() const
[[nodiscard]] CardOverrideSettings &cardOverrides() const
{
return *cardOverrideSettings;
}
DebugSettings &debug() const
[[nodiscard]] DebugSettings &debug() const
{
return *debugSettings;
}
CardCounterSettings &cardCounters() const;
[[nodiscard]] CardCounterSettings &cardCounters() const;
bool getIsPortableBuild() const
[[nodiscard]] bool getIsPortableBuild() const
{
return isPortableBuild;
}
bool getDownloadSpoilersStatus() const
[[nodiscard]] bool getDownloadSpoilersStatus() const
{
return mbDownloadSpoilers;
}
bool getRoundCardCorners() const
[[nodiscard]] bool getRoundCardCorners() const
{
return roundCardCorners;
}
@@ -984,10 +1018,12 @@ public slots:
void setDoubleClickToPlay(QT_STATE_CHANGED_T _doubleClickToPlay);
void setClickPlaysAllSelected(QT_STATE_CHANGED_T _clickPlaysAllSelected);
void setPlayToStack(QT_STATE_CHANGED_T _playToStack);
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
void setStartingHandSize(int _startingHandSize);
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
void setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T _overrideAllCardArt);
void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
@@ -1012,6 +1048,10 @@ public slots:
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
void setVisualDeckEditorCardSize(int _visualDeckEditorCardSize);
void setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize);
void setEDHRecCardSize(int _EDHRecCardSize);
void setArchidektPreviewCardSize(int _archidektPreviewCardSize);
void setDefaultDeckEditorType(int value);
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);

View File

@@ -7,7 +7,6 @@
#ifndef CARD_COUNTER_SETTINGS_H
#define CARD_COUNTER_SETTINGS_H
#include <QObject>
#include <libcockatrice/settings/settings_manager.h>
class QSettings;
@@ -20,9 +19,9 @@ class CardCounterSettings : public SettingsManager
public:
CardCounterSettings(const QString &settingsPath, QObject *parent = nullptr);
QColor color(int counterId) const;
[[nodiscard]] QColor color(int counterId) const;
QString displayName(int counterId) const;
[[nodiscard]] QString displayName(int counterId) const;
public slots:
void setColor(int counterId, const QColor &color);

View File

@@ -150,12 +150,7 @@ void ShortcutTreeView::currentChanged(const QModelIndex &current, const QModelIn
*/
void ShortcutTreeView::updateSearchString(const QString &searchString)
{
#if QT_VERSION > QT_VERSION_CHECK(5, 14, 0)
const auto skipEmptyParts = Qt::SkipEmptyParts;
#else
const auto skipEmptyParts = QString::SkipEmptyParts;
#endif
QStringList searchWords = searchString.split(" ", skipEmptyParts);
QStringList searchWords = searchString.split(" ", Qt::SkipEmptyParts);
auto escapeRegex = [](const QString &s) { return QRegularExpression::escape(s); };
std::transform(searchWords.begin(), searchWords.end(), searchWords.begin(), escapeRegex);

View File

@@ -7,7 +7,6 @@
#ifndef SHORTCUT_TREEVIEW_H
#define SHORTCUT_TREEVIEW_H
#include <QModelIndex>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QTreeView>
@@ -22,7 +21,7 @@ public:
explicit ShortcutFilterProxyModel(QObject *parent = nullptr);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
[[nodiscard]] bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
};
class ShortcutTreeView : public QTreeView

View File

@@ -99,15 +99,15 @@ public:
void setSequence(const QList &_sequence)
{
QList::operator=(_sequence);
};
QString getName() const
}
[[nodiscard]] QString getName() const
{
return QApplication::translate("shortcutsTab", name.toUtf8().data());
};
QString getGroupName() const
}
[[nodiscard]] QString getGroupName() const
{
return ShortcutGroup::getGroupName(group);
};
}
private:
QString name;
@@ -120,24 +120,24 @@ class ShortcutsSettings : public QObject
public:
explicit ShortcutsSettings(const QString &settingsFilePath, QObject *parent = nullptr);
ShortcutKey getDefaultShortcut(const QString &name) const;
ShortcutKey getShortcut(const QString &name) const;
QKeySequence getSingleShortcut(const QString &name) const;
QString getDefaultShortcutString(const QString &name) const;
QString getShortcutString(const QString &name) const;
QString getShortcutFriendlyName(const QString &shortcutName) const;
QList<QString> getAllShortcutKeys() const
[[nodiscard]] ShortcutKey getDefaultShortcut(const QString &name) const;
[[nodiscard]] ShortcutKey getShortcut(const QString &name) const;
[[nodiscard]] QKeySequence getSingleShortcut(const QString &name) const;
[[nodiscard]] QString getDefaultShortcutString(const QString &name) const;
[[nodiscard]] QString getShortcutString(const QString &name) const;
[[nodiscard]] QString getShortcutFriendlyName(const QString &shortcutName) const;
[[nodiscard]] QList<QString> getAllShortcutKeys() const
{
return shortCuts.keys();
};
}
void setShortcuts(const QString &name, const QList<QKeySequence> &Sequence);
void setShortcuts(const QString &name, const QKeySequence &Sequence);
void setShortcuts(const QString &name, const QString &sequences);
bool isKeyAllowed(const QString &name, const QString &sequences) const;
bool isValid(const QString &name, const QString &sequences) const;
QStringList findOverlaps(const QString &name, const QString &sequences) const;
[[nodiscard]] bool isKeyAllowed(const QString &name, const QString &sequences) const;
[[nodiscard]] bool isValid(const QString &name, const QString &sequences) const;
[[nodiscard]] QStringList findOverlaps(const QString &name, const QString &sequences) const;
void resetAllShortcuts();
void clearAllShortcuts();
@@ -152,8 +152,8 @@ private:
QString settingsFilePath;
QHash<QString, ShortcutKey> shortCuts;
QString stringifySequence(const QList<QKeySequence> &Sequence) const;
QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
[[nodiscard]] QString stringifySequence(const QList<QKeySequence> &Sequence) const;
[[nodiscard]] QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
const QHash<QString, ShortcutKey> defaultShortCuts = {
{"MainWindow/aCheckCardUpdates", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Check for Card Updates..."),
@@ -660,6 +660,12 @@ private:
{"Player/aMulligan", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Mulligan"),
parseSequenceString("Ctrl+M"),
ShortcutGroup::Drawing)},
{"Player/aMulliganSame", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Mulligan (Same hand size)"),
parseSequenceString("Ctrl+Shift+M"),
ShortcutGroup::Drawing)},
{"Player/aMulliganMinusOne", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Mulligan (Hand size - 1)"),
parseSequenceString("Ctrl+Shift+Alt+M"),
ShortcutGroup::Drawing)},
{"Player/aDrawCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Draw a Card"),
parseSequenceString("Ctrl+D"),
ShortcutGroup::Drawing)},

View File

@@ -7,15 +7,15 @@
class SettingsCardPreferenceProvider : public ICardPreferenceProvider
{
public:
QString getCardPreferenceOverride(const QString &cardName) const override
[[nodiscard]] QString getCardPreferenceOverride(const QString &cardName) const override
{
return SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName);
}
bool getIncludeRebalancedCards() const override
[[nodiscard]] bool getIncludeRebalancedCards() const override
{
return SettingsCache::instance().getIncludeRebalancedCards();
};
}
};
#endif // COCKATRICE_SETTINGS_CARD_PREFERENCE_PROVIDER_H

View File

@@ -1,5 +1,6 @@
#include "deck_filter_string.h"
#include <QFileInfo>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/filters/filter_string.h>
#include <libcockatrice/utility/peglib.h>
@@ -12,7 +13,7 @@ QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / GenericQuery
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / FormatQuery / GenericQuery
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
@@ -21,8 +22,9 @@ CardSearch <- '[[' CardFilterString ']]'
CardFilterString <- (!']]'.)*
DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String
FileNameQuery <- [Ff] ('ile' 'name'?)? [:] String
FileNameQuery <- [Ff] ([Nn] / 'ile' ([Nn] 'ame')?) [:] String
PathQuery <- [Pp] 'ath'? [:] String
FormatQuery <- [Ff] 'ormat'? [:] String
GenericQuery <- String
@@ -117,12 +119,13 @@ static void setupParserRules()
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
int count = 0;
deck->deckLoader->getDeckList()->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) {
auto cardNodes = deck->deckLoader->getDeck().deckList.getCardNodes();
for (auto node : cardNodes) {
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
count += node->getNumber();
}
});
}
return numberMatcher(count);
};
};
@@ -136,7 +139,7 @@ static void setupParserRules()
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto name = std::any_cast<QString>(sv[0]);
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
return deck->deckLoader->getDeckList()->getName().contains(name, Qt::CaseInsensitive);
return deck->deckLoader->getDeck().deckList.getName().contains(name, Qt::CaseInsensitive);
};
};
@@ -155,6 +158,14 @@ static void setupParserRules()
};
};
search["FormatQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto format = std::any_cast<QString>(sv[0]);
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
auto gameFormat = deck->deckLoader->getDeck().deckList.getGameFormat();
return QString::compare(format, gameFormat, Qt::CaseInsensitive) == 0;
};
};
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto name = std::any_cast<QString>(sv[0]);
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {

View File

@@ -10,10 +10,8 @@
#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h"
#include <QLoggingCategory>
#include <QMap>
#include <QString>
#include <functional>
#include <utility>
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
@@ -40,7 +38,7 @@ public:
return filter(deck, info);
}
bool valid() const
[[nodiscard]] bool valid() const
{
return _error.isEmpty();
}

View File

@@ -24,8 +24,8 @@ public slots:
void addFilter(const CardFilter *f);
void removeFilter(const CardFilter *f);
void clearFiltersOfType(CardFilter::Attr filterType);
QList<const CardFilter *> getFiltersOfType(CardFilter::Attr filterType) const;
QList<const CardFilter *> allFilters() const;
[[nodiscard]] QList<const CardFilter *> getFiltersOfType(CardFilter::Attr filterType) const;
[[nodiscard]] QList<const CardFilter *> allFilters() const;
private slots:
void proxyBeginInsertRow(const FilterTreeNode *, int);
@@ -34,23 +34,23 @@ private slots:
void proxyEndRemoveRow(const FilterTreeNode *, int);
private:
FilterTreeNode *indexToNode(const QModelIndex &idx) const;
[[nodiscard]] FilterTreeNode *indexToNode(const QModelIndex &idx) const;
QModelIndex nodeIndex(const FilterTreeNode *node, int row, int column) const;
public:
FilterTreeModel(QObject *parent = nullptr);
~FilterTreeModel() override;
FilterTree *filterTree() const
[[nodiscard]] FilterTree *filterTree() const
{
return fTree;
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
[[nodiscard]] int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QModelIndex parent(const QModelIndex &ind) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
[[nodiscard]] QModelIndex parent(const QModelIndex &ind) const override;
[[nodiscard]] QModelIndex index(int row, int column, const QModelIndex &parent) const override;
bool removeRows(int row, int count, const QModelIndex &parent) override;
void clear();
};

View File

@@ -3,15 +3,14 @@
#include "../../client/settings/cache_settings.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "translate_counter_name.h"
#include <QAction>
#include <QApplication>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneMouseEvent>
#include <QKeyEvent>
#include <QMenu>
#include <QPainter>
#include <QString>
#include <libcockatrice/protocol/pb/command_inc_counter.pb.h>
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>

View File

@@ -3,6 +3,7 @@
#include "../../client/settings/cache_settings.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "../player/player_target.h"
#include "../zones/card_zone.h"
#include "card_item.h"
@@ -151,8 +152,8 @@ void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
}
ArrowDragItem::ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color)
: ArrowItem(_owner, -1, _startItem, 0, _color)
ArrowDragItem::ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
: ArrowItem(_owner, -1, _startItem, 0, _color), deleteInPhase(_deleteInPhase)
{
}
@@ -231,20 +232,28 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
} else {
} else { // failed to cast target to card, this means it's a player
PlayerTarget *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem);
cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId());
}
if (startZone->getName().compare("hand") == 0) {
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
if (startZone->getName() == "hand") {
startCard->playCard(false);
CardInfoPtr ci = startCard->getCard().getCardPtr();
if (ci && ((!SettingsCache::instance().getPlayToStack() && ci->getUiAttributes().tableRow == 3) ||
(SettingsCache::instance().getPlayToStack() && ci->getUiAttributes().tableRow != 0 &&
startCard->getZone()->getName().toStdString() != "stack")))
bool playToStack = SettingsCache::instance().getPlayToStack();
if (ci &&
((!playToStack && ci->getUiAttributes().tableRow == 3) ||
(playToStack && ci->getUiAttributes().tableRow != 0 && startCard->getZone()->getName() != "stack")))
cmd.set_start_zone("stack");
else
cmd.set_start_zone(SettingsCache::instance().getPlayToStack() ? "stack" : "table");
cmd.set_start_zone(playToStack ? "stack" : "table");
}
if (deleteInPhase != 0) {
cmd.set_delete_in_phase(deleteInPhase);
}
player->getPlayerActions()->sendGameCommand(cmd);
}
delArrow();

View File

@@ -82,10 +82,11 @@ class ArrowDragItem : public ArrowItem
{
Q_OBJECT
private:
int deleteInPhase;
QList<ArrowDragItem *> childArrows;
public:
ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color);
ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
void addChildArrow(ArrowDragItem *childArrow);
protected:

View File

@@ -3,8 +3,9 @@
#include "../../client/settings/cache_settings.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../game_scene.h"
#include "../phase.h"
#include "../player/player.h"
#include "../zones/card_zone.h"
#include "../player/player_actions.h"
#include "../zones/logic/view_zone_logic.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
@@ -275,9 +276,14 @@ void CardItem::drawArrow(const QColor &arrowColor)
if (owner->getGame()->getPlayerManager()->isSpectator())
return;
Player *arrowOwner =
owner->getGame()->getPlayerManager()->getActiveLocalPlayer(owner->getGame()->getGameState()->getActivePlayer());
ArrowDragItem *arrow = new ArrowDragItem(arrowOwner, this, arrowColor);
auto *game = owner->getGame();
Player *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
int phase = 0; // 0 means to not set the phase
if (SettingsCache::instance().getDoNotDeleteArrowsInSubPhases()) {
int currentPhase = game->getGameState()->getCurrentPhase();
phase = Phases::getLastSubphase(currentPhase) + 1;
}
ArrowDragItem *arrow = new ArrowDragItem(arrowOwner, this, arrowColor, phase);
scene()->addItem(arrow);
arrow->grabMouse();
@@ -288,7 +294,7 @@ void CardItem::drawArrow(const QColor &arrowColor)
if (card->getZone() != zone)
continue;
ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, card, arrowColor);
ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, card, arrowColor, phase);
scene()->addItem(childArrow);
arrow->addChildArrow(childArrow);
}

View File

@@ -10,7 +10,7 @@
#include <algorithm>
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item,
const QPointF &_hotSpot,
@@ -343,10 +343,7 @@ void DeckViewScene::rebuildTree()
if (!deck)
return;
InnerDecklistNode *listRoot = deck->getRoot();
for (int i = 0; i < listRoot->size(); i++) {
auto *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
for (auto *currentZone : deck->getZoneNodes()) {
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
if (!container) {
container = new DeckViewCardContainer(currentZone->getName());

View File

@@ -9,11 +9,8 @@
#include "../board/abstract_card_drag_item.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QMap>
#include <QMultiMap>
#include <QPixmap>
#include <libcockatrice/protocol/pb/move_card_to_zone.pb.h>
class DeckList;

View File

@@ -8,13 +8,9 @@
#include "../../interface/widgets/dialogs/dlg_load_deck_from_website.h"
#include "../../interface/widgets/dialogs/dlg_load_remote_deck.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../game_scene.h"
#include "deck_view.h"
#include <QMessageBox>
#include <QMouseEvent>
#include <QToolButton>
#include <google/protobuf/descriptor.h>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/protocol/pb/command_deck_select.pb.h>
@@ -263,7 +259,7 @@ void DeckViewContainer::loadLocalDeck()
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
{
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(filePath);
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath);
DeckLoader deck(this);
bool success = deck.loadFromFile(filePath, fmt, true);
@@ -273,12 +269,12 @@ void DeckViewContainer::loadDeckFromFile(const QString &filePath)
return;
}
loadDeckFromDeckLoader(&deck);
loadDeckFromDeckList(deck.getDeck().deckList);
}
void DeckViewContainer::loadDeckFromDeckLoader(DeckLoader *deck)
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
{
QString deckString = deck->getDeckList()->writeToString_Native();
QString deckString = deck.writeToString_Native();
if (deckString.length() > MAX_FILE_LENGTH) {
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
@@ -312,8 +308,8 @@ void DeckViewContainer::loadFromClipboard()
return;
}
DeckLoader *deck = dlg.getDeckList();
loadDeckFromDeckLoader(deck);
DeckList deck = dlg.getDeckList();
loadDeckFromDeckList(deck);
}
void DeckViewContainer::loadFromWebsite()
@@ -324,16 +320,15 @@ void DeckViewContainer::loadFromWebsite()
return;
}
DeckLoader *deck = dlg.getDeck();
loadDeckFromDeckLoader(deck);
DeckList deck = dlg.getDeck();
loadDeckFromDeckList(deck);
}
void DeckViewContainer::deckSelectFinished(const Response &r)
{
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
DeckLoader newDeck(this, new DeckList(QString::fromStdString(resp.deck())));
CardPictureLoader::cacheCardPixmaps(
CardDatabaseManager::query()->getCards(newDeck.getDeckList()->getCardRefList()));
DeckList newDeck = DeckList(QString::fromStdString(resp.deck()));
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(newDeck.getCardRefList()));
setDeck(newDeck);
switchToDeckLoadedView();
}
@@ -414,8 +409,8 @@ void DeckViewContainer::setSideboardLocked(bool locked)
deckView->resetSideboardPlan();
}
void DeckViewContainer::setDeck(DeckLoader &deck)
void DeckViewContainer::setDeck(const DeckList &deck)
{
deckView->setDeck(*deck.getDeckList());
deckView->setDeck(deck);
switchToDeckLoadedView();
}

View File

@@ -85,12 +85,12 @@ public:
void setReadyStart(bool ready);
void readyAndUpdate();
void setSideboardLocked(bool locked);
void setDeck(DeckLoader &deck);
void setDeck(const DeckList &deck);
void setVisualDeckStorageExists(bool exists);
public slots:
void loadDeckFromFile(const QString &filePath);
void loadDeckFromDeckLoader(DeckLoader *deck);
void loadDeckFromDeckList(const DeckList &deck);
};
#endif // DECK_VIEW_CONTAINER_H

View File

@@ -16,7 +16,6 @@
#include <QLineEdit>
#include <QRadioButton>
#include <QTreeView>
#include <QVBoxLayout>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/models/database/card_database_model.h>
@@ -118,11 +117,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
chooseTokenFromDeckRadioButton->setDisabled(true); // No tokens in deck = no need for option
} else {
chooseTokenFromDeckRadioButton->setChecked(true);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
#else
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>::fromList(predefinedTokens));
#endif
}
auto *tokenChooseLayout = new QVBoxLayout;
@@ -224,11 +219,7 @@ void DlgCreateToken::actChooseTokenFromAll(bool checked)
void DlgCreateToken::actChooseTokenFromDeck(bool checked)
{
if (checked) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
#else
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>::fromList(predefinedTokens));
#endif
}
}

View File

@@ -8,7 +8,6 @@
#define DLG_CREATETOKEN_H
#include <QDialog>
#include <QModelIndex>
class QLabel;
class QLineEdit;

View File

@@ -15,7 +15,6 @@
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
#include <libcockatrice/protocol/pb/context_connection_state_changed.pb.h>
#include <libcockatrice/protocol/pb/context_deck_select.pb.h>
#include <libcockatrice/protocol/pb/context_ping_changed.pb.h>
#include <libcockatrice/protocol/pb/event_game_closed.pb.h>
#include <libcockatrice/protocol/pb/event_game_host_changed.pb.h>
#include <libcockatrice/protocol/pb/event_game_say.pb.h>

View File

@@ -8,7 +8,6 @@
#include "zones/view_zone.h"
#include "zones/view_zone_widget.h"
#include <QAction>
#include <QBasicTimer>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>

View File

@@ -7,10 +7,8 @@
#ifndef COCKATRICE_GAME_STATE_H
#define COCKATRICE_GAME_STATE_H
#include <QObject>
#include <QTimer>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/protocol/pb/serverinfo_game.pb.h>
class AbstractGame;
class ServerInfo_PlayerProperties;

View File

@@ -6,12 +6,10 @@
#include "../board/translate_counter_name.h"
#include "../phase.h"
#include "../player/player.h"
#include "../zones/card_zone.h"
#include <../../client/settings/card_counter_settings.h>
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <utility>
static const QString TABLE_ZONE_NAME = "table";

View File

@@ -7,12 +7,9 @@
#ifndef MESSAGELOGWIDGET_H
#define MESSAGELOGWIDGET_H
#include "../../client/translation.h"
#include "../../interface/widgets/server/chat_view/chat_view.h"
#include "../zones/logic/card_zone_logic.h"
#include <libcockatrice/network/server/remote/user_level.h>
class AbstractGame;
class CardItem;
class GameEventContext;

View File

@@ -22,6 +22,28 @@ Phase Phases::getPhase(int phase)
}
}
int Phases::getLastSubphase(int phase)
{
if (0 <= phase && phase < Phases::phaseTypesCount) {
return subPhasesEnd[phase];
} else {
return phase;
}
}
QVector<int> getSubPhasesEnd()
{
QVector<int> array(Phases::phaseTypesCount);
for (int phaseEnd = Phases::phaseTypesCount - 1; phaseEnd >= 0;) {
int subPhase = phaseEnd;
for (; subPhase >= 0 && Phases::phases[phaseEnd].color == Phases::phases[subPhase].color; --subPhase) {
array[subPhase] = phaseEnd;
}
phaseEnd = subPhase;
}
return array;
}
const Phase Phases::unknownPhase(QT_TRANSLATE_NOOP("Phase", "Unknown Phase"), "black", "unknown_phase");
const Phase Phases::phases[Phases::phaseTypesCount] = {
{QT_TRANSLATE_NOOP("Phase", "Untap"), "green", "untap_step"},
@@ -35,3 +57,4 @@ const Phase Phases::phases[Phases::phaseTypesCount] = {
{QT_TRANSLATE_NOOP("Phase", "End of Combat"), "red", "end_combat"},
{QT_TRANSLATE_NOOP("Phase", "Second Main"), "blue", "main_2"},
{QT_TRANSLATE_NOOP("Phase", "End/Cleanup"), "green", "end_step"}};
const QVector<int> Phases::subPhasesEnd = getSubPhasesEnd();

View File

@@ -28,8 +28,10 @@ struct Phases
const static int phaseTypesCount = 11;
const static Phase unknownPhase;
const static Phase phases[phaseTypesCount];
const static QVector<int> subPhasesEnd;
static Phase getPhase(int);
static int getLastSubphase(int phase);
};
#endif // PHASE_H

View File

@@ -396,7 +396,7 @@ void CardMenu::addRelatedCardActions()
relatedCardName = relatedCard.getName(); // "name"
}
QString text = tr("Token: ");
QString text = tr("Token") + ": ";
if (cardRelation->getDoesAttach()) {
text +=
tr(cardRelation->getDoesTransform() ? "Transform into " : "Attach to ") + "\"" + relatedCardName + "\"";
@@ -502,4 +502,4 @@ void CardMenu::setShortcutsActive()
aRemoveCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aRC" + colorWords[i]));
aSetCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aSC" + colorWords[i]));
}
}
}

View File

@@ -3,7 +3,6 @@
#include "../../abstract_game.h"
#include "../player.h"
#include "../player_actions.h"
#include "grave_menu.h"
#include <QAction>
#include <QMenu>

View File

@@ -60,6 +60,16 @@ HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : T
connect(aMulligan, &QAction::triggered, actions, &PlayerActions::actMulligan);
addAction(aMulligan);
// Mulligan same size
aMulliganSame = new QAction(this);
connect(aMulliganSame, &QAction::triggered, actions, &PlayerActions::actMulliganSameSize);
addAction(aMulliganSame);
// Mulligan -1
aMulliganMinusOne = new QAction(this);
connect(aMulliganMinusOne, &QAction::triggered, actions, &PlayerActions::actMulliganMinusOne);
addAction(aMulliganMinusOne);
addSeparator();
mMoveHandMenu = addTearOffMenu(QString());
@@ -104,7 +114,9 @@ void HandMenu::retranslateUi()
aSortHandByType->setText(tr("Type"));
aSortHandByManaValue->setText(tr("Mana Value"));
aMulligan->setText(tr("Take &mulligan"));
aMulligan->setText(tr("Take &mulligan (Choose hand size)"));
aMulliganSame->setText(tr("Take mulligan (Same hand size)"));
aMulliganMinusOne->setText(tr("Take mulligan (Hand size - 1)"));
mMoveHandMenu->setTitle(tr("&Move hand to..."));
aMoveHandToTopLibrary->setText(tr("&Top of library"));
@@ -128,6 +140,8 @@ void HandMenu::setShortcutsActive()
aSortHandByType->setShortcuts(shortcuts.getShortcut("Player/aSortHandByType"));
aSortHandByManaValue->setShortcuts(shortcuts.getShortcut("Player/aSortHandByManaValue"));
aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan"));
aMulliganSame->setShortcuts(shortcuts.getShortcut("Player/aMulliganSame"));
aMulliganMinusOne->setShortcuts(shortcuts.getShortcut("Player/aMulliganMinusOne"));
aRevealHandToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealHandToAll"));
aRevealRandomHandCardToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealRandomHandCardToAll"));
}

View File

@@ -46,6 +46,8 @@ private:
QAction *aViewHand = nullptr;
QAction *aMulligan = nullptr;
QAction *aMulliganSame = nullptr;
QAction *aMulliganMinusOne = nullptr;
QMenu *mSortHand = nullptr;
QAction *aSortHandByName = nullptr;

View File

@@ -3,12 +3,11 @@
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../board/card_item.h"
#include "../../zones/hand_zone.h"
#include "../card_menu_action_type.h"
#include "../player_actions.h"
#include "../../zones/pile_zone.h"
#include "../../zones/table_zone.h"
#include "card_menu.h"
#include "hand_menu.h"
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
PlayerMenu::PlayerMenu(Player *_player) : player(_player)

View File

@@ -1,6 +1,7 @@
#include "sideboard_menu.h"
#include "../player.h"
#include "../player_actions.h"
SideboardMenu::SideboardMenu(Player *player, QMenu *playerMenu) : QMenu(playerMenu)
{

View File

@@ -1,9 +1,13 @@
#include "utility_menu.h"
#include "../../../interface/deck_loader/deck_loader.h"
#include "../player.h"
#include "../player_actions.h"
#include "player_menu.h"
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/inner_deck_list_node.h>
UtilityMenu::UtilityMenu(Player *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
{
PlayerActions *playerActions = player->getPlayerActions();
@@ -56,21 +60,19 @@ void UtilityMenu::populatePredefinedTokensMenu()
clear();
setEnabled(false);
predefinedTokens.clear();
DeckLoader *_deck = player->getDeck();
const DeckList &deckList = player->getDeck();
if (!_deck) {
if (deckList.isEmpty()) {
return;
}
InnerDecklistNode *tokenZone =
dynamic_cast<InnerDecklistNode *>(_deck->getDeckList()->getRoot()->findChild(DECK_ZONE_TOKENS));
auto tokenCardNodes = deckList.getCardNodes({DECK_ZONE_TOKENS});
if (tokenZone) {
if (!tokenZone->empty())
setEnabled(true);
if (!tokenCardNodes.isEmpty()) {
setEnabled(true);
for (int i = 0; i < tokenZone->size(); ++i) {
const QString tokenName = tokenZone->at(i)->getName();
for (int i = 0; i < tokenCardNodes.size(); ++i) {
const QString tokenName = tokenCardNodes[i]->getName();
predefinedTokens.append(tokenName);
QAction *a = addAction(tokenName);
if (i < 10) {

View File

@@ -11,7 +11,7 @@
#include "../zones/pile_zone.h"
#include "../zones/stack_zone.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
#include "player_actions.h"
#include "player_target.h"
#include <QDebug>
@@ -32,7 +32,7 @@
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),
playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false),
conceded(false), deck(nullptr), zoneId(0), dialogSemaphore(false)
conceded(false), zoneId(0), dialogSemaphore(false)
{
initializeZones();
@@ -263,10 +263,9 @@ void Player::deleteCard(CardItem *card)
}
}
// TODO: Does a player need a DeckLoader?
void Player::setDeck(DeckLoader &_deck)
void Player::setDeck(const DeckList &_deck)
{
deck = new DeckLoader(this, _deck.getDeckList());
deck = _deck;
emit deckChanged();
}

View File

@@ -9,9 +9,12 @@
#include "../../game_graphics/board/abstract_graphics_item.h"
#include "../../interface/widgets/menus/tearoff_menu.h"
#include "../dialogs/dlg_create_token.h"
#include "../interface/deck_loader/loaded_deck.h"
#include "../zones/logic/hand_zone_logic.h"
#include "../zones/logic/pile_zone_logic.h"
#include "../zones/logic/stack_zone_logic.h"
#include "../zones/logic/table_zone_logic.h"
#include "menu/player_menu.h"
#include "player_actions.h"
#include "player_area.h"
#include "player_event_handler.h"
#include "player_graphics_item.h"
@@ -20,9 +23,7 @@
#include <QInputDialog>
#include <QLoggingCategory>
#include <QMap>
#include <QPoint>
#include <QTimer>
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/filters/filter_string.h>
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
#include <libcockatrice/protocol/pb/game_event.pb.h>
@@ -44,7 +45,6 @@ class ArrowTarget;
class CardDatabase;
class CardZone;
class CommandContainer;
class DeckLoader;
class GameCommand;
class GameEvent;
class PlayerInfo;
@@ -66,7 +66,7 @@ class Player : public QObject
Q_OBJECT
signals:
void openDeckEditor(DeckLoader *deck);
void openDeckEditor(const LoadedDeck &deck);
void deckChanged();
void newCardAdded(AbstractCardItem *card);
void rearrangeCounters();
@@ -113,7 +113,7 @@ public:
[[nodiscard]] PlayerActions *getPlayerActions() const
{
return playerActions;
};
}
[[nodiscard]] PlayerEventHandler *getPlayerEventHandler() const
{
@@ -123,16 +123,16 @@ public:
[[nodiscard]] PlayerInfo *getPlayerInfo() const
{
return playerInfo;
};
}
[[nodiscard]] PlayerMenu *getPlayerMenu() const
{
return playerMenu;
}
void setDeck(DeckLoader &_deck);
void setDeck(const DeckList &_deck);
[[nodiscard]] DeckLoader *getDeck() const
[[nodiscard]] const DeckList &getDeck() const
{
return deck;
}
@@ -241,7 +241,7 @@ private:
bool active;
bool conceded;
DeckLoader *deck;
DeckList deck;
int zoneId;
QMap<QString, CardZoneLogic *> zones;

View File

@@ -5,14 +5,15 @@
#include "../board/card_item.h"
#include "../dialogs/dlg_move_top_cards_until.h"
#include "../dialogs/dlg_roll_dice.h"
#include "../zones/hand_zone.h"
#include "../zones/logic/view_zone_logic.h"
#include "../zones/table_zone.h"
#include "card_menu_action_type.h"
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
#include <libcockatrice/protocol/pb/command_change_zone_properties.pb.h>
#include <libcockatrice/protocol/pb/command_concede.pb.h>
#include <libcockatrice/protocol/pb/command_create_token.pb.h>
#include <libcockatrice/protocol/pb/command_draw_cards.pb.h>
#include <libcockatrice/protocol/pb/command_flip_card.pb.h>
@@ -217,7 +218,7 @@ void PlayerActions::actAlwaysLookAtTopCard()
void PlayerActions::actOpenDeckInDeckEditor()
{
emit player->openDeckEditor(player->getDeck());
emit player->openDeckEditor({.deckList = player->getDeck()});
}
void PlayerActions::actViewGraveyard()
@@ -309,28 +310,48 @@ void PlayerActions::actMulligan()
{
int startSize = SettingsCache::instance().getStartingHandSize();
int handSize = player->getHandZone()->getCards().size();
int deckSize = player->getDeckZone()->getCards().size() + handSize; // hand is shuffled back into the deck
int deckSize = player->getDeckZone()->getCards().size() + handSize;
bool ok;
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Draw hand"),
tr("Number of cards: (max. %1)").arg(deckSize) + '\n' +
tr("0 and lower are in comparison to current hand size"),
startSize, -handSize, deckSize, 1, &ok);
if (!ok) {
return;
}
Command_Mulligan cmd;
if (number < 1) {
if (handSize == 0) {
return;
}
cmd.set_number(handSize + number);
} else {
cmd.set_number(number);
number = handSize + number;
}
doMulligan(number);
SettingsCache::instance().setStartingHandSize(number);
}
void PlayerActions::actMulliganSameSize()
{
int handSize = player->getHandZone()->getCards().size();
doMulligan(handSize);
}
void PlayerActions::actMulliganMinusOne()
{
int handSize = player->getHandZone()->getCards().size();
int targetSize = qMax(1, handSize - 1);
doMulligan(targetSize);
}
void PlayerActions::doMulligan(int number)
{
if (number < 1) {
return;
}
Command_Mulligan cmd;
cmd.set_number(number);
sendGameCommand(cmd);
if (startSize != number) {
SettingsCache::instance().setStartingHandSize(number);
}
}
void PlayerActions::actDrawCards()

View File

@@ -7,6 +7,7 @@
#ifndef COCKATRICE_PLAYER_ACTIONS_H
#define COCKATRICE_PLAYER_ACTIONS_H
#include "../dialogs/dlg_create_token.h"
#include "event_processing_options.h"
#include "player.h"
@@ -84,6 +85,9 @@ public slots:
void actDrawCards();
void actUndoDraw();
void actMulligan();
void actMulliganSameSize();
void actMulliganMinusOne();
void doMulligan(int number);
void actPlay();
void actPlayFacedown();

View File

@@ -6,6 +6,7 @@
#include "../board/card_list.h"
#include "../zones/view_zone.h"
#include "player.h"
#include "player_actions.h"
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
@@ -77,14 +78,7 @@ void PlayerEventHandler::eventShuffle(const Event_Shuffle &event)
void PlayerEventHandler::eventRollDie(const Event_RollDie &event)
{
if (!event.values().empty()) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QList<uint> rolls(event.values().begin(), event.values().end());
#else
QList<uint> rolls;
for (const auto &value : event.values()) {
rolls.append(value);
}
#endif
std::sort(rolls.begin(), rolls.end());
emit logRollDie(player, static_cast<int>(event.sides()), rolls);
} else if (event.value()) {

View File

@@ -1,7 +1,12 @@
#include "player_graphics_item.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../board/abstract_card_item.h"
#include "../hand_counter.h"
#include "../zones/hand_zone.h"
#include "../zones/pile_zone.h"
#include "../zones/stack_zone.h"
#include "../zones/table_zone.h"
PlayerGraphicsItem::PlayerGraphicsItem(Player *_player) : player(_player)
{

View File

@@ -7,11 +7,6 @@
#ifndef COCKATRICE_PLAYER_INFO_H
#define COCKATRICE_PLAYER_INFO_H
#include "../../interface/deck_loader/deck_loader.h"
#include "../zones/hand_zone.h"
#include "../zones/pile_zone.h"
#include "../zones/stack_zone.h"
#include "../zones/table_zone.h"
#include "player_target.h"
#include <QObject>

View File

@@ -4,15 +4,11 @@
#include "../../interface/widgets/server/user/user_context_menu.h"
#include "../../interface/widgets/server/user/user_list_manager.h"
#include "../../interface/widgets/server/user/user_list_widget.h"
#include "../../interface/widgets/tabs/tab_account.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../../interface/widgets/tabs/tab_supervisor.h"
#include <QAction>
#include <QHeaderView>
#include <QMenu>
#include <QMouseEvent>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/protocol/pb/command_kick_from_game.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_playerproperties.pb.h>
#include <libcockatrice/protocol/pb/session_commands.pb.h>

View File

@@ -11,7 +11,6 @@
#include "../board/abstract_counter.h"
#include "../board/arrow_target.h"
#include <QFont>
#include <QPixmap>
class Player;

View File

@@ -5,6 +5,7 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include <QPainter>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>

View File

@@ -2,7 +2,7 @@
#include "../../board/card_item.h"
#include "../../player/player.h"
#include "../pile_zone.h"
#include "../../player/player_actions.h"
#include "../view_zone.h"
#include "view_zone_logic.h"
@@ -10,7 +10,6 @@
#include <QDebug>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
/**
* @param _player the player that the zone belongs to
@@ -148,17 +147,24 @@ void CardZoneLogic::moveAllToZone()
void CardZoneLogic::clearContents()
{
for (int i = 0; i < cards.size(); i++) {
// First gather the cards into a safe temporary list.
const CardList toClear = cards;
// Detach and notify attached cards and zones *before* deleting anything.
for (CardItem *card : toClear) {
// If an incorrectly implemented server doesn't return attached cards to whom they belong before dropping a
// player, we have to return them to avoid a crash.
const QList<CardItem *> &attachedCards = cards[i]->getAttachedCards();
for (auto attachedCard : attachedCards) {
const QList<CardItem *> &attachedCards = card->getAttachedCards();
for (CardItem *attachedCard : attachedCards) {
emit attachedCard->getZone()->cardAdded(attachedCard);
}
player->deleteCard(cards.at(i));
}
// Now request deletions after all manipulations are done.
for (CardItem *card : toClear) {
player->deleteCard(card);
}
cards.clear();
emit cardCountChanged();
}

View File

@@ -52,7 +52,7 @@ public:
void rawInsertCard(CardItem *card, int index)
{
cards.insert(index, card);
};
}
[[nodiscard]] const CardList &getCards() const
{

View File

@@ -3,6 +3,7 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "logic/pile_zone_logic.h"
#include "view_zone.h"

View File

@@ -6,10 +6,10 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "logic/stack_zone_logic.h"
#include <QPainter>
#include <QSet>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
StackZone::StackZone(StackZoneLogic *_logic, int _zoneHeight, QGraphicsItem *parent)

View File

@@ -6,11 +6,11 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "logic/table_zone_logic.h"
#include <QGraphicsScene>
#include <QPainter>
#include <QSet>
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>

View File

@@ -3,6 +3,7 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "logic/view_zone_logic.h"
#include <QBrush>
@@ -10,7 +11,6 @@
#include <QGraphicsSceneWheelEvent>
#include <QPainter>
#include <QtMath>
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/protocol/pb/command_dump_zone.pb.h>
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
#include <libcockatrice/protocol/pb/response_dump_zone.pb.h>

View File

@@ -6,19 +6,27 @@
#include "../board/card_item.h"
#include "../game_scene.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "view_zone.h"
#include <QCheckBox>
#include <QGraphicsLinearLayout>
#include <QGraphicsProxyWidget>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QLabel>
#include <QPainter>
#include <QScrollBar>
#include <QStyle>
#include <QStyleOption>
#include <QStyleOptionTitleBar>
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
namespace
{
constexpr qreal kTitleBarHeight = 24.0;
constexpr qreal kMinVisibleWidth = 100.0;
} // namespace
/**
* @param _player the player the cards were revealed to.
* @param _origZone the zone the cards were revealed from.
@@ -241,33 +249,191 @@ void ZoneViewWidget::retranslateUi()
pileViewCheckBox.setText(tr("pile view"));
}
void ZoneViewWidget::moveEvent(QGraphicsSceneMoveEvent * /* event */)
void ZoneViewWidget::stopWindowDrag()
{
if (!scene())
if (!draggingWindow)
return;
int titleBarHeight = 24;
draggingWindow = false;
ungrabMouse();
}
QPointF scenePos = pos();
void ZoneViewWidget::startWindowDrag(QGraphicsSceneMouseEvent *event)
{
draggingWindow = true;
dragStartItemPos = pos();
dragStartScreenPos = event->screenPos();
dragView = findDragView(event->widget());
if (scenePos.x() < 0) {
scenePos.setX(0);
} else {
qreal maxw = scene()->sceneRect().width() - 100;
if (scenePos.x() > maxw)
scenePos.setX(maxw);
// need to grab mouse to receive events and not miss initial movement
grabMouse();
}
QRectF ZoneViewWidget::closeButtonRect(QWidget *styleWidget) const
{
const QRectF frameRectF = windowFrameRect();
// query the style for the close button position (handles macOS top-left placement)
// Title bar rect MUST be local (0,0-based) for QStyle
const QRect titleBarRect(0, 0, static_cast<int>(frameRectF.width()), static_cast<int>(kTitleBarHeight));
if (styleWidget) {
QStyleOptionTitleBar opt;
opt.initFrom(styleWidget);
opt.rect = titleBarRect;
opt.text = windowTitle();
opt.icon = styleWidget->windowIcon();
opt.titleBarFlags = Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
opt.subControls = QStyle::SC_TitleBarCloseButton;
opt.activeSubControls = QStyle::SC_TitleBarCloseButton;
opt.titleBarState = styleWidget->isActiveWindow() ? Qt::WindowActive : Qt::WindowNoState;
if (styleWidget->isActiveWindow()) {
opt.state |= QStyle::State_Active;
}
QRect r = styleWidget->style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarCloseButton,
styleWidget);
if (r.isValid() && !r.isEmpty()) {
// Translate from local-titlebar coords → frame coords
r.translate(frameRectF.topLeft().toPoint());
return QRectF(r);
}
}
if (scenePos.y() < titleBarHeight) {
scenePos.setY(titleBarHeight);
} else {
qreal maxh = scene()->sceneRect().height() - titleBarHeight;
if (scenePos.y() > maxh)
scenePos.setY(maxh);
// Fallback: frame-relative top-right
return QRectF(frameRectF.right() - kTitleBarHeight, frameRectF.top(), kTitleBarHeight, kTitleBarHeight);
}
QGraphicsView *ZoneViewWidget::findDragView(QWidget *eventWidget) const
{
QWidget *current = eventWidget;
while (current) {
if (auto *view = qobject_cast<QGraphicsView *>(current))
return view;
current = current->parentWidget();
}
if (scenePos != pos())
setPos(scenePos);
if (scene() && !scene()->views().isEmpty())
return scene()->views().constFirst();
return nullptr;
}
QPointF ZoneViewWidget::calcDraggedWindowPos(const QPoint &screenPos,
const QPointF &scenePos,
const QPointF &buttonDownScenePos) const
{
if (dragView && dragView->viewport()) {
const QPoint vpStart = dragView->viewport()->mapFromGlobal(dragStartScreenPos);
const QPoint vpNow = dragView->viewport()->mapFromGlobal(screenPos);
const QPointF sceneStart = dragView->mapToScene(vpStart);
const QPointF sceneNow = dragView->mapToScene(vpNow);
return dragStartItemPos + (sceneNow - sceneStart);
}
return dragStartItemPos + (scenePos - buttonDownScenePos);
}
bool ZoneViewWidget::windowFrameEvent(QEvent *event)
{
if (event->type() == QEvent::UngrabMouse) {
stopWindowDrag();
return QGraphicsWidget::windowFrameEvent(event);
}
auto *me = dynamic_cast<QGraphicsSceneMouseEvent *>(event);
if (!me)
return QGraphicsWidget::windowFrameEvent(event);
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:
if (me->button() == Qt::LeftButton && windowFrameSectionAt(me->pos()) == Qt::TitleBarArea) {
// avoid drag on close button
if (closeButtonRect(me->widget()).contains(me->pos())) {
me->accept();
close();
return true;
}
startWindowDrag(me);
me->accept();
return true;
}
break;
case QEvent::GraphicsSceneMouseMove:
if (draggingWindow) {
if (!(me->buttons() & Qt::LeftButton)) {
stopWindowDrag();
} else {
setPos(
calcDraggedWindowPos(me->screenPos(), me->scenePos(), me->buttonDownScenePos(Qt::LeftButton)));
}
me->accept();
return true;
}
break;
case QEvent::GraphicsSceneMouseRelease:
if (draggingWindow && me->button() == Qt::LeftButton) {
stopWindowDrag();
me->accept();
return true;
}
break;
default:
break;
}
return QGraphicsWidget::windowFrameEvent(event);
}
void ZoneViewWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// move if the scene routes moves while dragging
if (draggingWindow && (event->buttons() & Qt::LeftButton)) {
setPos(calcDraggedWindowPos(event->screenPos(), event->scenePos(), event->buttonDownScenePos(Qt::LeftButton)));
event->accept();
return;
}
QGraphicsWidget::mouseMoveEvent(event);
}
void ZoneViewWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (draggingWindow && event->button() == Qt::LeftButton) {
stopWindowDrag();
event->accept();
return;
}
QGraphicsWidget::mouseReleaseEvent(event);
}
QVariant ZoneViewWidget::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemPositionChange && scene()) {
// Keep grab area in main view
const QRectF sceneRect = scene()->sceneRect();
const QPointF requestedPos = value.toPointF();
QPointF desiredPos = requestedPos;
const qreal minX = sceneRect.left();
const qreal maxX = qMax(minX, sceneRect.right() - kMinVisibleWidth);
const qreal minY = sceneRect.top() + kTitleBarHeight;
const qreal maxY = qMax(minY, sceneRect.bottom() - kTitleBarHeight);
desiredPos.setX(qBound(minX, desiredPos.x(), maxX));
desiredPos.setY(qBound(minY, desiredPos.y(), maxY));
return desiredPos;
}
return QGraphicsWidget::itemChange(change, value);
}
void ZoneViewWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
@@ -350,6 +516,7 @@ void ZoneViewWidget::handleScrollBarChange(int value)
void ZoneViewWidget::closeEvent(QCloseEvent *event)
{
stopWindowDrag();
disconnect(zone, &ZoneViewZone::closed, this, 0);
// manually call zone->close in order to remove it from the origZones views
zone->close();

View File

@@ -3,7 +3,6 @@
* @ingroup GameGraphicsZones
* @brief TODO: Document this.
*/
#ifndef ZONEVIEWWIDGET_H
#define ZONEVIEWWIDGET_H
@@ -14,6 +13,7 @@
#include <QGraphicsProxyWidget>
#include <QGraphicsWidget>
#include <QLineEdit>
#include <QPointer>
#include <libcockatrice/utility/macros.h>
class QLabel;
@@ -28,6 +28,8 @@ class ServerInfo_Card;
class QGraphicsSceneMouseEvent;
class QGraphicsSceneWheelEvent;
class QStyleOption;
class QGraphicsView;
class QWidget;
class ScrollableGraphicsProxyWidget : public QGraphicsProxyWidget
{
@@ -52,7 +54,6 @@ private:
ZoneViewZone *zone;
QGraphicsWidget *zoneContainer;
QPushButton *closeButton;
QScrollBar *scrollBar;
ScrollableGraphicsProxyWidget *scrollBarProxy;
@@ -66,6 +67,33 @@ private:
int extraHeight;
Player *player;
bool draggingWindow = false;
QPoint dragStartScreenPos;
QPointF dragStartItemPos;
QPointer<QGraphicsView> dragView;
void stopWindowDrag();
void startWindowDrag(QGraphicsSceneMouseEvent *event);
QRectF closeButtonRect(QWidget *styleWidget) const;
/**
* @brief Resolves the QGraphicsView to use for drag coordinate mapping
*
* @param eventWidget QWidget that originated the mouse event
* @return The resolved QGraphicsView
*/
QGraphicsView *findDragView(QWidget *eventWidget) const;
/**
* @brief Calculates the desired widget position while dragging
*
* @param screenPos Global screen coordinates of the current mouse position
* @param scenePos Scene coordinates of the current mouse position
* @param buttonDownScenePos Scene coordinates of the initial mouse press position
*
* @return The new widget position in scene coordinates
*/
QPointF
calcDraggedWindowPos(const QPoint &screenPos, const QPointF &scenePos, const QPointF &buttonDownScenePos) const;
void resizeScrollbar(qreal newZoneHeight);
signals:
void closePressed(ZoneViewWidget *zv);
@@ -76,7 +104,6 @@ private slots:
void resizeToZoneContents(bool forceInitialHeight = false);
void handleScrollBarChange(int value);
void zoneDeleted();
void moveEvent(QGraphicsSceneMoveEvent * /* event */) override;
void resizeEvent(QGraphicsSceneResizeEvent * /* event */) override;
void expandWindow();
@@ -101,6 +128,10 @@ public:
protected:
void closeEvent(QCloseEvent *event) override;
void initStyleOption(QStyleOption *option) const override;
bool windowFrameEvent(QEvent *event) override;
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
};

View File

@@ -17,12 +17,7 @@ void AbstractGraphicsItem::paintNumberEllipse(int number,
font.setWeight(QFont::Bold);
QFontMetrics fm(font);
double w = 1.3 *
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
fm.horizontalAdvance(numStr);
#else
fm.width(numStr);
#endif
double w = 1.3 * fm.horizontalAdvance(numStr);
double h = fm.height() * 1.3;
if (w < h)
w = h;

View File

@@ -9,7 +9,6 @@
#include <QFileInfo>
#include <QMainWindow>
#include <QMovie>
#include <QNetworkDiskCache>
#include <QNetworkRequest>
#include <QPainter>
#include <QPixmapCache>

View File

@@ -5,7 +5,6 @@
#include "card_picture_loader_worker.h"
#include <QLoggingCategory>
#include <libcockatrice/card/card_info.h>
inline Q_LOGGING_CATEGORY(CardPictureLoaderLog, "card_picture_loader");
inline Q_LOGGING_CATEGORY(CardPictureLoaderCardBackCacheFailLog, "card_picture_loader.card_back_cache_fail");

View File

@@ -1,8 +1,6 @@
#ifndef PICTURE_LOADER_LOCAL_H
#define PICTURE_LOADER_LOCAL_H
#include <QLoggingCategory>
#include <QObject>
#include <QTimer>
#include <libcockatrice/card/printing/exact_card.h>
@@ -42,7 +40,7 @@ public:
*
* Uses a set of name variants and folder paths to attempt to locate the correct image.
*/
QImage tryLoad(const ExactCard &toLoad) const;
[[nodiscard]] QImage tryLoad(const ExactCard &toLoad) const;
private:
QString picsPath; ///< Path to standard card image folder
@@ -72,10 +70,10 @@ private:
* Uses several filename patterns to match card images, in order from
* most-specific to least-specific.
*/
QImage tryLoadCardImageFromDisk(const QString &setName,
const QString &correctedCardName,
const QString &collectorNumber,
const QString &providerId) const;
[[nodiscard]] QImage tryLoadCardImageFromDisk(const QString &setName,
const QString &correctedCardName,
const QString &collectorNumber,
const QString &providerId) const;
private slots:
/**

View File

@@ -1,11 +1,11 @@
#ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
#include "card_picture_loader_worker_work.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QUrl>
#include <QWidget>
#include <libcockatrice/card/printing/exact_card.h>
/**
* @class CardPictureLoaderRequestStatusDisplayWidget

View File

@@ -6,7 +6,6 @@
#include <QHBoxLayout>
#include <QProgressBar>
#include <QTimer>
#include <QWidget>
/**

View File

@@ -9,8 +9,8 @@
#include <QNetworkDiskCache>
#include <QNetworkReply>
#include <QThread>
#include <libcockatrice/card/database/card_database_manager.h>
#include <utility>
#include <version_string.h>
static constexpr int MAX_REQUESTS_PER_SEC = 10;
@@ -21,9 +21,7 @@ CardPictureLoaderWorker::CardPictureLoaderWorker()
// We need a timeout to ensure requests don't hang indefinitely in case of
// cache corruption, see related Qt bug: https://bugreports.qt.io/browse/QTBUG-111397
// Use Qt's default timeout (30s, as of 2023-02-22)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
networkManager->setTransferTimeout();
#endif
cache = new QNetworkDiskCache(this);
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
cache->setMaximumCacheSize(1024L * 1024L *
@@ -87,6 +85,7 @@ QNetworkReply *CardPictureLoaderWorker::makeRequest(const QUrl &url, CardPicture
}
QNetworkRequest req(url);
req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
if (!picDownload) {
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
}

View File

@@ -7,11 +7,9 @@
#include <QDirIterator>
#include <QLoggingCategory>
#include <QMovie>
#include <QNetworkDiskCache>
#include <QNetworkReply>
#include <QThread>
#include <QThreadPool>
#include <libcockatrice/card/database/card_database_manager.h>
// Card back returned by gatherer when card is not found
static const QStringList MD5_BLACKLIST = {"db0c48db407a907c16ade38de048a441"};

View File

@@ -1,7 +1,6 @@
#ifndef PICTURE_TO_LOAD_H
#define PICTURE_TO_LOAD_H
#include <QLoggingCategory>
#include <libcockatrice/card/printing/exact_card.h>
inline Q_LOGGING_CATEGORY(CardPictureToLoadLog, "card_picture_loader.picture_to_load");

View File

@@ -0,0 +1,40 @@
#include "card_node_function.h"
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
void CardNodeFunction::SetProviderIdToPreferred::operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
{
Q_UNUSED(node);
PrintingInfo preferredPrinting = CardDatabaseManager::query()->getPreferredPrinting(card->getName());
QString providerId = preferredPrinting.getUuid();
QString setShortName = preferredPrinting.getSet()->getShortName();
QString collectorNumber = preferredPrinting.getProperty("num");
card->setCardProviderId(providerId);
card->setCardCollectorNumber(collectorNumber);
card->setCardSetShortName(setShortName);
}
void CardNodeFunction::ClearPrintingData::operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
{
Q_UNUSED(node);
card->setCardSetShortName(nullptr);
card->setCardCollectorNumber(nullptr);
card->setCardProviderId(nullptr);
}
void CardNodeFunction::ResolveProviderId::operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
{
Q_UNUSED(node);
// Retrieve the providerId based on setName and collectorNumber
QString providerId =
CardDatabaseManager::getInstance()
->query()
->getSpecificPrinting(card->getName(), card->getCardSetShortName(), card->getCardCollectorNumber())
.getUuid();
// Set the providerId on the card
card->setCardProviderId(providerId);
}

View File

@@ -0,0 +1,39 @@
#ifndef COCKATRICE_DECK_FUNCTION_H
#define COCKATRICE_DECK_FUNCTION_H
class DecklistCardNode;
class InnerDecklistNode;
/**
* Functions to be used with DeckList::forEachCard
*/
namespace CardNodeFunction
{
/**
* @brief Sets the providerId of the card to the preferred printing.
*/
struct SetProviderIdToPreferred
{
void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const;
};
/**
* @brief Clears all fields on the card related to the printing
*/
struct ClearPrintingData
{
void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const;
};
/**
* @brief Sets the providerId of the card based on its set name and collector number.
*/
struct ResolveProviderId
{
void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const;
};
} // namespace CardNodeFunction
#endif // COCKATRICE_DECK_FUNCTION_H

View File

@@ -0,0 +1,9 @@
#include "deck_file_format.h"
DeckFileFormat::Format DeckFileFormat::getFormatFromName(const QString &fileName)
{
if (fileName.endsWith(".cod", Qt::CaseInsensitive)) {
return Cockatrice;
}
return PlainText;
}

View File

@@ -0,0 +1,36 @@
#ifndef COCKATRICE_DECK_FILE_FORMAT_H
#define COCKATRICE_DECK_FILE_FORMAT_H
#include <QString>
namespace DeckFileFormat
{
/**
* The deck file formats that Cockatrice supports.
*/
enum Format
{
/**
* Plaintext deck files, a format that is intended to be widely supported among different programs.
* This format does not support Cockatrice specific features such as banner cards or tags.
*/
PlainText,
/**
* This is cockatrice's native deck file format, and supports deck metadata such as banner cards and tags.
* Stored as .cod files.
*/
Cockatrice
};
/**
* Determines what deck file format the given filename corresponds to.
*
* @param fileName The filename
* @return The deck format
*/
Format getFormatFromName(const QString &fileName);
} // namespace DeckFileFormat
#endif // COCKATRICE_DECK_FILE_FORMAT_H

View File

@@ -18,24 +18,18 @@
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
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(QObject *parent)
: QObject(parent), deckList(new DeckList()), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
DeckLoader::DeckLoader(QObject *parent) : QObject(parent)
{
}
DeckLoader::DeckLoader(QObject *parent, DeckList *_deckList)
: QObject(parent), deckList(_deckList), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
{
}
bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest)
bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
@@ -43,18 +37,19 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool user
}
bool result = false;
DeckList deckList = DeckList();
switch (fmt) {
case PlainTextFormat:
result = deckList->loadFromFile_Plain(&file);
case DeckFileFormat::PlainText:
result = deckList.loadFromFile_Plain(&file);
break;
case CockatriceFormat: {
result = deckList->loadFromFile_Native(&file);
case DeckFileFormat::Cockatrice: {
result = deckList.loadFromFile_Native(&file);
qCInfo(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
if (!result) {
qCInfo(DeckLoaderLog) << "Retrying as plain format";
file.seek(0);
result = deckList->loadFromFile_Plain(&file);
fmt = PlainTextFormat;
result = deckList.loadFromFile_Plain(&file);
fmt = DeckFileFormat::PlainText;
}
break;
}
@@ -64,8 +59,11 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool user
}
if (result) {
lastFileName = fileName;
lastFileFormat = fmt;
loadedDeck.deckList = deckList;
loadedDeck.lastLoadInfo = {
.fileName = fileName,
.fileFormat = fmt,
};
if (userRequest) {
updateLastLoadedTimestamp(fileName, fmt);
}
@@ -77,7 +75,7 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool user
return result;
}
bool DeckLoader::loadFromFileAsync(const QString &fileName, FileFormat fmt, bool userRequest)
bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
{
auto *watcher = new QFutureWatcher<bool>(this);
@@ -86,8 +84,10 @@ bool DeckLoader::loadFromFileAsync(const QString &fileName, FileFormat fmt, bool
watcher->deleteLater();
if (result) {
lastFileName = fileName;
lastFileFormat = fmt;
loadedDeck.lastLoadInfo = {
.fileName = fileName,
.fileFormat = fmt,
};
if (userRequest) {
updateLastLoadedTimestamp(fileName, fmt);
}
@@ -104,14 +104,14 @@ bool DeckLoader::loadFromFileAsync(const QString &fileName, FileFormat fmt, bool
}
switch (fmt) {
case PlainTextFormat:
return deckList->loadFromFile_Plain(&file);
case CockatriceFormat: {
case DeckFileFormat::PlainText:
return loadedDeck.deckList.loadFromFile_Plain(&file);
case DeckFileFormat::Cockatrice: {
bool result = false;
result = deckList->loadFromFile_Native(&file);
result = loadedDeck.deckList.loadFromFile_Native(&file);
if (!result) {
file.seek(0);
return deckList->loadFromFile_Plain(&file);
return loadedDeck.deckList.loadFromFile_Plain(&file);
}
return result;
}
@@ -127,18 +127,18 @@ bool DeckLoader::loadFromFileAsync(const QString &fileName, FileFormat fmt, bool
bool DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId)
{
bool result = deckList->loadFromString_Native(nativeString);
bool result = loadedDeck.deckList.loadFromString_Native(nativeString);
if (result) {
lastFileName = QString();
lastFileFormat = CockatriceFormat;
lastRemoteDeckId = remoteDeckId;
loadedDeck.lastLoadInfo = {
.remoteDeckId = remoteDeckId,
};
emit deckLoaded();
}
return result;
}
bool DeckLoader::saveToFile(const QString &fileName, FileFormat fmt)
bool DeckLoader::saveToFile(const QString &fileName, DeckFileFormat::Format fmt)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
@@ -147,18 +147,20 @@ bool DeckLoader::saveToFile(const QString &fileName, FileFormat fmt)
bool result = false;
switch (fmt) {
case PlainTextFormat:
result = deckList->saveToFile_Plain(&file);
case DeckFileFormat::PlainText:
result = loadedDeck.deckList.saveToFile_Plain(&file);
break;
case CockatriceFormat:
result = deckList->saveToFile_Native(&file);
case DeckFileFormat::Cockatrice:
result = loadedDeck.deckList.saveToFile_Native(&file);
qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result;
break;
}
if (result) {
lastFileName = fileName;
lastFileFormat = fmt;
loadedDeck.lastLoadInfo = {
.fileName = fileName,
.fileFormat = fmt,
};
qCInfo(DeckLoaderLog) << "Deck was saved -" << result;
}
@@ -168,7 +170,7 @@ bool DeckLoader::saveToFile(const QString &fileName, FileFormat fmt)
return result;
}
bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt)
bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt)
{
QFileInfo fileInfo(fileName);
if (!fileInfo.exists()) {
@@ -189,20 +191,22 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, FileFormat f
// Perform file modifications
switch (fmt) {
case PlainTextFormat:
result = deckList->saveToFile_Plain(&file);
case DeckFileFormat::PlainText:
result = loadedDeck.deckList.saveToFile_Plain(&file);
break;
case CockatriceFormat:
deckList->setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
result = deckList->saveToFile_Native(&file);
case DeckFileFormat::Cockatrice:
loadedDeck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
result = loadedDeck.deckList.saveToFile_Native(&file);
break;
}
file.close(); // Close the file to ensure changes are flushed
if (result) {
lastFileName = fileName;
lastFileFormat = fmt;
loadedDeck.lastLoadInfo = {
.fileName = fileName,
.fileFormat = fmt,
};
// Re-open the file and set the original timestamp
if (!file.open(QIODevice::ReadWrite)) {
@@ -263,39 +267,35 @@ static QString toDecklistExportString(const DecklistCardNode *card)
return cardString;
}
/**
* Converts all cards in the list to their decklist export string and joins them into one string
*/
static QString toDecklistExportString(const QList<const DecklistCardNode *> &cardNodes)
{
QString result;
for (auto cardNode : cardNodes) {
result += toDecklistExportString(cardNode);
}
return result;
}
/**
* Export deck to decklist function, called to format the deck in a way to be sent to a server
*
* @param deckList The decklist to export
* @param website The website we're sending the deck to
*/
QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website)
QString DeckLoader::exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website)
{
// Add the base url
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
// Create two strings to pass to function
QString mainBoardCards, sideBoardCards;
// Set up the function to call
auto formatDeckListForExport = [&mainBoardCards, &sideBoardCards](const auto *node, const auto *card) {
// Get the card name
CardInfoPtr dbCard = CardDatabaseManager::query()->getCardInfo(card->getName());
if (!dbCard || dbCard->getIsToken()) {
// If it's a token, we don't care about the card.
return;
}
// export all cards in zone
QString mainBoardCards = toDecklistExportString(deckList.getCardNodes({DECK_ZONE_MAIN}));
QString sideBoardCards = toDecklistExportString(deckList.getCardNodes({DECK_ZONE_SIDE}));
// Check if it's a sideboard card.
if (node->getName() == DECK_ZONE_SIDE) {
sideBoardCards += toDecklistExportString(card);
} else {
// If it's a mainboard card, do the same thing, but for the mainboard card string
mainBoardCards += toDecklistExportString(card);
}
};
// call our struct function for each card in the deck
deckList->forEachCard(formatDeckListForExport);
// Remove the extra return at the end of the last cards
mainBoardCards.chop(3);
sideBoardCards.chop(3);
@@ -310,113 +310,7 @@ QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsi
return deckString;
}
// This struct is here to support the forEachCard function call, defined in decklist.
// It requires a function to be called for each card, and it will set the providerId to the preferred printing.
struct SetProviderIdToPreferred
{
// Main operator for struct, allowing the foreachcard to work.
SetProviderIdToPreferred()
{
}
void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
{
Q_UNUSED(node);
PrintingInfo preferredPrinting = CardDatabaseManager::query()->getPreferredPrinting(card->getName());
QString providerId = preferredPrinting.getUuid();
QString setShortName = preferredPrinting.getSet()->getShortName();
QString collectorNumber = preferredPrinting.getProperty("num");
card->setCardProviderId(providerId);
card->setCardCollectorNumber(collectorNumber);
card->setCardSetShortName(setShortName);
}
};
/**
* This function iterates through each card in the decklist and sets the providerId
* on each card based on its set name and collector number.
*
* @param deckList The decklist to modify
*/
void DeckLoader::setProviderIdToPreferredPrinting(const DeckList *deckList)
{
// Set up the struct to call.
SetProviderIdToPreferred setProviderIdToPreferred;
// Call the forEachCard method for each card in the deck
deckList->forEachCard(setProviderIdToPreferred);
}
/**
* Sets the providerId on each card in the decklist based on its set name and collector number.
*
* @param deckList The decklist to modify
*/
void DeckLoader::resolveSetNameAndNumberToProviderID(const DeckList *deckList)
{
auto setProviderId = [](const auto node, const auto card) {
Q_UNUSED(node);
// Retrieve the providerId based on setName and collectorNumber
QString providerId =
CardDatabaseManager::getInstance()
->query()
->getSpecificPrinting(card->getName(), card->getCardSetShortName(), card->getCardCollectorNumber())
.getUuid();
// Set the providerId on the card
card->setCardProviderId(providerId);
};
deckList->forEachCard(setProviderId);
}
// This struct is here to support the forEachCard function call, defined in decklist.
// It requires a function to be called for each card, and it will set the providerId.
struct ClearSetNameNumberAndProviderId
{
// Main operator for struct, allowing the foreachcard to work.
ClearSetNameNumberAndProviderId()
{
}
void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
{
Q_UNUSED(node);
// Set the providerId on the card
card->setCardSetShortName(nullptr);
card->setCardCollectorNumber(nullptr);
card->setCardProviderId(nullptr);
}
};
/**
* Clears the set name and numbers on each card in the decklist.
*
* @param deckList The decklist to modify
*/
void DeckLoader::clearSetNamesAndNumbers(const DeckList *deckList)
{
auto clearSetNameAndNumber = [](const auto node, auto card) {
Q_UNUSED(node)
// Set the providerId on the card
card->setCardSetShortName(nullptr);
card->setCardCollectorNumber(nullptr);
card->setCardProviderId(nullptr);
};
deckList->forEachCard(clearSetNameAndNumber);
}
DeckLoader::FileFormat DeckLoader::getFormatFromName(const QString &fileName)
{
if (fileName.endsWith(".cod", Qt::CaseInsensitive)) {
return CockatriceFormat;
}
return PlainTextFormat;
}
void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, bool addSetNameAndNumber)
void DeckLoader::saveToClipboard(const DeckList &deckList, bool addComments, bool addSetNameAndNumber)
{
QString buffer;
QTextStream stream(&buffer);
@@ -426,7 +320,7 @@ void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, boo
}
bool DeckLoader::saveToStream_Plain(QTextStream &out,
const DeckList *deckList,
const DeckList &deckList,
bool addComments,
bool addSetNameAndNumber)
{
@@ -435,9 +329,7 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out,
}
// loop zones
for (int i = 0; i < deckList->getRoot()->size(); i++) {
const auto *zoneNode = dynamic_cast<InnerDecklistNode *>(deckList->getRoot()->at(i));
for (auto zoneNode : deckList.getZoneNodes()) {
saveToStream_DeckZone(out, zoneNode, addComments, addSetNameAndNumber);
// end of zone
@@ -447,14 +339,14 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out,
return true;
}
void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList)
void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList)
{
if (!deckList->getName().isEmpty()) {
out << "// " << deckList->getName() << "\n\n";
if (!deckList.getName().isEmpty()) {
out << "// " << deckList.getName() << "\n\n";
}
if (!deckList->getComments().isEmpty()) {
QStringList commentRows = deckList->getComments().split(QRegularExpression("\n|\r\n|\r"));
if (!deckList.getComments().isEmpty()) {
QStringList commentRows = deckList.getComments().split(QRegularExpression("\n|\r\n|\r"));
for (const QString &row : commentRows) {
out << "// " << row << "\n";
}
@@ -542,7 +434,7 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
}
}
bool DeckLoader::convertToCockatriceFormat(QString fileName)
bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
{
// Change the file extension to .cod
QFileInfo fileInfo(fileName);
@@ -558,12 +450,12 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
bool result = false;
// Perform file modifications based on the detected format
switch (getFormatFromName(fileName)) {
case PlainTextFormat:
switch (DeckFileFormat::getFormatFromName(fileName)) {
case DeckFileFormat::PlainText:
// Save in Cockatrice's native format
result = deckList->saveToFile_Native(&file);
result = loadedDeck.deckList.saveToFile_Native(&file);
break;
case CockatriceFormat:
case DeckFileFormat::Cockatrice:
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
result = true;
break;
@@ -582,37 +474,16 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
} else {
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
}
lastFileName = newFileName;
lastFileFormat = CockatriceFormat;
loadedDeck.lastLoadInfo = {
.fileName = newFileName,
.fileFormat = DeckFileFormat::Cockatrice,
};
}
return result;
}
QString DeckLoader::getCardZoneFromName(const QString &cardName, QString currentZoneName)
{
CardInfoPtr card = CardDatabaseManager::query()->getCardInfo(cardName);
if (card && card->getIsToken()) {
return DECK_ZONE_TOKENS;
}
return currentZoneName;
}
QString DeckLoader::getCompleteCardName(const QString &cardName)
{
if (CardDatabaseManager::getInstance()) {
ExactCard temp = CardDatabaseManager::query()->guessCard({cardName});
if (temp) {
return temp.getName();
}
}
return cardName;
}
void DeckLoader::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node)
void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node)
{
const int totalColumns = 2;
@@ -672,7 +543,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node)
cursor->movePosition(QTextCursor::End);
}
void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList)
void DeckLoader::printDeckList(QPrinter *printer, const DeckList &deckList)
{
QTextDocument doc;
@@ -688,19 +559,18 @@ void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList)
headerCharFormat.setFontWeight(QFont::Bold);
cursor.insertBlock(headerBlockFormat, headerCharFormat);
cursor.insertText(deckList->getName());
cursor.insertText(deckList.getName());
headerCharFormat.setFontPointSize(12);
cursor.insertBlock(headerBlockFormat, headerCharFormat);
cursor.insertText(deckList->getComments());
cursor.insertText(deckList.getComments());
cursor.insertBlock(headerBlockFormat, headerCharFormat);
for (int i = 0; i < deckList->getRoot()->size(); i++) {
for (auto zoneNode : deckList.getZoneNodes()) {
cursor.insertHtml("<br><img src=theme:hr.jpg>");
// cursor.insertHtml("<hr>");
cursor.insertBlock(headerBlockFormat, headerCharFormat);
printDeckListNode(&cursor, dynamic_cast<InnerDecklistNode *>(deckList->getRoot()->at(i)));
printDeckListNode(&cursor, zoneNode);
}
doc.print(printer);

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