diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp index b6908ce94..68de8bdac 100644 --- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp +++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp @@ -549,6 +549,12 @@ void AbstractTabDeckEditor::filterTreeChanged(FilterTree *filterTree) databaseDisplayDockWidget->setFilterTree(filterTree); } +void AbstractTabDeckEditor::closeEvent(QCloseEvent *event) +{ + emit deckEditorClosing(this); + event->accept(); +} + // Method uses to sync docks state with menu items state bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e) { @@ -592,12 +598,11 @@ bool AbstractTabDeckEditor::confirmClose() return true; } -void AbstractTabDeckEditor::closeRequest(bool forced) +bool AbstractTabDeckEditor::closeRequest() { - if (!forced && !confirmClose()) { - return; + if (!confirmClose()) { + return false; } - emit deckEditorClosing(this); - close(); + return close(); } \ No newline at end of file diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h index 7b52ff3b6..dd85028dc 100644 --- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h +++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h @@ -78,7 +78,7 @@ public slots: void actDecrementCardFromSideboard(const ExactCard &card); void actOpenRecent(const QString &fileName); void filterTreeChanged(FilterTree *filterTree); - void closeRequest(bool forced = false) override; + bool closeRequest() override; virtual void showPrintingSelector() = 0; virtual void dockTopLevelChanged(bool topLevel) = 0; @@ -117,6 +117,7 @@ protected slots: virtual void freeDocksSize() = 0; virtual void refreshShortcuts() = 0; + void closeEvent(QCloseEvent *event) override; bool eventFilter(QObject *o, QEvent *e) override; virtual void dockVisibleTriggered() = 0; virtual void dockFloatingTriggered() = 0; diff --git a/cockatrice/src/client/tabs/tab.cpp b/cockatrice/src/client/tabs/tab.cpp index dcc1ae0c2..8b098c280 100644 --- a/cockatrice/src/client/tabs/tab.cpp +++ b/cockatrice/src/client/tabs/tab.cpp @@ -43,16 +43,7 @@ void Tab::deleteCardInfoPopup(const QString &cardName) } } -/** - * Overrides the closeEvent in order to emit a close signal - */ -void Tab::closeEvent(QCloseEvent *event) +bool Tab::closeRequest() { - emit closed(); - event->accept(); -} - -void Tab::closeRequest(bool /*forced*/) -{ - close(); + return close(); } \ No newline at end of file diff --git a/cockatrice/src/client/tabs/tab.h b/cockatrice/src/client/tabs/tab.h index 68a1882a7..fc97585c3 100644 --- a/cockatrice/src/client/tabs/tab.h +++ b/cockatrice/src/client/tabs/tab.h @@ -15,12 +15,6 @@ class Tab : public QMainWindow signals: void userEvent(bool globalEvent = true); void tabTextChanged(Tab *tab, const QString &newTabText); - /** - * Emitted when the tab is closed (because Qt doesn't provide a built-in close signal) - * This signal is emitted from this class's overridden Tab::closeEvent method. - * Make sure any subclasses that override closeEvent still emit this signal from there. - */ - void closed(); protected: TabSupervisor *tabSupervisor; @@ -31,7 +25,6 @@ protected: protected slots: void showCardInfoPopup(const QPoint &pos, const CardRef &cardRef); void deleteCardInfoPopup(const QString &cardName); - void closeEvent(QCloseEvent *event) override; private: CardRef currentCard; @@ -59,13 +52,16 @@ public: } virtual QString getTabText() const = 0; virtual void retranslateUi() = 0; + /** - * Sends a request to close the tab. - * Signals for cleanup should be emitted from this method instead of the destructor. + * Nicely asks to close the tab. + * Override this method to do checks or ask for confirmation before closing the tab. + * If you need to force close the tab, just call close() instead. * - * @param forced whether this close request was initiated by the user or forced by the server. + * @return True if the tab is successfully closed. */ - virtual void closeRequest(bool forced = false); + virtual bool closeRequest(); + virtual void tabActivated() { } diff --git a/cockatrice/src/client/tabs/tab_game.cpp b/cockatrice/src/client/tabs/tab_game.cpp index c4a119961..f96949074 100644 --- a/cockatrice/src/client/tabs/tab_game.cpp +++ b/cockatrice/src/client/tabs/tab_game.cpp @@ -376,15 +376,19 @@ void TabGame::refreshShortcuts() } } -void TabGame::closeRequest(bool forced) +bool TabGame::closeRequest() { - if (!forced && !leaveGame()) { - return; + if (!leaveGame()) { + return false; } - emit gameClosing(this); + return close(); +} - close(); +void TabGame::closeEvent(QCloseEvent *event) +{ + emit gameClosing(this); + event->accept(); } void TabGame::incrementGameTime() @@ -1249,7 +1253,7 @@ void TabGame::createMenuItems() aConcede = new QAction(this); connect(aConcede, &QAction::triggered, this, &TabGame::actConcede); aLeaveGame = new QAction(this); - connect(aLeaveGame, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aLeaveGame, &QAction::triggered, this, &TabGame::closeRequest); aFocusChat = new QAction(this); connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus)); aCloseReplay = nullptr; @@ -1299,7 +1303,7 @@ void TabGame::createReplayMenuItems() aFocusChat = nullptr; aLeaveGame = nullptr; aCloseReplay = new QAction(this); - connect(aCloseReplay, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aCloseReplay, &QAction::triggered, this, &TabGame::closeRequest); phasesMenu = nullptr; gameMenu = new QMenu(this); diff --git a/cockatrice/src/client/tabs/tab_game.h b/cockatrice/src/client/tabs/tab_game.h index e00a76dc8..7927d44a6 100644 --- a/cockatrice/src/client/tabs/tab_game.h +++ b/cockatrice/src/client/tabs/tab_game.h @@ -202,6 +202,9 @@ private slots: void dockFloatingTriggered(); void dockTopLevelChanged(bool topLevel); +protected slots: + void closeEvent(QCloseEvent *event) override; + public: TabGame(TabSupervisor *_tabSupervisor, QList &_clients, @@ -212,7 +215,7 @@ public: ~TabGame() override; void retranslateUi() override; void updatePlayerListDockTitle(); - void closeRequest(bool forced = false) override; + bool closeRequest() override; const QMap &getPlayers() const { return players; diff --git a/cockatrice/src/client/tabs/tab_message.cpp b/cockatrice/src/client/tabs/tab_message.cpp index 9dc53156d..06700d4e3 100644 --- a/cockatrice/src/client/tabs/tab_message.cpp +++ b/cockatrice/src/client/tabs/tab_message.cpp @@ -39,7 +39,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, vbox->addWidget(sayEdit); aLeave = new QAction(this); - connect(aLeave, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aLeave, &QAction::triggered, this, &TabMessage::closeRequest); messageMenu = new QMenu(this); messageMenu->addAction(aLeave); @@ -86,10 +86,10 @@ QString TabMessage::getTabText() const return tr("%1 - Private chat").arg(QString::fromStdString(otherUserInfo->name())); } -void TabMessage::closeRequest(bool /*forced*/) +void TabMessage::closeEvent(QCloseEvent *event) { emit talkClosing(this); - close(); + event->accept(); } void TabMessage::sendMessage() diff --git a/cockatrice/src/client/tabs/tab_message.h b/cockatrice/src/client/tabs/tab_message.h index dd7424e5d..659d0b804 100644 --- a/cockatrice/src/client/tabs/tab_message.h +++ b/cockatrice/src/client/tabs/tab_message.h @@ -37,6 +37,9 @@ private slots: void addMentionTag(QString mentionTag); void messageClicked(); +protected slots: + void closeEvent(QCloseEvent *event) override; + public: TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, @@ -44,7 +47,6 @@ public: const ServerInfo_User &_otherUserInfo); ~TabMessage() override; void retranslateUi() override; - void closeRequest(bool forced = false) override; void tabActivated() override; QString getUserName() const; QString getTabText() const override; diff --git a/cockatrice/src/client/tabs/tab_room.cpp b/cockatrice/src/client/tabs/tab_room.cpp index 1eb648f48..569a88094 100644 --- a/cockatrice/src/client/tabs/tab_room.cpp +++ b/cockatrice/src/client/tabs/tab_room.cpp @@ -103,7 +103,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, hbox->addWidget(userList, 1); aLeaveRoom = new QAction(this); - connect(aLeaveRoom, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aLeaveRoom, &QAction::triggered, this, &TabRoom::closeRequest); roomMenu = new QMenu(this); roomMenu->addAction(aLeaveRoom); @@ -173,11 +173,11 @@ void TabRoom::actShowPopup(const QString &message) } } -void TabRoom::closeRequest(bool /*forced*/) +void TabRoom::closeEvent(QCloseEvent *event) { sendRoomCommand(prepareRoomCommand(Command_LeaveRoom())); emit roomClosing(this); - close(); + event->accept(); } void TabRoom::tabActivated() diff --git a/cockatrice/src/client/tabs/tab_room.h b/cockatrice/src/client/tabs/tab_room.h index ca88a256f..4c0c6c18f 100644 --- a/cockatrice/src/client/tabs/tab_room.h +++ b/cockatrice/src/client/tabs/tab_room.h @@ -88,13 +88,15 @@ private slots: void processRemoveMessagesEvent(const Event_RemoveMessages &event); void refreshShortcuts(); +protected slots: + void closeEvent(QCloseEvent *event) override; + public: TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, ServerInfo_User *_ownUser, const ServerInfo_Room &info); void retranslateUi() override; - void closeRequest(bool forced = false) override; void tabActivated() override; void processRoomEvent(const RoomEvent &event); int getRoomId() const diff --git a/cockatrice/src/client/tabs/tab_supervisor.cpp b/cockatrice/src/client/tabs/tab_supervisor.cpp index 4ed0e5a6b..d87cb4744 100644 --- a/cockatrice/src/client/tabs/tab_supervisor.cpp +++ b/cockatrice/src/client/tabs/tab_supervisor.cpp @@ -182,7 +182,16 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget * TabSupervisor::~TabSupervisor() { - stop(); + // Note: this used to call stop(), but stop() is doing a bunch of stuff including emitting some signals, + // and we don't want to do that in a destructor. + + for (auto &localClient : localClients) { + localClient->deleteLater(); + } + localClients.clear(); + + delete userInfo; + userInfo = nullptr; } void TabSupervisor::retranslateUi() @@ -268,26 +277,6 @@ void TabSupervisor::closeEvent(QCloseEvent *event) event->ignore(); } } - - // Close the game tabs in order to make sure they store their layout. - QSet gameTabsToRemove; - for (auto it = gameTabs.begin(), end = gameTabs.end(); it != end; ++it) { - if (it.value()->close()) { - // Hotfix: the tab owns the `QMenu`s so they need to be cleared, - // otherwise we end up with use-after-free bugs. - if (it.value() == currentWidget()) { - emit setMenu(); - } - - gameTabsToRemove.insert(it.key()); - } else { - event->ignore(); - } - } - - for (auto tabId : gameTabsToRemove) { - gameTabs.remove(tabId); - } } AbstractClient *TabSupervisor::getClient() const @@ -375,7 +364,7 @@ void TabSupervisor::addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager // If managed, all close requests should go through the menu action connect(closeButton, &CloseButton::clicked, this, [manager] { checkAndTrigger(manager, false); }); } else { - connect(closeButton, &CloseButton::clicked, tab, [tab] { tab->closeRequest(); }); + connect(closeButton, &CloseButton::clicked, tab, &Tab::closeRequest); } tabBar()->setTabButton(tabIndex, closeSide, closeButton); } @@ -469,16 +458,16 @@ void TabSupervisor::stop() emit localGameEnded(); } else { if (tabAccount) { - tabAccount->closeRequest(true); + tabAccount->close(); } if (tabServer) { - tabServer->closeRequest(true); + tabServer->close(); } if (tabAdmin) { - tabAdmin->closeRequest(true); + tabAdmin->close(); } if (tabLog) { - tabLog->closeRequest(true); + tabLog->close(); } } @@ -497,7 +486,7 @@ void TabSupervisor::stop() } for (const auto tab : tabsToDelete) { - tab->closeRequest(true); + tab->close(); } userListManager->handleDisconnect(); @@ -521,7 +510,7 @@ void TabSupervisor::openTabVisualDeckStorage() { tabVisualDeckStorage = new TabDeckStorageVisual(this); myAddTab(tabVisualDeckStorage, aTabVisualDeckStorage); - connect(tabVisualDeckStorage, &Tab::closed, this, [this] { + connect(tabVisualDeckStorage, &QObject::destroyed, this, [this] { tabVisualDeckStorage = nullptr; aTabVisualDeckStorage->setChecked(false); }); @@ -544,7 +533,7 @@ void TabSupervisor::openTabServer() tabServer = new TabServer(this, client); connect(tabServer, &TabServer::roomJoined, this, &TabSupervisor::addRoomTab); myAddTab(tabServer, aTabServer); - connect(tabServer, &Tab::closed, this, [this] { + connect(tabServer, &QObject::destroyed, this, [this] { tabServer = nullptr; aTabServer->setChecked(false); }); @@ -569,7 +558,7 @@ void TabSupervisor::openTabAccount() connect(tabAccount, &TabAccount::userJoined, this, &TabSupervisor::processUserJoined); connect(tabAccount, &TabAccount::userLeft, this, &TabSupervisor::processUserLeft); myAddTab(tabAccount, aTabAccount); - connect(tabAccount, &Tab::closed, this, [this] { + connect(tabAccount, &QObject::destroyed, this, [this] { tabAccount = nullptr; aTabAccount->setChecked(false); }); @@ -592,7 +581,7 @@ void TabSupervisor::openTabDeckStorage() tabDeckStorage = new TabDeckStorage(this, client, userInfo); connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab); myAddTab(tabDeckStorage, aTabDeckStorage); - connect(tabDeckStorage, &Tab::closed, this, [this] { + connect(tabDeckStorage, &QObject::destroyed, this, [this] { tabDeckStorage = nullptr; aTabDeckStorage->setChecked(false); }); @@ -615,7 +604,7 @@ void TabSupervisor::openTabReplays() tabReplays = new TabReplays(this, client, userInfo); connect(tabReplays, &TabReplays::openReplay, this, &TabSupervisor::openReplay); myAddTab(tabReplays, aTabReplays); - connect(tabReplays, &Tab::closed, this, [this] { + connect(tabReplays, &QObject::destroyed, this, [this] { tabReplays = nullptr; aTabReplays->setChecked(false); }); @@ -638,7 +627,7 @@ void TabSupervisor::openTabAdmin() tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin)); connect(tabAdmin, &TabAdmin::adminLockChanged, this, &TabSupervisor::adminLockChanged); myAddTab(tabAdmin, aTabAdmin); - connect(tabAdmin, &Tab::closed, this, [this] { + connect(tabAdmin, &QObject::destroyed, this, [this] { tabAdmin = nullptr; aTabAdmin->setChecked(false); }); @@ -660,7 +649,7 @@ void TabSupervisor::openTabLog() { tabLog = new TabLog(this, client); myAddTab(tabLog, aTabLog); - connect(tabLog, &Tab::closed, this, [this] { + connect(tabLog, &QObject::destroyed, this, [this] { tabLog = nullptr; aTabAdmin->setChecked(false); }); diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp index 76423fb9b..1034b5651 100644 --- a/cockatrice/src/game/player/player.cpp +++ b/cockatrice/src/game/player/player.cpp @@ -420,6 +420,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T connect(aCreateAnotherToken, &QAction::triggered, this, &Player::actCreateAnotherToken); aCreateAnotherToken->setEnabled(false); + aIncrementAllCardCounters = new QAction(this); + connect(aIncrementAllCardCounters, &QAction::triggered, this, &Player::incrementAllCardCounters); + createPredefinedTokenMenu = new QMenu(QString()); createPredefinedTokenMenu->setEnabled(false); @@ -427,6 +430,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T playerMenu->addSeparator(); countersMenu = playerMenu->addMenu(QString()); + playerMenu->addAction(aIncrementAllCardCounters); playerMenu->addSeparator(); playerMenu->addAction(aUntapAll); playerMenu->addSeparator(); @@ -914,6 +918,7 @@ void Player::retranslateUi() aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(cardCounterSettings.displayName(i))); } + aIncrementAllCardCounters->setText(tr("Increment all card counters")); aMoveToTopLibrary->setText(tr("&Top of library in random order")); aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library...")); aMoveToBottomLibrary->setText(tr("&Bottom of library in random order")); @@ -964,38 +969,11 @@ void Player::setShortcutsActive() aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow")); aSelectColumn->setShortcuts(shortcuts.getShortcut("Player/aSelectColumn")); - QList addCCShortCuts; - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCRed")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCYellow")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCGreen")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCCyan")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCPurple")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCMagenta")); - - QList removeCCShortCuts; - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCRed")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCYellow")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCGreen")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCCyan")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCPurple")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCMagenta")); - - QList setCCShortCuts; - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCRed")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCYellow")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCGreen")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCCyan")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCPurple")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCMagenta")); - - for (int i = 0; i < addCCShortCuts.size(); ++i) { - aAddCounter[i]->setShortcut(addCCShortCuts.at(i)); - } - for (int i = 0; i < removeCCShortCuts.size(); ++i) { - aRemoveCounter[i]->setShortcut(removeCCShortCuts.at(i)); - } - for (int i = 0; i < setCCShortCuts.size(); ++i) { - aSetCounter[i]->setShortcut(setCCShortCuts.at(i)); + static const QStringList colorWords = {"Red", "Yellow", "Green", "Cyan", "Purple", "Magenta"}; + for (int i = 0; i < aAddCounter.size(); i++) { + aAddCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aCC" + colorWords[i])); + aRemoveCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aRC" + colorWords[i])); + aSetCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aSC" + colorWords[i])); } QMapIterator counterIterator(counters); @@ -1003,44 +981,45 @@ void Player::setShortcutsActive() counterIterator.next().value()->setShortcutsActive(); } - aViewSideboard->setShortcut(shortcuts.getSingleShortcut("Player/aViewSideboard")); - aViewLibrary->setShortcut(shortcuts.getSingleShortcut("Player/aViewLibrary")); - aViewHand->setShortcut(shortcuts.getSingleShortcut("Player/aViewHand")); - aViewTopCards->setShortcut(shortcuts.getSingleShortcut("Player/aViewTopCards")); - aViewBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aViewBottomCards")); - aViewGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aViewGraveyard")); - aDrawCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawCard")); - aDrawCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawCards")); - aUndoDraw->setShortcut(shortcuts.getSingleShortcut("Player/aUndoDraw")); - aMulligan->setShortcut(shortcuts.getSingleShortcut("Player/aMulligan")); - aShuffle->setShortcut(shortcuts.getSingleShortcut("Player/aShuffle")); - aShuffleTopCards->setShortcut(shortcuts.getSingleShortcut("Player/aShuffleTopCards")); - aShuffleBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aShuffleBottomCards")); - aUntapAll->setShortcut(shortcuts.getSingleShortcut("Player/aUntapAll")); - aRollDie->setShortcut(shortcuts.getSingleShortcut("Player/aRollDie")); - aCreateToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateToken")); - aCreateAnotherToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateAnotherToken")); - aAlwaysRevealTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysRevealTopCard")); - aAlwaysLookAtTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysLookAtTopCard")); - aMoveTopToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlay")); - aMoveTopToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlayFaceDown")); - aMoveTopCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToGraveyard")); - aMoveTopCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToGraveyard")); - aMoveTopCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToExile")); - aMoveTopCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToExile")); - aMoveTopCardsUntil->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsUntil")); - aMoveTopCardToBottom->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToBottom")); - aDrawBottomCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCard")); - aDrawBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCards")); - aMoveBottomToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlay")); - aMoveBottomToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlayFaceDown")); - aMoveBottomCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToGrave")); - aMoveBottomCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToGrave")); - aMoveBottomCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToExile")); - aMoveBottomCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToExile")); - aMoveBottomCardToTop->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToTop")); - aPlayFacedown->setShortcut(shortcuts.getSingleShortcut("Player/aPlayFacedown")); - aPlay->setShortcut(shortcuts.getSingleShortcut("Player/aPlay")); + aIncrementAllCardCounters->setShortcuts(shortcuts.getShortcut("Player/aIncrementAllCardCounters")); + aViewSideboard->setShortcuts(shortcuts.getShortcut("Player/aViewSideboard")); + aViewLibrary->setShortcuts(shortcuts.getShortcut("Player/aViewLibrary")); + aViewHand->setShortcuts(shortcuts.getShortcut("Player/aViewHand")); + aViewTopCards->setShortcuts(shortcuts.getShortcut("Player/aViewTopCards")); + aViewBottomCards->setShortcuts(shortcuts.getShortcut("Player/aViewBottomCards")); + aViewGraveyard->setShortcuts(shortcuts.getShortcut("Player/aViewGraveyard")); + aDrawCard->setShortcuts(shortcuts.getShortcut("Player/aDrawCard")); + aDrawCards->setShortcuts(shortcuts.getShortcut("Player/aDrawCards")); + aUndoDraw->setShortcuts(shortcuts.getShortcut("Player/aUndoDraw")); + aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan")); + aShuffle->setShortcuts(shortcuts.getShortcut("Player/aShuffle")); + aShuffleTopCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleTopCards")); + aShuffleBottomCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleBottomCards")); + aUntapAll->setShortcuts(shortcuts.getShortcut("Player/aUntapAll")); + aRollDie->setShortcuts(shortcuts.getShortcut("Player/aRollDie")); + aCreateToken->setShortcuts(shortcuts.getShortcut("Player/aCreateToken")); + aCreateAnotherToken->setShortcuts(shortcuts.getShortcut("Player/aCreateAnotherToken")); + aAlwaysRevealTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysRevealTopCard")); + aAlwaysLookAtTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysLookAtTopCard")); + aMoveTopToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlay")); + aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown")); + aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard")); + aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard")); + aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile")); + aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile")); + aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil")); + aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom")); + aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard")); + aDrawBottomCards->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCards")); + aMoveBottomToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlay")); + aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown")); + aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave")); + aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave")); + aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile")); + aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile")); + aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop")); + aPlayFacedown->setShortcuts(shortcuts.getShortcut("Player/aPlayFacedown")); + aPlay->setShortcuts(shortcuts.getShortcut("Player/aPlay")); // Don't enable always-active shortcuts in local games, since it causes keyboard shortcuts to work inconsistently // when there are more than 1 player. @@ -1089,6 +1068,7 @@ void Player::setShortcutsInactive() aMoveBottomCardsToGraveyard->setShortcut(QKeySequence()); aMoveBottomCardToExile->setShortcut(QKeySequence()); aMoveBottomCardsToExile->setShortcut(QKeySequence()); + aIncrementAllCardCounters->setShortcut(QKeySequence()); aSortHand->setShortcut(QKeySequence()); QMapIterator counterIterator(counters); @@ -3049,6 +3029,51 @@ void Player::clearCounters() counters.clear(); } +void Player::incrementAllCardCounters() +{ + QList cardsToUpdate; + + auto selectedItems = scene()->selectedItems(); + if (!selectedItems.isEmpty()) { + // If cards are selected, only update those + for (const auto &item : selectedItems) { + auto *card = static_cast(item); + cardsToUpdate.append(card); + } + } else { + // If no cards selected, update all cards on table + const CardList &tableCards = table->getCards(); + cardsToUpdate = tableCards; + } + + QList commandList; + + for (const auto *card : cardsToUpdate) { + const auto &cardCounters = card->getCounters(); + + QMapIterator counterIterator(cardCounters); + while (counterIterator.hasNext()) { + counterIterator.next(); + int counterId = counterIterator.key(); + int currentValue = counterIterator.value(); + if (currentValue >= MAX_COUNTERS_ON_CARD) { + continue; + } + + auto cmd = std::make_unique(); + cmd->set_zone(card->getZone()->getName().toStdString()); + cmd->set_card_id(card->getId()); + cmd->set_counter_id(counterId); + cmd->set_counter_value(currentValue + 1); + commandList.append(cmd.release()); + } + } + + if (!commandList.isEmpty()) { + sendGameCommand(prepareGameCommand(commandList)); + } +} + ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow) { const QMap &playerList = game->getPlayers(); @@ -4186,8 +4211,8 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) if (createRelatedCards) { if (shortcutsActive) { - createRelatedCards->setShortcut( - SettingsCache::instance().shortcuts().getSingleShortcut("Player/aCreateRelatedTokens")); + createRelatedCards->setShortcuts( + SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens")); } connect(createRelatedCards, &QAction::triggered, this, &Player::actCreateAllRelatedCards); cardMenu->addAction(createRelatedCards); diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h index 2f65956d3..3efad6b77 100644 --- a/cockatrice/src/game/player/player.h +++ b/cockatrice/src/game/player/player.h @@ -276,7 +276,7 @@ private: QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT, *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aFlowP, *aFlowT, *aSetAnnotation, *aFlip, *aPeek, *aClone, *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile, - *aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn, *aSortHand; + *aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn, *aSortHand, *aIncrementAllCardCounters; bool movingCardsUntil; QTimer *moveTopCardTimer; @@ -420,6 +420,7 @@ public: AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); void delCounter(int counterId); void clearCounters(); + void incrementAllCardCounters(); ArrowItem *addArrow(const ServerInfo_Arrow &arrow); ArrowItem *addArrow(int arrowId, CardItem *startCard, ArrowTarget *targetItem, const QColor &color); diff --git a/cockatrice/src/settings/shortcuts_settings.cpp b/cockatrice/src/settings/shortcuts_settings.cpp index db5559d8f..53c6f6a23 100644 --- a/cockatrice/src/settings/shortcuts_settings.cpp +++ b/cockatrice/src/settings/shortcuts_settings.cpp @@ -115,6 +115,13 @@ ShortcutKey ShortcutsSettings::getShortcut(const QString &name) const return getDefaultShortcut(name); } +/** + * Gets the first shortcut for the given action. + * + * NOTE: In most cases you should be using ShortcutsSettings::getShortcut instead, + * as that will return all shortcuts if there are multiple shortcuts. + * The only reason to use this method is if an object does not accept multiple shortcuts, such as with QButtons. + */ QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const { return getShortcut(name).at(0); diff --git a/cockatrice/src/settings/shortcuts_settings.h b/cockatrice/src/settings/shortcuts_settings.h index 68ee6ca12..fdf422783 100644 --- a/cockatrice/src/settings/shortcuts_settings.h +++ b/cockatrice/src/settings/shortcuts_settings.h @@ -413,6 +413,10 @@ private: {"Player/aSetCounter_storm", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Other Counters..."), parseSequenceString("Ctrl+\\"), ShortcutGroup::Player_Counters)}, + {"Player/aIncrementAllCardCounters", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increment all card counters"), + parseSequenceString("Ctrl+Shift+A"), + ShortcutGroup::Playing_Area)}, {"Player/aIncP", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Power (+1/+0)"), parseSequenceString("Ctrl++;Ctrl+="), ShortcutGroup::Power_Toughness)},