mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
[Tests] Play card interactions through a Cockatrice event player (#7697)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
34201122ec
commit
3fa8d78786
14 changed files with 1119 additions and 3 deletions
|
|
@ -50,3 +50,17 @@ A test is a `<events>` list. Widgets are named by their path from the main windo
|
|||
| `activate` | action or menu name | triggers a QAction (menus are opened first) |
|
||||
| `key` | Qt key code | presses that key on the focused widget |
|
||||
| `pause` | milliseconds | waits, letting the UI settle |
|
||||
| `clickCard` | `card,zone` | double click the card found in that zone (plays it from hand) |
|
||||
| `flipCard` | `card,zone` | right-click → *Turn Over* |
|
||||
| `cardAction` | `card,zone,label` | right-click → first menu entry whose label contains `label` (submenus included) |
|
||||
| `moveCard` | `card,srcZone,dstZone` | drags the card onto the destination zone |
|
||||
| `drawArrow` | `srcCard,srcZone,dstCard,dstZone` | right-drag an arrow between two cards |
|
||||
| `createToken` | `name,color,pt` | creates a token as the active local player |
|
||||
| `selectItem` | `item label` | selects the tree/list entry with that label |
|
||||
| `typeText` | `text` | types text one key event at a time |
|
||||
| `expectProperty` | `property,value` | fails playback unless the widget property matches |
|
||||
|
||||
The card, item and property commands are `pqCockatriceEventPlayer`
|
||||
(`cockatrice/src/game_graphics/pq_cockatrice_event_player.h`). They resolve cards by name
|
||||
and zone through the `QGraphicsScene` and send real mouse events at the card's current
|
||||
viewport position, so a test does not depend on the window size or screen resolution.
|
||||
|
|
|
|||
69
Testing/card_actions_test.xml
Normal file
69
Testing/card_actions_test.xml
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<events>
|
||||
<!--
|
||||
Card actions (custom commands of pqCockatriceEventPlayer).
|
||||
|
||||
Exercises the context menu path (tap, counters in a submenu, flip),
|
||||
arrow drawing, and dragging a card between zones. All of it through
|
||||
mouse events on the game view, so the same file runs at any resolution.
|
||||
-->
|
||||
|
||||
<!-- ===== Two-player local game ===== -->
|
||||
<event widget="MainWindow/menubar/cockatriceMenu" command="activate" arguments="Start &local game..." />
|
||||
<event widget="MainWindow/localGameDialog/generalGroupBox/numberPlayersEdit" command="set_int" arguments="2" />
|
||||
<event widget="MainWindow/localGameDialog" command="key" arguments="16777220" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
|
||||
<!-- ===== Player 1 loads a one-card deck ===== -->
|
||||
<!-- (No tab-count assertion: the restored workspace state decides how many other
|
||||
tabs exist, and the paths below already prove the game tab is there.) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/loadFromClipboardButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="typeText" arguments="1 Lightning Bolt" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit" command="keyEvent" arguments="6,16777220,67108864,,0,1" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/readyStartButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
|
||||
<!-- ===== Player 2 loads the same deck and readies up ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/loadFromClipboardButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="typeText" arguments="1 Lightning Bolt" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit" command="keyEvent" arguments="6,16777220,67108864,,0,1" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/readyStartButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
|
||||
<!-- ===== Player 1, precombat main ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- ===== A token to interact with ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="createToken" arguments="Goblin,r,1/1" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
|
||||
<!-- Tap it through the context menu -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="cardAction" arguments="Goblin,table,Tap / Untap" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
|
||||
<!-- Add a counter: the entry lives in the "Card counters" submenu -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="cardAction" arguments="Goblin,table,Add counter (A)" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
|
||||
<!-- Flip it face down -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="flipCard" arguments="Goblin,table" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
|
||||
<!-- ===== An arrow from a second token to the Goblin ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="createToken" arguments="Elf,w,1/1" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="drawArrow" arguments="Elf,table,Goblin,table" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- ===== Drag the Goblin into the graveyard ===== -->
|
||||
<!-- A token that leaves the battlefield is destroyed rather than moved, so
|
||||
there is nothing to drag back afterwards. -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="moveCard" arguments="Goblin,table,grave" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
</events>
|
||||
101
Testing/game_mechanics_test.xml
Normal file
101
Testing/game_mechanics_test.xml
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
<events>
|
||||
<!--
|
||||
Tier 7: Game Mechanics
|
||||
Tests: play cards (clickCard), flip cards (flipCard),
|
||||
create tokens (createToken), draw arrows (drawArrow).
|
||||
All interactions are pure UI mouse events through the QGraphicsView viewport.
|
||||
-->
|
||||
|
||||
<!-- ===== Start a local 2-player game ===== -->
|
||||
<event widget="MainWindow/menubar/cockatriceMenu" command="activate" arguments="Start &local game..." />
|
||||
<!-- Force two players so both deck views exist, independent of the user's settings -->
|
||||
<event widget="MainWindow/localGameDialog/generalGroupBox/numberPlayersEdit" command="set_int" arguments="2" />
|
||||
<event widget="MainWindow/localGameDialog" command="key" arguments="16777220" />
|
||||
|
||||
<!-- ===== Player 1: Load 3-card deck ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/loadFromClipboardButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="keyEvent" arguments="6,65,67108864,,0,1" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="typeText" arguments="3 Lightning Bolt" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit" command="keyEvent" arguments="6,16777220,67108864,,0,1" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/readyStartButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
|
||||
<!-- ===== Player 2: Load same deck ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/loadFromClipboardButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="keyEvent" arguments="6,65,67108864,,0,1" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="typeText" arguments="3 Lightning Bolt" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit" command="keyEvent" arguments="6,16777220,67108864,,0,1" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/readyStartButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
|
||||
<!-- ===== Player 1, Turn 1 ===== -->
|
||||
<!-- Upkeep → Draw → Main 1 -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- Create a Goblin token -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="createToken" arguments="Goblin,r,1/1" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
|
||||
<!-- Create a second token (Elf) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="createToken" arguments="Elf,w,1/1" />
|
||||
<event widget="MainWindow" command="pause" arguments="1000" />
|
||||
|
||||
<!-- Flip the Goblin (right-click → Turn Over) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="flipCard" arguments="Goblin,table" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- Play a Lightning Bolt from hand (double-click) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="clickCard" arguments="Lightning Bolt,hand" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" -->
|
||||
|
||||
<!-- Draw arrow from Elf to Goblin (right-drag) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="drawArrow" arguments="Elf,table,Goblin,table" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- Advance through all remaining phases to end turn -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- ===== Player 2, Turn 1 ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<!-- Advance through all phases to end turn -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="200" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
</events>
|
||||
178
Testing/local_game_lifecycle_test.xml
Normal file
178
Testing/local_game_lifecycle_test.xml
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
<events>
|
||||
<!--
|
||||
Tier 6: Local Game Lifecycle (Extended)
|
||||
Tests: create game -> load decks -> ready up -> game starts
|
||||
-> play through turns using menu activate commands
|
||||
|
||||
Phase actions triggered via activate on phasesMenu:
|
||||
aNextPhaseAction advances phase + triggers phase action (e.g., draw at draw step)
|
||||
aNextTurn in gameMenu triggers next turn
|
||||
|
||||
This avoids keyboard shortcut issues in offscreen/test environments.
|
||||
-->
|
||||
|
||||
<!-- ===== Phase 1: Start a local game via main menu ===== -->
|
||||
<event widget="MainWindow/menubar/cockatriceMenu" command="activate" arguments="Start &local game..." />
|
||||
<!-- Force two players so both deck views exist, independent of the user's settings -->
|
||||
<event widget="MainWindow/localGameDialog/generalGroupBox/numberPlayersEdit" command="set_int" arguments="2" />
|
||||
<event widget="MainWindow/localGameDialog" command="key" arguments="16777220" />
|
||||
|
||||
<!-- ===== Phase 2: Player 1 loads deck from clipboard ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/loadFromClipboardButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="keyEvent" arguments="6,65,67108864,,0,1" />
|
||||
<!-- 1 Lightning Bolt -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="typeText" arguments="1 Lightning Bolt" />
|
||||
<!-- Ctrl+Return to accept clipboard dialog -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit" command="keyEvent" arguments="6,16777220,67108864,,0,1" />
|
||||
<!-- Delay -->
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Player 1 ready up -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_0/qt_tabwidget_stackedwidget/deckViewContainer/readyStartButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
|
||||
<!-- ===== Phase 3: Player 2 loads deck from clipboard ===== -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/loadFromClipboardButton" command="activate" arguments="" />
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="keyEvent" arguments="6,65,67108864,,0,1" />
|
||||
<!-- 1 Lightning Bolt -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit/contentsEdit" command="typeText" arguments="1 Lightning Bolt" />
|
||||
<!-- Ctrl+Return to accept clipboard dialog -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/dlgDeckTextEdit" command="keyEvent" arguments="6,16777220,67108864,,0,1" />
|
||||
<!-- Delay -->
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Player 2 ready up -> game auto-starts -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/deckViewContainerWidget/tabbedDeckView_1/qt_tabwidget_stackedwidget/deckViewContainer/readyStartButton" command="activate" arguments="" />
|
||||
<!-- Delay for game to start -->
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
|
||||
<!-- ===== Phase 4: Advance through all 11 phases via phasesMenu activate ===== -->
|
||||
<!-- Using activate on phasesMenu triggers aNextPhaseAction which:
|
||||
- advances the phase by 1
|
||||
- calls triggerPhaseAction (e.g., draw card at draw step, untap all at untap) -->
|
||||
|
||||
<!-- Phase 0 (Untap) → 1 (Upkeep) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 1 (Upkeep) → 2 (Draw): TRIGGERS DRAW — Player 1 draws 1 card -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
<!-- Phase 2 (Draw) → 3 (Main 1) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- ===== Main 1: Play a card from hand by double-click ===== -->
|
||||
<!-- clickCard resolves card by name in the scene, maps to viewport coords at current window size. -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/mainWidget/gamePlayAreaWidget/gameView" command="clickCard" arguments="Lightning Bolt,hand" />
|
||||
<event widget="MainWindow" command="pause" arguments="500" />
|
||||
|
||||
<!-- Phase 3 → 4 (Begin Combat) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="pause" arguments="300" />
|
||||
<!-- Phase 4 → 5 (Declare Attackers) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 5 → 6 (Declare Blockers) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 6 → 7 (Combat Damage) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 7 → 8 (End Combat) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 8 → 9 (Main 2) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 9 → 10 (Cleanup) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 10 → 0 (Untap): TRIGGERS NEXT TURN + UNTAP ALL — now Player 2's turn -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<!-- Delay for turn transition -->
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
|
||||
<!-- ===== Phase 5: Player 2's turn — advance through all 11 phases ===== -->
|
||||
<!-- Phase 0 (Untap) → 1 (Upkeep) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 1 (Upkeep) → 2 (Draw): TRIGGERS DRAW — Player 2 draws 1 card -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 2 (Draw) → 3 (Main 1) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 3 → 4 (Begin Combat) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 4 → 5 (Declare Attackers) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 5 → 6 (Declare Blockers) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 6 → 7 (Combat Damage) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 7 → 8 (End Combat) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 8 → 9 (Main 2) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 9 → 10 (Cleanup) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 10 → 0 (Untap): TRIGGERS NEXT TURN — back to Player 1 -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<!-- Delay -->
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
|
||||
<!-- ===== Phase 6: Player 1 turn 2 — advance to draw again ===== -->
|
||||
<!-- Phase 0 (Untap) → 1 (Upkeep) -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<!-- Phase 1 (Upkeep) → 2 (Draw): TRIGGERS DRAW — Player 1 draws again -->
|
||||
<event widget="MainWindow/tabSupervisor/stackedWidget/TabGame/phasesMenu" command="activate" arguments="aNextPhaseAction" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
<event widget="MainWindow" command="key" arguments="32" />
|
||||
|
||||
</events>
|
||||
|
|
@ -567,9 +567,9 @@ target_link_libraries(
|
|||
cockatrice_target_enable_crash_reporting(cockatrice)
|
||||
|
||||
if(WITH_GUI_TEST)
|
||||
# recording.cpp translates between XML test files and the QtTesting event pipeline;
|
||||
# it needs the QtTesting headers, so it only exists with the harness.
|
||||
target_sources(cockatrice PRIVATE src/interface/recording.cpp)
|
||||
# These two translate between XML test files and the QtTesting event pipeline;
|
||||
# they need the QtTesting headers, so they only exist with the harness.
|
||||
target_sources(cockatrice PRIVATE src/game_graphics/pq_cockatrice_event_player.cpp src/interface/recording.cpp)
|
||||
target_link_libraries(cockatrice PRIVATE QtTesting)
|
||||
target_compile_definitions(cockatrice PRIVATE WITH_GUI_TEST)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ void ToggleButton::setState(bool _state)
|
|||
DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||
: QWidget(nullptr), visualDeckStorageWidget(nullptr), parentGame(parent), playerId(_playerId)
|
||||
{
|
||||
setObjectName("deckViewContainer");
|
||||
|
||||
loadLocalButton = new QPushButton;
|
||||
loadRemoteButton = new QPushButton;
|
||||
loadFromClipboardButton = new QPushButton;
|
||||
|
|
@ -80,6 +82,14 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
|||
forceStartGameButton = new QPushButton;
|
||||
sideboardLockButton = new ToggleButton;
|
||||
|
||||
loadLocalButton->setObjectName("loadLocalButton");
|
||||
loadRemoteButton->setObjectName("loadRemoteButton");
|
||||
loadFromClipboardButton->setObjectName("loadFromClipboardButton");
|
||||
readyStartButton->setObjectName("readyStartButton");
|
||||
forceStartGameButton->setObjectName("forceStartGameButton");
|
||||
unloadDeckButton->setObjectName("unloadDeckButton");
|
||||
sideboardLockButton->setObjectName("sideboardLockButton");
|
||||
|
||||
connect(loadLocalButton, &QPushButton::clicked, this, &DeckViewContainer::loadLocalDeck);
|
||||
connect(loadRemoteButton, &QPushButton::clicked, this, &DeckViewContainer::loadRemoteDeck);
|
||||
connect(loadFromClipboardButton, &QPushButton::clicked, this, &DeckViewContainer::loadFromClipboard);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class TabGame;
|
|||
TabbedDeckViewContainer::TabbedDeckViewContainer(int _playerId, TabGame *parent)
|
||||
: QTabWidget(nullptr), playerId(_playerId), parentGame(parent)
|
||||
{
|
||||
setObjectName(QString("tabbedDeckView_%1").arg(_playerId));
|
||||
setTabsClosable(true);
|
||||
connect(this, &QTabWidget::tabCloseRequested, this, &TabbedDeckViewContainer::closeTab);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ protected:
|
|||
|
||||
GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, parent), rubberBand(0)
|
||||
{
|
||||
setObjectName("gameView");
|
||||
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
||||
setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
|
||||
setViewportUpdateMode(BoundingRectViewportUpdate);
|
||||
|
|
|
|||
628
cockatrice/src/game_graphics/pq_cockatrice_event_player.cpp
Normal file
628
cockatrice/src/game_graphics/pq_cockatrice_event_player.cpp
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
#include "pq_cockatrice_event_player.h"
|
||||
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "board/card_item.h"
|
||||
#include "game_scene.h"
|
||||
#include "game_view.h"
|
||||
#include "zones/card_zone.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QTreeWidget>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/game_state.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(PQ_COCKATRICE_EVENT_PLAYER, "cockatrice.guiTest.eventPlayer")
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Strips Qt's mnemonic markers so a test can name a menu entry by the label the
|
||||
* user sees ("Turn Over" rather than "T&urn Over").
|
||||
*/
|
||||
QString normalizeActionText(const QString &text)
|
||||
{
|
||||
QString normalized = text;
|
||||
normalized.remove('&');
|
||||
return normalized.simplified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a printable character onto the key a US keyboard would report for it, so
|
||||
* typing produces the same QKeyEvents a recording would.
|
||||
*/
|
||||
Qt::Key keyForCharacter(QChar character)
|
||||
{
|
||||
if (character.isLetter()) {
|
||||
return static_cast<Qt::Key>(Qt::Key_A + (character.toUpper().unicode() - 'A'));
|
||||
}
|
||||
if (character.isDigit()) {
|
||||
return static_cast<Qt::Key>(Qt::Key_0 + (character.unicode() - '0'));
|
||||
}
|
||||
switch (character.unicode()) {
|
||||
case ' ':
|
||||
return Qt::Key_Space;
|
||||
case '\n':
|
||||
return Qt::Key_Return;
|
||||
case '\t':
|
||||
return Qt::Key_Tab;
|
||||
case '-':
|
||||
return Qt::Key_Minus;
|
||||
case '_':
|
||||
return Qt::Key_Underscore;
|
||||
case '/':
|
||||
return Qt::Key_Slash;
|
||||
case ',':
|
||||
return Qt::Key_Comma;
|
||||
case '.':
|
||||
return Qt::Key_Period;
|
||||
case '\'':
|
||||
return Qt::Key_Apostrophe;
|
||||
case ';':
|
||||
return Qt::Key_Semicolon;
|
||||
case ':':
|
||||
return Qt::Key_Colon;
|
||||
case '"':
|
||||
return Qt::Key_QuoteDbl;
|
||||
case '&':
|
||||
return Qt::Key_Ampersand;
|
||||
case '(':
|
||||
return Qt::Key_ParenLeft;
|
||||
case ')':
|
||||
return Qt::Key_ParenRight;
|
||||
case '[':
|
||||
return Qt::Key_BracketLeft;
|
||||
case ']':
|
||||
return Qt::Key_BracketRight;
|
||||
default:
|
||||
return Qt::Key_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
/** Depth-first search for the first model index whose label matches @p text. */
|
||||
QModelIndex findModelIndexByText(const QAbstractItemModel *model, const QString &text, const QModelIndex &parent = {})
|
||||
{
|
||||
for (int row = 0; row < model->rowCount(parent); ++row) {
|
||||
const QModelIndex index = model->index(row, 0, parent);
|
||||
if (index.data(Qt::DisplayRole).toString() == text) {
|
||||
return index;
|
||||
}
|
||||
const QModelIndex child = findModelIndexByText(model, text, index);
|
||||
if (child.isValid()) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool needsShift(QChar character)
|
||||
{
|
||||
if (character.isUpper()) {
|
||||
return true;
|
||||
}
|
||||
return QStringLiteral("_:\"&()").contains(character);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
pqCockatriceEventPlayer::pqCockatriceEventPlayer(QObject *parent) : pqWidgetEventPlayer(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playEvent(QObject *object, const QString &command, const QString &arguments, bool &error)
|
||||
{
|
||||
// A known command that fails is a handled-but-failed event: QtTesting logs
|
||||
// "Unhandled event" when playEvent returns false, so report through `error`
|
||||
// (the contract playExpectProperty already follows) and still return true.
|
||||
const auto run = [&error](bool ok) {
|
||||
if (!ok) {
|
||||
error = true;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (command == "clickCard") {
|
||||
return run(playClickCard(object, arguments));
|
||||
} else if (command == "flipCard") {
|
||||
return run(playFlipCard(object, arguments));
|
||||
} else if (command == "cardAction") {
|
||||
return run(playCardAction(object, arguments));
|
||||
} else if (command == "moveCard") {
|
||||
return run(playMoveCard(object, arguments));
|
||||
} else if (command == "drawArrow") {
|
||||
return run(playDrawArrow(object, arguments));
|
||||
} else if (command == "createToken") {
|
||||
return run(playCreateToken(object, arguments));
|
||||
} else if (command == "selectItem") {
|
||||
return run(playSelectItem(object, arguments));
|
||||
} else if (command == "typeText") {
|
||||
return run(playTypeText(object, arguments));
|
||||
} else if (command == "expectProperty") {
|
||||
return playExpectProperty(object, arguments, error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QGraphicsItem *
|
||||
pqCockatriceEventPlayer::findCardInScene(QGraphicsScene *scene, const QString &cardName, const QString &zoneName)
|
||||
{
|
||||
for (QGraphicsItem *gi : scene->items()) {
|
||||
if (gi->type() != typeCard) {
|
||||
continue;
|
||||
}
|
||||
auto *card = static_cast<CardItem *>(gi);
|
||||
if (!card->getZone() || card->getZone()->getName() != zoneName) {
|
||||
continue;
|
||||
}
|
||||
QString actualName = card->getName();
|
||||
if (actualName == cardName || actualName.endsWith(" " + cardName)) {
|
||||
return card;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QGraphicsItem *pqCockatriceEventPlayer::findZoneInScene(QGraphicsScene *scene, const QString &zoneName)
|
||||
{
|
||||
for (QGraphicsItem *gi : scene->items()) {
|
||||
if (gi->type() != typeZone) {
|
||||
continue;
|
||||
}
|
||||
auto *zone = static_cast<CardZone *>(gi);
|
||||
if (zone->getLogic() && zone->getLogic()->getName() == zoneName) {
|
||||
return zone;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QAction *pqCockatriceEventPlayer::findActionInMenu(QMenu *menu, const QString &actionText)
|
||||
{
|
||||
if (!menu || actionText.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (QAction *action : menu->actions()) {
|
||||
if (action->isSeparator()) {
|
||||
continue;
|
||||
}
|
||||
if (normalizeActionText(action->text()).contains(actionText, Qt::CaseInsensitive)) {
|
||||
return action;
|
||||
}
|
||||
if (QMenu *subMenu = action->menu()) {
|
||||
if (QAction *found = findActionInMenu(subMenu, actionText)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMenu *pqCockatriceEventPlayer::visiblePopupMenu()
|
||||
{
|
||||
for (QWidget *w : QApplication::topLevelWidgets()) {
|
||||
auto *menu = qobject_cast<QMenu *>(w);
|
||||
if (menu && menu->isVisible()) {
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QPoint pqCockatriceEventPlayer::viewportPoint(QGraphicsView *view, const QGraphicsItem *item)
|
||||
{
|
||||
return view->mapFromScene(item->sceneBoundingRect().center());
|
||||
}
|
||||
void pqCockatriceEventPlayer::sendMouseEvent(QGraphicsView *view,
|
||||
QEvent::Type type,
|
||||
const QPoint &pos,
|
||||
Qt::MouseButton button,
|
||||
Qt::MouseButtons buttons)
|
||||
{
|
||||
QMouseEvent event(type, pos, view->viewport()->mapToGlobal(pos), button, buttons, Qt::NoModifier);
|
||||
qApp->notify(view->viewport(), &event);
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playClickCard(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *gv = qobject_cast<QGraphicsView *>(object);
|
||||
if (!gv) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "clickCard: target widget is not a QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 2) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "clickCard: arguments must be 'cardName,zoneName', got:" << arguments;
|
||||
return false;
|
||||
}
|
||||
|
||||
QGraphicsScene *scene = gv->scene();
|
||||
if (!scene) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "clickCard: no scene on the QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *target = findCardInScene(scene, parts[0].trimmed(), parts[1].trimmed());
|
||||
if (!target) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "clickCard: card" << parts[0].trimmed() << "not found in zone" << parts[1].trimmed();
|
||||
return false;
|
||||
}
|
||||
|
||||
const QPoint pos = viewportPoint(gv, target);
|
||||
// A double click is the play gesture from hand: press/release, then the
|
||||
// double-click event and its release, exactly as a recording produces it.
|
||||
sendMouseEvent(gv, QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton);
|
||||
sendMouseEvent(gv, QEvent::MouseButtonRelease, pos, Qt::LeftButton, Qt::LeftButton);
|
||||
sendMouseEvent(gv, QEvent::MouseButtonDblClick, pos, Qt::LeftButton, Qt::LeftButton);
|
||||
sendMouseEvent(gv, QEvent::MouseButtonRelease, pos, Qt::LeftButton, Qt::LeftButton);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playFlipCard(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *gv = qobject_cast<QGraphicsView *>(object);
|
||||
if (!gv) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "flipCard: target widget is not a QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 2) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "flipCard: arguments must be 'cardName,zoneName', got:" << arguments;
|
||||
return false;
|
||||
}
|
||||
|
||||
QGraphicsScene *scene = gv->scene();
|
||||
if (!scene) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "flipCard: no scene";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *card = qgraphicsitem_cast<CardItem *>(findCardInScene(scene, parts[0].trimmed(), parts[1].trimmed()));
|
||||
if (!card) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "flipCard: card" << parts[0].trimmed() << "not found in zone" << parts[1].trimmed();
|
||||
return false;
|
||||
}
|
||||
|
||||
return invokeCardMenuAction("flipCard", gv, card, QStringLiteral("Turn Over"));
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playCardAction(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *gv = qobject_cast<QGraphicsView *>(object);
|
||||
if (!gv) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "cardAction: target widget is not a QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 3) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "cardAction: arguments must be 'cardName,zoneName,actionText', got:" << arguments;
|
||||
return false;
|
||||
}
|
||||
|
||||
QGraphicsScene *scene = gv->scene();
|
||||
if (!scene) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "cardAction: no scene";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *card = qgraphicsitem_cast<CardItem *>(findCardInScene(scene, parts[0].trimmed(), parts[1].trimmed()));
|
||||
if (!card) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "cardAction: card" << parts[0].trimmed() << "not found in zone" << parts[1].trimmed();
|
||||
return false;
|
||||
}
|
||||
|
||||
return invokeCardMenuAction("cardAction", gv, card, parts.mid(2).join(',').trimmed());
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::invokeCardMenuAction(const char *command,
|
||||
QGraphicsView *view,
|
||||
CardItem *card,
|
||||
const QString &actionText)
|
||||
{
|
||||
const QPoint pos = viewportPoint(view, card);
|
||||
sendMouseEvent(view, QEvent::MouseButtonPress, pos, Qt::RightButton, Qt::RightButton);
|
||||
sendMouseEvent(view, QEvent::MouseButtonRelease, pos, Qt::RightButton, Qt::NoButton);
|
||||
qApp->processEvents();
|
||||
|
||||
QMenu *menu = visiblePopupMenu();
|
||||
if (!menu) {
|
||||
qCWarning(PQ_COCKATRICE_EVENT_PLAYER) << command << ": no popup menu appeared after right-click";
|
||||
return false;
|
||||
}
|
||||
|
||||
QAction *action = findActionInMenu(menu, actionText);
|
||||
if (!action) {
|
||||
qCWarning(PQ_COCKATRICE_EVENT_PLAYER) << command << ": no context menu action matching" << actionText;
|
||||
menu->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
action->trigger();
|
||||
menu->close();
|
||||
qApp->processEvents();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playMoveCard(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *gv = qobject_cast<QGraphicsView *>(object);
|
||||
if (!gv) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "moveCard: target widget is not a QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 3) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "moveCard: arguments must be 'cardName,srcZoneName,dstZoneName', got:" << arguments;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString cardName = parts[0].trimmed();
|
||||
const QString srcZoneName = parts[1].trimmed();
|
||||
const QString dstZoneName = parts[2].trimmed();
|
||||
|
||||
QGraphicsScene *scene = gv->scene();
|
||||
if (!scene) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "moveCard: no scene";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *card = findCardInScene(scene, cardName, srcZoneName);
|
||||
if (!card) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "moveCard: card" << cardName << "not found in zone" << srcZoneName;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *dstZone = findZoneInScene(scene, dstZoneName);
|
||||
if (!dstZone) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "moveCard: destination zone" << dstZoneName << "not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QPoint srcPos = viewportPoint(gv, card);
|
||||
const QPoint dstPos = viewportPoint(gv, dstZone);
|
||||
|
||||
// A drag has to travel past Qt's start distance before the scene turns it
|
||||
// into a card drag item, otherwise the move is interpreted as a click.
|
||||
const int dragDistance = 2 * QApplication::startDragDistance() + 10;
|
||||
const QPoint pastDragStart = srcPos + QPoint(dragDistance, 0);
|
||||
|
||||
sendMouseEvent(gv, QEvent::MouseButtonPress, srcPos, Qt::LeftButton, Qt::LeftButton);
|
||||
sendMouseEvent(gv, QEvent::MouseMove, pastDragStart, Qt::LeftButton, Qt::LeftButton);
|
||||
qApp->processEvents();
|
||||
sendMouseEvent(gv, QEvent::MouseMove, dstPos, Qt::LeftButton, Qt::LeftButton);
|
||||
qApp->processEvents();
|
||||
sendMouseEvent(gv, QEvent::MouseButtonRelease, dstPos, Qt::LeftButton, Qt::NoButton);
|
||||
qApp->processEvents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playDrawArrow(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *gv = qobject_cast<QGraphicsView *>(object);
|
||||
if (!gv) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "drawArrow: target widget is not a QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 4) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "drawArrow: arguments must be 'srcCard,srcZone,dstCard,dstZone', got:" << arguments;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString srcCardName = parts[0].trimmed();
|
||||
const QString srcZoneName = parts[1].trimmed();
|
||||
const QString dstCardName = parts[2].trimmed();
|
||||
const QString dstZoneName = parts[3].trimmed();
|
||||
|
||||
QGraphicsScene *scene = gv->scene();
|
||||
if (!scene) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "drawArrow: no scene";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *srcCard = findCardInScene(scene, srcCardName, srcZoneName);
|
||||
if (!srcCard) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "drawArrow: source card" << srcCardName << "not found in zone" << srcZoneName;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *dstCard = findCardInScene(scene, dstCardName, dstZoneName);
|
||||
if (!dstCard) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "drawArrow: dest card" << dstCardName << "not found in zone" << dstZoneName;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QPoint srcPos = viewportPoint(gv, srcCard);
|
||||
const QPoint dstPos = viewportPoint(gv, dstCard);
|
||||
|
||||
const int dragDistance = 2 * QApplication::startDragDistance() + 10;
|
||||
const QPoint pastDragStart = srcPos + QPoint(dragDistance, 0);
|
||||
|
||||
sendMouseEvent(gv, QEvent::MouseButtonPress, srcPos, Qt::RightButton, Qt::RightButton);
|
||||
sendMouseEvent(gv, QEvent::MouseMove, pastDragStart, Qt::RightButton, Qt::RightButton);
|
||||
qApp->processEvents();
|
||||
sendMouseEvent(gv, QEvent::MouseMove, dstPos, Qt::RightButton, Qt::RightButton);
|
||||
sendMouseEvent(gv, QEvent::MouseButtonRelease, dstPos, Qt::RightButton, Qt::NoButton);
|
||||
qApp->processEvents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playCreateToken(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *gv = qobject_cast<QGraphicsView *>(object);
|
||||
if (!gv) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "createToken: target widget is not a QGraphicsView";
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 3) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "createToken: arguments must be 'name,color,pt', got:" << arguments;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString tokenName = parts[0].trimmed();
|
||||
QString tokenColor = parts[1].trimmed();
|
||||
QString tokenPt = parts[2].trimmed();
|
||||
|
||||
TabGame *tabGame = nullptr;
|
||||
QWidget *w = gv;
|
||||
while (w) {
|
||||
tabGame = qobject_cast<TabGame *>(w);
|
||||
if (tabGame) {
|
||||
break;
|
||||
}
|
||||
w = w->parentWidget();
|
||||
}
|
||||
if (!tabGame) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "createToken: TabGame not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractGame *game = tabGame->getGame();
|
||||
if (!game) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "createToken: no game";
|
||||
return false;
|
||||
}
|
||||
|
||||
int activePlayerId = game->getGameState()->getActivePlayer();
|
||||
PlayerLogic *player = game->getPlayerManager()->getActiveLocalPlayer(activePlayerId);
|
||||
if (!player) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "createToken: no active local player";
|
||||
return false;
|
||||
}
|
||||
|
||||
TokenInfo info;
|
||||
info.name = tokenName;
|
||||
info.color = tokenColor;
|
||||
info.pt = tokenPt;
|
||||
info.destroy = true;
|
||||
info.faceDown = false;
|
||||
|
||||
player->getPlayerActions()->actCreateToken(info);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playSelectItem(QObject *object, const QString &arguments)
|
||||
{
|
||||
const QString text = arguments.trimmed();
|
||||
if (text.isEmpty()) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "selectItem: needs the label of the item to select";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto *tree = qobject_cast<QTreeWidget *>(object)) {
|
||||
QTreeWidgetItemIterator item(tree);
|
||||
while (*item) {
|
||||
if ((*item)->text(0) == text) {
|
||||
tree->setCurrentItem(*item);
|
||||
qApp->processEvents();
|
||||
return true;
|
||||
}
|
||||
++item;
|
||||
}
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "selectItem: no tree item labelled" << text;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto *view = qobject_cast<QAbstractItemView *>(object)) {
|
||||
const QModelIndex index = findModelIndexByText(view->model(), text);
|
||||
if (!index.isValid()) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "selectItem: no item labelled" << text;
|
||||
return false;
|
||||
}
|
||||
view->setCurrentIndex(index);
|
||||
qApp->processEvents();
|
||||
return true;
|
||||
}
|
||||
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "selectItem: target is neither a tree widget nor an item view";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playTypeText(QObject *object, const QString &arguments)
|
||||
{
|
||||
auto *widget = qobject_cast<QWidget *>(object);
|
||||
if (!widget) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "typeText: target is not a QWidget";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const QChar character : arguments) {
|
||||
const Qt::Key key = keyForCharacter(character);
|
||||
const Qt::KeyboardModifiers modifiers = needsShift(character) ? Qt::ShiftModifier : Qt::NoModifier;
|
||||
QKeyEvent press(QEvent::KeyPress, key, modifiers, QString(character));
|
||||
QKeyEvent release(QEvent::KeyRelease, key, modifiers, QString(character));
|
||||
qApp->notify(widget, &press);
|
||||
qApp->notify(widget, &release);
|
||||
}
|
||||
qApp->processEvents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pqCockatriceEventPlayer::playExpectProperty(QObject *object, const QString &arguments, bool &error)
|
||||
{
|
||||
if (!object) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "expectProperty: no target object";
|
||||
error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList parts = arguments.split(',');
|
||||
if (parts.size() < 2) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "expectProperty: arguments must be 'propertyName,expectedValue', got:" << arguments;
|
||||
error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString propertyName = parts[0].trimmed();
|
||||
const QString expected = parts.mid(1).join(',');
|
||||
|
||||
const QVariant actual = object->property(propertyName.toUtf8().constData());
|
||||
if (!actual.isValid()) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER)
|
||||
<< "expectProperty:" << object->objectName() << "has no property" << propertyName;
|
||||
error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actual.toString() != expected) {
|
||||
qCCritical(PQ_COCKATRICE_EVENT_PLAYER) << "expectProperty:" << object->objectName() << propertyName << "is"
|
||||
<< actual.toString() << "but the test expected" << expected;
|
||||
error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
91
cockatrice/src/game_graphics/pq_cockatrice_event_player.h
Normal file
91
cockatrice/src/game_graphics/pq_cockatrice_event_player.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef PQ_COCKATRICE_EVENT_PLAYER_H
|
||||
#define PQ_COCKATRICE_EVENT_PLAYER_H
|
||||
|
||||
#include "pqWidgetEventPlayer.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
|
||||
class CardItem;
|
||||
class QAction;
|
||||
class QGraphicsItem;
|
||||
class QGraphicsScene;
|
||||
class QGraphicsView;
|
||||
class QMenu;
|
||||
|
||||
/**
|
||||
* Custom event player for Cockatrice game interactions.
|
||||
*
|
||||
* Card commands are resolution independent: the card is looked up in the
|
||||
* QGraphicsScene by name and zone, then mouse events are sent at the card's
|
||||
* current viewport position. That keeps recordings usable across screen sizes
|
||||
* and window geometries.
|
||||
*
|
||||
* Commands:
|
||||
* clickCard "cardName,zoneName"
|
||||
* left press/release + double click — plays a card from hand, taps a
|
||||
* permanent, opens the deck view entry, depending on the zone
|
||||
* flipCard "cardName,zoneName"
|
||||
* right-click → "Turn Over" (shorthand for cardAction)
|
||||
* cardAction "cardName,zoneName,actionText"
|
||||
* right-click the card and trigger the first context menu action whose
|
||||
* label contains actionText; submenus are searched as well, so
|
||||
* "Add counter (A)" works
|
||||
* moveCard "cardName,srcZoneName,dstZoneName"
|
||||
* left-drag the card onto the destination zone — plays a card, moves it
|
||||
* to the graveyard/exile, puts it back into hand, ...
|
||||
* drawArrow "srcCard,srcZone,dstCard,dstZone"
|
||||
* right-drag an arrow from one card to another
|
||||
* createToken "name,color,pt"
|
||||
* create a token through the active local player, as the table context
|
||||
* menu's "Create token" dialog would
|
||||
* selectItem "item text"
|
||||
* selects the first item of a tree/list widget whose label matches, for
|
||||
* navigating the settings navigation tree or similar label-driven views
|
||||
* typeText "some text"
|
||||
* types the text into the widget one key event at a time — use it for
|
||||
* deck lists and search boxes instead of one event per character
|
||||
* expectProperty "propertyName,expectedValue"
|
||||
* assertion: playback fails unless object->property(propertyName)
|
||||
* equals expectedValue — for example "count,2" on the tab widget
|
||||
*/
|
||||
class pqCockatriceEventPlayer : public pqWidgetEventPlayer
|
||||
{
|
||||
Q_OBJECT
|
||||
typedef pqWidgetEventPlayer Superclass;
|
||||
|
||||
public:
|
||||
explicit pqCockatriceEventPlayer(QObject *parent = nullptr);
|
||||
|
||||
using Superclass::playEvent;
|
||||
|
||||
bool playEvent(QObject *object, const QString &command, const QString &arguments, bool &error) override;
|
||||
|
||||
private:
|
||||
bool playClickCard(QObject *object, const QString &arguments);
|
||||
bool playFlipCard(QObject *object, const QString &arguments);
|
||||
bool playCardAction(QObject *object, const QString &arguments);
|
||||
bool playMoveCard(QObject *object, const QString &arguments);
|
||||
bool playDrawArrow(QObject *object, const QString &arguments);
|
||||
bool playCreateToken(QObject *object, const QString &arguments);
|
||||
bool playSelectItem(QObject *object, const QString &arguments);
|
||||
bool playTypeText(QObject *object, const QString &arguments);
|
||||
bool playExpectProperty(QObject *object, const QString &arguments, bool &error);
|
||||
|
||||
/** @brief Triggers the context menu entry @p actionText after right-clicking @p card. */
|
||||
bool invokeCardMenuAction(const char *command, QGraphicsView *view, CardItem *card, const QString &actionText);
|
||||
|
||||
static QGraphicsItem *findCardInScene(QGraphicsScene *scene, const QString &cardName, const QString &zoneName);
|
||||
static QGraphicsItem *findZoneInScene(QGraphicsScene *scene, const QString &zoneName);
|
||||
static QAction *findActionInMenu(QMenu *menu, const QString &actionText);
|
||||
static QMenu *visiblePopupMenu();
|
||||
|
||||
/** @brief Viewport position of the item's centre, as the mouse events have to be sent. */
|
||||
static QPoint viewportPoint(QGraphicsView *view, const QGraphicsItem *item);
|
||||
static void sendMouseEvent(QGraphicsView *view,
|
||||
QEvent::Type type,
|
||||
const QPoint &pos,
|
||||
Qt::MouseButton button,
|
||||
Qt::MouseButtons buttons);
|
||||
};
|
||||
|
||||
#endif // PQ_COCKATRICE_EVENT_PLAYER_H
|
||||
|
|
@ -28,12 +28,16 @@ class QWidget;
|
|||
*/
|
||||
AbstractDlgDeckTextEdit::AbstractDlgDeckTextEdit(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
setObjectName("dlgDeckTextEdit");
|
||||
|
||||
contentsEdit = new QPlainTextEdit;
|
||||
contentsEdit->setObjectName("contentsEdit");
|
||||
|
||||
refreshButton = new QPushButton(tr("&Refresh"));
|
||||
connect(refreshButton, &QPushButton::clicked, this, &AbstractDlgDeckTextEdit::actRefresh);
|
||||
|
||||
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
buttonBox->setObjectName("buttonBox");
|
||||
buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &AbstractDlgDeckTextEdit::actOK);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &AbstractDlgDeckTextEdit::reject);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,11 @@ class QWidget;
|
|||
|
||||
DlgLocalGameOptions::DlgLocalGameOptions(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
setObjectName("localGameDialog");
|
||||
|
||||
numberPlayersLabel = new QLabel(tr("Players:"), this);
|
||||
numberPlayersEdit = new QSpinBox(this);
|
||||
numberPlayersEdit->setObjectName("numberPlayersEdit");
|
||||
numberPlayersEdit->setMinimum(1);
|
||||
numberPlayersEdit->setMaximum(8);
|
||||
numberPlayersEdit->setValue(1);
|
||||
|
|
@ -28,10 +31,12 @@ DlgLocalGameOptions::DlgLocalGameOptions(QWidget *parent) : QDialog(parent)
|
|||
generalGrid->addWidget(numberPlayersLabel, 0, 0);
|
||||
generalGrid->addWidget(numberPlayersEdit, 0, 1);
|
||||
generalGroupBox = new QGroupBox(tr("General"), this);
|
||||
generalGroupBox->setObjectName("generalGroupBox");
|
||||
generalGroupBox->setLayout(generalGrid);
|
||||
|
||||
startingLifeTotalLabel = new QLabel(tr("Starting life total:"), this);
|
||||
startingLifeTotalEdit = new QSpinBox(this);
|
||||
startingLifeTotalEdit->setObjectName("startingLifeTotalEdit");
|
||||
startingLifeTotalEdit->setMinimum(-999999999);
|
||||
startingLifeTotalEdit->setMaximum(999999999);
|
||||
startingLifeTotalEdit->setValue(20);
|
||||
|
|
@ -42,11 +47,14 @@ DlgLocalGameOptions::DlgLocalGameOptions(QWidget *parent) : QDialog(parent)
|
|||
gameSetupGrid->addWidget(startingLifeTotalLabel, 0, 0);
|
||||
gameSetupGrid->addWidget(startingLifeTotalEdit, 0, 1);
|
||||
gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options"), this);
|
||||
gameSetupOptionsGroupBox->setObjectName("gameSetupOptionsGroupBox");
|
||||
gameSetupOptionsGroupBox->setLayout(gameSetupGrid);
|
||||
|
||||
rememberSettingsCheckBox = new QCheckBox(tr("Remember settings"), this);
|
||||
rememberSettingsCheckBox->setObjectName("rememberSettingsCheckBox");
|
||||
|
||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
buttonBox->setObjectName("buttonBox");
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLocalGameOptions::actOK);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLocalGameOptions::reject);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ class Message;
|
|||
TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
||||
: Tab(_tabSupervisor), sayLabel(nullptr), sayEdit(nullptr)
|
||||
{
|
||||
setObjectName("TabGame");
|
||||
// THIS CTOR IS USED ON REPLAY
|
||||
game = new Replay(this, _replay, tabSupervisor->getIsLocalGame(), &SettingsCache::instance().userInterface(),
|
||||
new SettingsCardPreferenceProvider(this));
|
||||
|
|
@ -116,6 +117,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
|||
addDockWidget(Qt::BottomDockWidgetArea, replayDock);
|
||||
|
||||
mainWidget = new QStackedWidget(this);
|
||||
mainWidget->setObjectName("mainWidget");
|
||||
mainWidget->addWidget(deckViewContainerWidget);
|
||||
mainWidget->addWidget(gamePlayAreaWidget);
|
||||
setCentralWidget(mainWidget);
|
||||
|
|
@ -144,6 +146,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
|||
const QMap<int, QString> &_roomGameTypes)
|
||||
: Tab(_tabSupervisor), userListProxy(_tabSupervisor->getUserListManager())
|
||||
{
|
||||
setObjectName("TabGame");
|
||||
// THIS CTOR IS USED ON GAMES
|
||||
game = new Game(this, tabSupervisor->getIsLocalGame(), _clients, event, _roomGameTypes,
|
||||
&SettingsCache::instance().userInterface(), new SettingsCardPreferenceProvider(this));
|
||||
|
|
@ -160,6 +163,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
|||
addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock);
|
||||
|
||||
mainWidget = new QStackedWidget(this);
|
||||
mainWidget->setObjectName("mainWidget");
|
||||
mainWidget->addWidget(deckViewContainerWidget);
|
||||
mainWidget->addWidget(gamePlayAreaWidget);
|
||||
mainWidget->setContentsMargins(0, 0, 0, 0);
|
||||
|
|
@ -1118,6 +1122,7 @@ void TabGame::createMenuItems()
|
|||
connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus));
|
||||
|
||||
phasesMenu = new TearOffMenu(this);
|
||||
phasesMenu->setObjectName("phasesMenu");
|
||||
|
||||
for (int i = 0; i < phasesToolbar->phaseCount(); ++i) {
|
||||
auto *temp = new QAction(QString(), this);
|
||||
|
|
@ -1128,12 +1133,16 @@ void TabGame::createMenuItems()
|
|||
|
||||
phasesMenu->addSeparator();
|
||||
phasesMenu->addAction(aNextPhase);
|
||||
aNextPhase->setObjectName("aNextPhase");
|
||||
phasesMenu->addAction(aNextPhaseAction);
|
||||
aNextPhaseAction->setObjectName("aNextPhaseAction");
|
||||
|
||||
gameMenu = new QMenu(this);
|
||||
gameMenu->setObjectName("gameMenu");
|
||||
playersSeparator = gameMenu->addSeparator();
|
||||
gameMenu->addMenu(phasesMenu);
|
||||
gameMenu->addAction(aNextTurn);
|
||||
aNextTurn->setObjectName("aNextTurn");
|
||||
gameMenu->addAction(aReverseTurn);
|
||||
gameMenu->addSeparator();
|
||||
gameMenu->addAction(aRemoveLocalArrows);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
#include "widgets/settings_page/abstract_settings_page.h"
|
||||
#include "widgets/tabs/api/commander_spellbook/handle_commander_brackets.h"
|
||||
#ifdef WITH_GUI_TEST
|
||||
#include "../game_graphics/pq_cockatrice_event_player.h"
|
||||
#include "pqEventObserver.h"
|
||||
#include "pqEventSource.h"
|
||||
#include "pqEventTypes.h"
|
||||
|
|
@ -689,6 +690,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
testUtility->setRecordWithDialog(true);
|
||||
testUtility->addEventObserver("xml", new XMLEventObserver(this));
|
||||
testUtility->addEventSource("xml", new XMLEventSource(this));
|
||||
testUtility->eventPlayer()->addWidgetEventPlayer(new pqCockatriceEventPlayer(this));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue