From b9cd942308fb547111ff159732d1660eadd388a2 Mon Sep 17 00:00:00 2001 From: Mark McDonald Date: Mon, 27 Feb 2017 02:50:10 -0500 Subject: [PATCH] Add keybaord shortcut for creating related cards (#2426) * Extract createCard from actCreateRelatedCard * Merge related cards and reverse related cards before handling * Add "Create all related cards" action to a card * Stop displaying all related tokens if only one token is available * Add shortcut for Creating all tokens related to selected card * Extract method for adding related card actions * Prefer foreach to index based iteration * Guard against null cards, card menus, or cardInfos * Remove QRegExp dependency from commonly depended header --- cockatrice/src/player.cpp | 138 ++++++++++++------ cockatrice/src/player.h | 7 +- cockatrice/src/sequenceEdit/ui_shortcutstab.h | 21 ++- cockatrice/src/shortcutssettings.cpp | 1 + 4 files changed, 114 insertions(+), 53 deletions(-) diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 7ad4a35c..f6196c5a 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "pb/command_change_zone_properties.pb.h" #include "pb/command_reveal_cards.pb.h" @@ -1095,20 +1096,33 @@ void Player::actCreatePredefinedToken() void Player::actCreateRelatedCard() { - // get the clicked card CardItem * sourceCard = game->getActiveCard(); if(!sourceCard) return; - // get the target card name QAction *action = static_cast(sender()); + const QString &actionDisplayName = action->text(); + createCard(sourceCard, dbNameFromTokenDisplayName(actionDisplayName)); +} - // removes p/t from tokens (and leading space)) - // Added split for "Token:" due to change in PR fixing #2317 - QStringList spaces = action->text().split(tr("Token: "))[1].split(" "); - if (spaces.at(0).indexOf("/") != -1) // Strip space from creatures - spaces.removeFirst(); - CardInfo *cardInfo = db->getCard(spaces.join(" ")); +void Player::actCreateAllRelatedCards() +{ + CardItem * sourceCard = game->getActiveCard(); + if(!sourceCard) + return; + + QStringList relatedCards = * new QStringList(); + relatedCards.append(sourceCard->getInfo()->getRelatedCards()); + relatedCards.append(sourceCard->getInfo()->getReverseRelatedCards2Me()); + + foreach (const QString &tokenName, relatedCards) + { + createCard(sourceCard, dbNameFromTokenDisplayName(tokenName)); + } +} + +void Player::createCard(const CardItem *sourceCard, const QString &dbCardName) { + CardInfo *cardInfo = db->getCard(dbCardName); if(!cardInfo) return; @@ -1177,6 +1191,21 @@ void Player::setCardAttrHelper(const GameEventContext &context, CardItem *card, } } +// token names take the form of " / " or " ". +// dbName for tokens should take the form of " ". +// trailing whitespace is significant; it is hacked on at the end as an additional identifier in our single key database +QString Player::dbNameFromTokenDisplayName(const QString &tokenName) { + QRegExp tokenNamePattern(".*/\\S+\\s+(.*)"); + + int index = tokenNamePattern.indexIn(tokenName); + if (index != -1) + { + return tokenNamePattern.capturedTexts()[1]; + } else { + return tokenName; + } +} + void Player::eventGameSay(const Event_GameSay &event) { emit logSay(this, QString::fromStdString(event.message())); @@ -2286,10 +2315,17 @@ void Player::actPlayFacedown() void Player::refreshShortcuts() { if(shortcutsActive) + { setShortcutsActive(); + + foreach (const CardItem *cardItem, table->getCards()) + { + updateCardMenu(cardItem); + } + } } -void Player::updateCardMenu(CardItem *card) +void Player::updateCardMenu(const CardItem *card) { QMenu *cardMenu = card->getCardMenu(); QMenu *ptMenu = card->getPTMenu(); @@ -2348,26 +2384,8 @@ void Player::updateCardMenu(CardItem *card) if (card->getFaceDown()) cardMenu->addAction(aPeek); - if(card->getInfo()) - { - QStringList relatedCards = card->getInfo()->getRelatedCards(); - QStringList reverserelatedCards2Me = card->getInfo()->getReverseRelatedCards2Me(); - if(relatedCards.size() || reverserelatedCards2Me.size()) - { - cardMenu->addSeparator(); - for (int i = 0; i < relatedCards.size(); ++i) { - QAction *a = new QAction(tr("Token: ") + relatedCards.at(i), this); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); - cardMenu->addAction(a); - } + addRelatedCardActions(card, cardMenu); - for (int i = 0; i < reverserelatedCards2Me.size(); ++i) { - QAction *a = new QAction(tr("Token: ") + reverserelatedCards2Me.at(i), this); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); - cardMenu->addAction(a); - } - } - } cardMenu->addSeparator(); cardMenu->addAction(aAttach); if (card->getAttachedTo()) @@ -2395,26 +2413,7 @@ void Player::updateCardMenu(CardItem *card) cardMenu->addAction(aDrawArrow); cardMenu->addMenu(moveMenu); - if(card->getInfo()) - { - QStringList relatedCards = card->getInfo()->getRelatedCards(); - QStringList reverserelatedCards2Me = card->getInfo()->getReverseRelatedCards2Me(); - if(relatedCards.size() || reverserelatedCards2Me.size()) - { - cardMenu->addSeparator(); - for (int i = 0; i < relatedCards.size(); ++i) { - QAction *a = new QAction(tr("Token: ") + relatedCards.at(i), this); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); - cardMenu->addAction(a); - } - - for (int i = 0; i < reverserelatedCards2Me.size(); ++i) { - QAction *a = new QAction(tr("Token: ") + reverserelatedCards2Me.at(i), this); - connect(a, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); - cardMenu->addAction(a); - } - } - } + addRelatedCardActions(card, cardMenu); } else { cardMenu->addAction(aPlay); cardMenu->addAction(aPlayFacedown); @@ -2425,6 +2424,49 @@ void Player::updateCardMenu(CardItem *card) } } +void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) { + if (!card || !cardMenu || !card->getInfo()) + { + return; + } + + QStringList relatedCards = *new QStringList(); + relatedCards.append(card->getInfo()->getRelatedCards()); + relatedCards.append(card->getInfo()->getReverseRelatedCards2Me()); + + switch (relatedCards.length()) { + case 0: + break; + case 1: { + cardMenu->addSeparator(); + QAction *createRelatedCards = new QAction(tr("Token: ") + relatedCards.at(0), this); + connect(createRelatedCards, SIGNAL(triggered()), this, SLOT(actCreateAllRelatedCards())); + if (shortcutsActive) { + createRelatedCards->setShortcut(settingsCache->shortcuts().getSingleShortcut("Player/aCreateRelatedTokens")); + } + cardMenu->addAction(createRelatedCards); + break; + } + default: { + cardMenu->addSeparator(); + foreach (QString cardName, relatedCards) + { + QAction *createRelated = new QAction(tr("Token: ") + cardName, this); + connect(createRelated, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard())); + cardMenu->addAction(createRelated); + } + QAction *createRelatedCards = new QAction(tr("All tokens"), this); + connect(createRelatedCards, SIGNAL(triggered()), this, SLOT(actCreateAllRelatedCards())); + if (shortcutsActive) { + createRelatedCards->setShortcut(settingsCache->shortcuts().getSingleShortcut("Player/aCreateRelatedTokens")); + } + cardMenu->addAction(createRelatedCards); + break; + } + } + +} + void Player::setCardMenu(QMenu *menu) { if (aCardMenu) diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index db13d7f8..f5f30723 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -141,6 +141,7 @@ private slots: void actOpenDeckInDeckEditor(); void actCreatePredefinedToken(); void actCreateRelatedCard(); + void actCreateAllRelatedCards(); void cardMenuAction(); void actCardCounterTrigger(); void actAttach(); @@ -209,6 +210,9 @@ private: PlayerTarget *playerTarget; void setCardAttrHelper(const GameEventContext &context, CardItem *card, CardAttribute attribute, const QString &avalue, bool allCards); + void addRelatedCardActions(const CardItem *card, QMenu *cardMenu); + void createCard(const CardItem *sourceCard, const QString &dbCardName); + QString dbNameFromTokenDisplayName(const QString &tokenName); QRectF bRect; @@ -281,7 +285,7 @@ public: const QMap &getArrows() const { return arrows; } void setCardMenu(QMenu *menu); QMenu *getCardMenu() const; - void updateCardMenu(CardItem *card); + void updateCardMenu(const CardItem *card); bool getActive() const { return active; } void setActive(bool _active); void setShortcutsActive(); @@ -306,6 +310,7 @@ public: PendingCommand *prepareGameCommand(const QList< const ::google::protobuf::Message * > &cmdList); void sendGameCommand(PendingCommand *pend); void sendGameCommand(const google::protobuf::Message &command); + }; #endif diff --git a/cockatrice/src/sequenceEdit/ui_shortcutstab.h b/cockatrice/src/sequenceEdit/ui_shortcutstab.h index 33641423..5058c862 100644 --- a/cockatrice/src/sequenceEdit/ui_shortcutstab.h +++ b/cockatrice/src/sequenceEdit/ui_shortcutstab.h @@ -199,6 +199,8 @@ public: SequenceEdit *Player_aClone; QLabel *lbl_Player_aCreateToken; SequenceEdit *Player_aCreateToken; + QLabel *lbl_Player_aCreateRelatedTokens; + SequenceEdit *Player_aCreateRelatedTokens; QLabel *lbl_Player_aCreateAnotherToken; SequenceEdit *Player_aCreateAnotherToken; QLabel *lbl_Player_aSetAnnotation; @@ -1080,25 +1082,35 @@ public: gridLayout_13->addWidget(Player_aCreateToken, 10, 1, 1, 1); + lbl_Player_aCreateRelatedTokens = new QLabel(groupBox_13); + lbl_Player_aCreateRelatedTokens->setObjectName("lbl_Player_aCreateRelatedTokens"); + + gridLayout_13->addWidget(lbl_Player_aCreateRelatedTokens, 11, 0, 1, 1); + + Player_aCreateRelatedTokens = new SequenceEdit("Player/aCreateRelatedTokens",groupBox_13); + Player_aCreateRelatedTokens->setObjectName("Player_aCreateRelatedTokens"); + + gridLayout_13->addWidget(Player_aCreateRelatedTokens, 11, 1, 1, 1); + lbl_Player_aCreateAnotherToken = new QLabel(groupBox_13); lbl_Player_aCreateAnotherToken->setObjectName("lbl_Player_aCreateAnotherToken"); - gridLayout_13->addWidget(lbl_Player_aCreateAnotherToken, 11, 0, 1, 1); + gridLayout_13->addWidget(lbl_Player_aCreateAnotherToken, 12, 0, 1, 1); Player_aCreateAnotherToken = new SequenceEdit("Player/aCreateAnotherToken",groupBox_13); Player_aCreateAnotherToken->setObjectName("Player_aCreateAnotherToken"); - gridLayout_13->addWidget(Player_aCreateAnotherToken, 11, 1, 1, 1); + gridLayout_13->addWidget(Player_aCreateAnotherToken, 12, 1, 1, 1); lbl_Player_aSetAnnotation = new QLabel(groupBox_13); lbl_Player_aSetAnnotation->setObjectName("lbl_Player_aSetAnnotation"); - gridLayout_13->addWidget(lbl_Player_aSetAnnotation, 12, 0, 1, 1); + gridLayout_13->addWidget(lbl_Player_aSetAnnotation, 13, 0, 1, 1); Player_aSetAnnotation = new SequenceEdit("Player/aSetAnnotation",groupBox_13); Player_aSetAnnotation->setObjectName("Player_aSetAnnotation"); - gridLayout_13->addWidget(Player_aSetAnnotation, 12, 1, 1, 1); + gridLayout_13->addWidget(Player_aSetAnnotation, 13, 1, 1, 1); gridLayout_17->addWidget(groupBox_13, 0, 2, 1, 1); @@ -1543,6 +1555,7 @@ public: lbl_Player_aUnattach->setText(QApplication::translate("shortcutsTab", "Unattach card", 0)); lbl_Player_aClone->setText(QApplication::translate("shortcutsTab", "Clone card", 0)); lbl_Player_aCreateToken->setText(QApplication::translate("shortcutsTab", "Create token", 0)); + lbl_Player_aCreateRelatedTokens->setText(QApplication::translate("shortcutsTab", "Create all related tokens", 0)); lbl_Player_aCreateAnotherToken->setText(QApplication::translate("shortcutsTab", "Create another token", 0)); lbl_Player_aSetAnnotation->setText(QApplication::translate("shortcutsTab", "Set annotation", 0)); tabWidget->setTabText(tabWidget->indexOf(tab_2), QApplication::translate("shortcutsTab", "Phases | P/T | Playing Area", 0)); diff --git a/cockatrice/src/shortcutssettings.cpp b/cockatrice/src/shortcutssettings.cpp index bf1bb440..c7b5171b 100644 --- a/cockatrice/src/shortcutssettings.cpp +++ b/cockatrice/src/shortcutssettings.cpp @@ -185,6 +185,7 @@ void ShortcutsSettings::fillDefaultShorcuts() defaultShortCuts["Player/aClone"] = parseSequenceString("Ctrl+J"); defaultShortCuts["Player/aCreateAnotherToken"] = parseSequenceString("Ctrl+G"); defaultShortCuts["Player/aCreateToken"] = parseSequenceString("Ctrl+T"); + defaultShortCuts["Player/aCreateRelatedTokens"] = parseSequenceString("Ctrl+Shift+T"); defaultShortCuts["Player/aDecP"] = parseSequenceString("Ctrl+-"); defaultShortCuts["Player/aDecPT"] = parseSequenceString("Ctrl+Alt+-"); defaultShortCuts["Player/aDecT"] = parseSequenceString("Alt+-");