[Game] Move graphics out of game and into game_graphics (#6928)
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run

* [Game][Player] Pull out graphics_items out of player_logic

Took 25 seconds


Took 9 minutes

* [Game] Move graphics files into game_graphics

Took 1 minute

Took 2 minutes

Took 23 seconds

Took 1 minute

Took 2 seconds

* Include.

Took 4 minutes

Took 3 minutes

Took 4 minutes

Took 1 minute

Took 3 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-06-09 09:51:13 +02:00 committed by GitHub
parent cbfd286908
commit da4ba222c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
116 changed files with 208 additions and 198 deletions

View file

@ -0,0 +1,32 @@
/**
* @file abstract_player_component.h
* @ingroup GameMenusPlayers
* @brief Polymorphic interface for player-bound UI components managed by PlayerMenu.
*/
#ifndef COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
#define COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
/**
* @brief Interface for player-bound UI components that need shortcut and translation lifecycle management.
*
* Not a QObject avoids diamond inheritance with Qt's MOC. Each concrete component
* inherits QObject through its Qt base class (QMenu, TearOffMenu, QGraphicsItem, etc.)
* and this interface through regular multiple inheritance.
*/
class AbstractPlayerComponent
{
public:
virtual ~AbstractPlayerComponent() = default;
/** @brief Bind keyboard shortcuts. Called when this player gains focus. */
virtual void setShortcutsActive() = 0;
/** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
virtual void setShortcutsInactive() = 0;
/** @brief Retranslate all user-visible strings. Called on language change. */
virtual void retranslateUi() = 0;
};
#endif // COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H

View file

@ -0,0 +1,551 @@
#include "card_menu.h"
#include "../../../client/settings/card_counter_settings.h"
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../board/card_item.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../../game/zones/view_zone_logic.h"
#include "../card_menu_action_type.h"
#include "../player_graphics_item.h"
#include "move_menu.h"
#include "pt_menu.h"
#include <QPainter>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/utility/zone_names.h>
/**
* @brief Creates a circular icon filled with the specified color.
*/
static QIcon createCircleIcon(const QColor &color)
{
QPixmap pixmap(32, 32);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(color);
painter.drawEllipse(pixmap.rect());
return QIcon(pixmap);
}
template <typename Slot>
static QAction *makeAction(QObject *parent, Slot &&slot, bool checkable = false, bool checked = false)
{
auto *a = new QAction(parent);
a->setCheckable(checkable);
if (checkable) {
a->setChecked(checked);
}
QObject::connect(a, &QAction::triggered, parent, std::forward<Slot>(slot));
return a;
}
CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _shortcutsActive)
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
{
const QList<PlayerLogic *> &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto playerToAdd : players) {
if (playerToAdd == player->getLogic()) {
continue;
}
playersInfo.append(qMakePair(playerToAdd->getPlayerInfo()->getName(), playerToAdd->getPlayerInfo()->getId()));
}
connect(player->getLogic()->getGame()->getPlayerManager(), &PlayerManager::playerRemoved, this,
&CardMenu::removePlayer);
auto *actions = player->getLogic()->getPlayerActions();
auto *gameScene = player->getGameScene();
// Single selection resolver used by all lambdas — called at trigger time
auto sel = [gameScene]() { return gameScene->selectedCards(); };
// Unified dispatcher for card menu actions
auto invoke = [actions, sel](CardMenuActionType type) {
return [actions, sel, type]() { actions->cardMenuAction(sel(), type); };
};
// Actions using invoke (type dispatch, need selection)
aTap = makeAction(this, invoke(cmTap));
aDoesntUntap = makeAction(this, invoke(cmDoesntUntap), /*checkable=*/true, card && card->getDoesntUntap());
aFlip = makeAction(this, invoke(cmFlip));
aPeek = makeAction(this, invoke(cmPeek));
aClone = makeAction(this, invoke(cmClone));
// Actions using selection directly
aUnattach = makeAction(this, [actions, sel]() { actions->actUnattach(sel()); });
aSetAnnotation = makeAction(this, [actions, sel]() { actions->actRequestSetAnnotationDialog(sel()); });
aPlay = makeAction(this, [actions, sel]() { actions->actPlay(sel()); });
aPlayFacedown = makeAction(this, [actions, sel]() { actions->actPlayFacedown(sel()); });
aHide = makeAction(this, [actions, sel]() { actions->actHide(sel()); });
aReduceLifeByPower = makeAction(this, [actions, sel]() { actions->actReduceLifeByPower(sel()); });
// Actions that use activeCard, not selection — direct connection
aAttach = new QAction(this);
aDrawArrow = new QAction(this);
aSelectAll = new QAction(this);
aSelectRow = new QAction(this);
aSelectColumn = new QAction(this);
connect(aAttach, &QAction::triggered, actions, &PlayerActions::actAttach);
connect(aDrawArrow, &QAction::triggered, actions, &PlayerActions::actDrawArrow);
connect(aSelectAll, &QAction::triggered, actions, &PlayerActions::actSelectAll);
connect(aSelectRow, &QAction::triggered, actions, &PlayerActions::actSelectRow);
connect(aSelectColumn, &QAction::triggered, actions, &PlayerActions::actSelectColumn);
aRevealToAll = new QAction(this);
mCardCounters = new QMenu;
// Card counters
for (int i = 0; i < 6; ++i) {
QColor color = SettingsCache::instance().cardCounters().color(i);
QIcon circleIcon = createCircleIcon(color);
auto *addAction = makeAction(this, [actions, sel, i]() { actions->actAddCardCounter(sel(), i); });
addAction->setIcon(circleIcon);
aAddCounter.append(addAction);
auto *removeAction = makeAction(this, [actions, sel, i]() { actions->actRemoveCardCounter(sel(), i); });
removeAction->setIcon(circleIcon);
aRemoveCounter.append(removeAction);
auto *setAction = makeAction(this, [actions, sel, i]() { actions->actRequestSetCardCounterDialog(sel(), i); });
setAction->setIcon(circleIcon);
aSetCounter.append(setAction);
}
setShortcutsActive();
retranslateUi();
if (card == nullptr) {
return;
}
bool revealedCard = false;
bool writeableCard = player->getLogic()->getPlayerInfo()->getLocalOrJudge();
if (auto *view = qobject_cast<ZoneViewZoneLogic *>(card->getZone())) {
if (view->getRevealZone()) {
if (view->getWriteableRevealZone()) {
writeableCard = true;
} else {
revealedCard = true;
}
}
}
if (revealedCard) {
addAction(aHide);
addSeparator();
addAction(aClone);
addSeparator();
addAction(aSelectAll);
addAction(aSelectColumn);
addRelatedCardView();
} else {
if (card->getZone()) {
if (card->getZone()->getName() == ZoneNames::TABLE) {
createTableMenu(writeableCard);
} else if (card->getZone()->getName() == ZoneNames::STACK) {
createStackMenu(writeableCard);
} else if (card->getZone()->getName() == ZoneNames::EXILE ||
card->getZone()->getName() == ZoneNames::GRAVE) {
createGraveyardOrExileMenu(writeableCard);
} else {
createHandOrCustomZoneMenu(writeableCard);
}
} else {
createZonelessMenu(writeableCard);
}
}
}
void CardMenu::removePlayer(PlayerLogic *playerToRemove)
{
for (auto it = playersInfo.begin(); it != playersInfo.end();) {
if (it->second == playerToRemove->getPlayerInfo()->getId()) {
it = playersInfo.erase(it);
} else {
++it;
}
}
}
void CardMenu::createTableMenu(bool canModifyCard)
{
// Card is on the battlefield
if (!canModifyCard) {
addAction(aDrawArrow);
addSeparator();
addAction(aClone);
addSeparator();
addAction(aReduceLifeByPower);
addSeparator();
addAction(aSelectAll);
addAction(aSelectRow);
addRelatedCardView();
addRelatedCardActions();
return;
}
addAction(aTap);
addAction(aDoesntUntap);
addAction(aFlip);
if (card->getFaceDown()) {
addAction(aPeek);
}
addSeparator();
addAction(aClone);
addMenu(new MoveMenu(player));
addSeparator();
addAction(aAttach);
if (card->getAttachedTo()) {
addAction(aUnattach);
}
addAction(aDrawArrow);
addSeparator();
addMenu(new PtMenu(player));
addAction(aSetAnnotation);
addSeparator();
addAction(aReduceLifeByPower);
addSeparator();
addAction(aSelectAll);
addAction(aSelectRow);
addSeparator();
mCardCounters->clear();
for (int i = 0; i < aAddCounter.size(); ++i) {
mCardCounters->addSeparator();
mCardCounters->addAction(aAddCounter[i]);
if (card->getCounters().contains(i)) {
mCardCounters->addAction(aRemoveCounter[i]);
}
mCardCounters->addAction(aSetCounter[i]);
}
addSeparator();
addMenu(mCardCounters);
addRelatedCardView();
addRelatedCardActions();
}
void CardMenu::createStackMenu(bool canModifyCard)
{
// Card is on the stack
if (!canModifyCard) {
addAction(aDrawArrow);
addSeparator();
addAction(aClone);
addSeparator();
addAction(aSelectAll);
addRelatedCardView();
addRelatedCardActions();
return;
}
addAction(aPlay);
addAction(aPlayFacedown);
addSeparator();
addAction(aClone);
addMenu(new MoveMenu(player));
addSeparator();
addAction(aAttach);
addAction(aDrawArrow);
addSeparator();
addAction(aSelectAll);
addRelatedCardView();
addRelatedCardActions();
}
void CardMenu::createGraveyardOrExileMenu(bool canModifyCard)
{
// Card is in the graveyard or exile
if (!canModifyCard) {
addAction(aDrawArrow);
addSeparator();
addAction(aClone);
addSeparator();
addAction(aSelectAll);
addAction(aSelectColumn);
addRelatedCardView();
addRelatedCardActions();
return;
}
addAction(aPlay);
addAction(aPlayFacedown);
addSeparator();
addAction(aClone);
addMenu(new MoveMenu(player));
addSeparator();
addAction(aAttach);
addAction(aDrawArrow);
addSeparator();
addAction(aSelectAll);
addAction(aSelectColumn);
addRelatedCardView();
addRelatedCardActions();
}
void CardMenu::createHandOrCustomZoneMenu(bool canModifyCard)
{
if (!canModifyCard) {
addAction(aDrawArrow);
addSeparator();
addAction(aClone);
addSeparator();
addAction(aSelectAll);
addRelatedCardView();
addRelatedCardActions();
return;
}
// Card is in hand or a custom zone specified by server
addAction(aPlay);
addAction(aPlayFacedown);
QMenu *revealMenu = addMenu(tr("Re&veal to..."));
initContextualPlayersMenu(revealMenu, aRevealToAll);
connect(revealMenu, &QMenu::triggered, this, [this](QAction *action) {
player->getLogic()->getPlayerActions()->actReveal(player->getGameScene()->selectedCards(), action);
});
addSeparator();
addAction(aClone);
addMenu(new MoveMenu(player));
// actions that are really wonky when done from deck or sideboard
if (card->getZone()->getName() == ZoneNames::HAND) {
addSeparator();
addAction(aAttach);
addAction(aDrawArrow);
}
addSeparator();
addAction(aSelectAll);
if (qobject_cast<ZoneViewZoneLogic *>(card->getZone())) {
addAction(aSelectColumn);
}
addRelatedCardView();
if (card->getZone()->getName() == ZoneNames::HAND) {
addRelatedCardActions();
}
}
void CardMenu::createZonelessMenu(bool canModifyCard)
{
if (canModifyCard) {
addMenu(new MoveMenu(player));
}
}
/**
* @brief Populates the menu with an action for each active player.
*
* The "all players" action is created separately, so it has to be passed into this function.
* It will be put at the top of the menu.
*
* @param menu The menu to add the player actions to.
* @param allPlayersAction The action for "all players".
*/
void CardMenu::initContextualPlayersMenu(QMenu *menu, QAction *allPlayersAction)
{
allPlayersAction->setData(-1);
menu->addAction(allPlayersAction);
menu->addSeparator();
for (const auto &playerInfo : playersInfo) {
menu->addAction(playerInfo.first)->setData(playerInfo.second);
}
}
void CardMenu::addRelatedCardView()
{
if (!card) {
return;
}
auto exactCard = card->getCard();
if (!exactCard) {
return;
}
bool atLeastOneGoodRelationFound = false;
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
for (const CardRelation *cardRelation : relatedCards) {
CardInfoPtr relatedCard = CardDatabaseManager::query()->getCardInfo(cardRelation->getName());
if (relatedCard != nullptr) {
atLeastOneGoodRelationFound = true;
break;
}
}
if (!atLeastOneGoodRelationFound) {
return;
}
addSeparator();
auto viewRelatedCards = new QMenu(tr("View related cards"));
addMenu(viewRelatedCards);
for (const CardRelation *relatedCard : relatedCards) {
QString relatedCardName = relatedCard->getName();
CardRef cardRef = {relatedCardName, exactCard.getPrinting().getUuid()};
QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
Q_UNUSED(viewCard);
connect(viewCard, &QAction::triggered, this, [this, cardRef] { emit cardInfoRequested(cardRef); });
}
}
void CardMenu::addRelatedCardActions()
{
if (!card) {
return;
}
auto exactCard = card->getCard();
if (!exactCard) {
return;
}
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
if (relatedCards.isEmpty()) {
return;
}
addSeparator();
int index = 0;
QAction *createRelatedCards = nullptr;
for (const CardRelation *cardRelation : relatedCards) {
ExactCard relatedCard =
CardDatabaseManager::query()->getCardFromSameSet(cardRelation->getName(), card->getCard().getPrinting());
if (!relatedCard) {
relatedCard = CardDatabaseManager::query()->getCard({cardRelation->getName()});
}
if (!relatedCard) {
continue;
}
QString relatedCardName;
if (relatedCard.getInfo().getPowTough().size() > 0) {
relatedCardName = relatedCard.getInfo().getPowTough() + " " + relatedCard.getName(); // "n/n name"
} else {
relatedCardName = relatedCard.getName(); // "name"
}
QString text = tr("Token: ");
if (cardRelation->getDoesAttach()) {
text +=
tr(cardRelation->getDoesTransform() ? "Transform into " : "Attach to ") + "\"" + relatedCardName + "\"";
} else if (cardRelation->getIsVariable()) {
text += "X " + relatedCardName;
} else if (cardRelation->getDefaultCount() != 1) {
text += QString::number(cardRelation->getDefaultCount()) + "x " + relatedCardName;
} else {
text += relatedCardName;
}
if (createRelatedCards == nullptr) {
if (relatedCards.length() == 1) {
createRelatedCards = new QAction(text, this); // set actCreateAllRelatedCards with this text
break; // do not set an individual entry as there is only one entry
} else {
createRelatedCards = new QAction(tr("All tokens"), this);
}
}
auto *createRelated = new QAction(text, this);
createRelated->setData(QVariant(index++));
connect(createRelated, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actCreateRelatedCard);
addAction(createRelated);
}
if (createRelatedCards) {
if (shortcutsActive) {
createRelatedCards->setShortcuts(
SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens"));
}
connect(createRelatedCards, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actCreateAllRelatedCards);
addAction(createRelatedCards);
}
}
void CardMenu::retranslateUi()
{
aSelectAll->setText(tr("&Select All"));
aSelectRow->setText(tr("S&elect Row"));
aSelectColumn->setText(tr("S&elect Column"));
aPlay->setText(tr("&Play"));
aHide->setText(tr("&Hide"));
aPlayFacedown->setText(tr("Play &Face Down"));
aRevealToAll->setText(tr("&All players"));
//: Turn sideways or back again
aTap->setText(tr("&Tap / Untap"));
aDoesntUntap->setText(tr("Skip &untapping"));
//: Turn face up/face down
aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over"
// All code and proto bits are still unchanged (flip) for compatibility reasons
// A protocol rewrite with v3 could incorporate that, see #3100
aPeek->setText(tr("&Peek at card face"));
aClone->setText(tr("&Clone"));
aAttach->setText(tr("Attac&h to card..."));
aUnattach->setText(tr("Unattac&h"));
aDrawArrow->setText(tr("&Draw arrow..."));
aSetAnnotation->setText(tr("&Set annotation..."));
aReduceLifeByPower->setText(tr("Reduce life by power"));
mCardCounters->setTitle(tr("Ca&rd counters"));
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
for (int i = 0; i < aAddCounter.size(); ++i) {
aAddCounter[i]->setText(tr("&Add counter (%1)").arg(cardCounterSettings.displayName(i)));
}
for (int i = 0; i < aRemoveCounter.size(); ++i) {
aRemoveCounter[i]->setText(tr("&Remove counter (%1)").arg(cardCounterSettings.displayName(i)));
}
for (int i = 0; i < aSetCounter.size(); ++i) {
aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(cardCounterSettings.displayName(i)));
}
}
void CardMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aHide->setShortcuts(shortcuts.getShortcut("Player/aHide"));
aPlay->setShortcuts(shortcuts.getShortcut("Player/aPlay"));
aPlayFacedown->setShortcuts(shortcuts.getShortcut("Player/aPlayFacedown"));
aRevealToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealToAll"));
aTap->setShortcuts(shortcuts.getShortcut("Player/aTap"));
aDoesntUntap->setShortcuts(shortcuts.getShortcut("Player/aDoesntUntap"));
aFlip->setShortcuts(shortcuts.getShortcut("Player/aFlip"));
aPeek->setShortcuts(shortcuts.getShortcut("Player/aPeek"));
aClone->setShortcuts(shortcuts.getShortcut("Player/aClone"));
aAttach->setShortcuts(shortcuts.getShortcut("Player/aAttach"));
aUnattach->setShortcuts(shortcuts.getShortcut("Player/aUnattach"));
aDrawArrow->setShortcuts(shortcuts.getShortcut("Player/aDrawArrow"));
aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation"));
aReduceLifeByPower->setShortcuts(shortcuts.getShortcut("Player/aReduceLifeByPower"));
aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll"));
aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow"));
aSelectColumn->setShortcuts(shortcuts.getShortcut("Player/aSelectColumn"));
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]));
}
}

View file

@ -0,0 +1,61 @@
/**
* @file card_menu.h
* @ingroup GameMenusCards
*/
//! \todo Document this file.
#ifndef COCKATRICE_CARD_MENU_H
#define COCKATRICE_CARD_MENU_H
#include <QMenu>
#include <libcockatrice/utility/card_ref.h>
class CardItem;
class PlayerGraphicsItem;
class PlayerLogic;
class CardMenu : public QMenu
{
Q_OBJECT
signals:
void cardInfoRequested(const CardRef &cardRef);
public:
explicit CardMenu(PlayerGraphicsItem *player, const CardItem *card, bool shortcutsActive);
void removePlayer(PlayerLogic *playerToRemove);
void createTableMenu(bool canModifyCard);
void createStackMenu(bool canModifyCard);
void createGraveyardOrExileMenu(bool canModifyCard);
void createHandOrCustomZoneMenu(bool canModifyCard);
void createZonelessMenu(bool canModifyCard);
QMenu *mCardCounters;
QAction *aPlay, *aPlayFacedown;
QAction *aRevealToAll;
QAction *aHide;
QAction *aClone;
QAction *aSelectAll, *aSelectRow, *aSelectColumn;
QAction *aDrawArrow;
QAction *aTap, *aDoesntUntap;
QAction *aFlip, *aPeek;
QAction *aAttach, *aUnattach;
QAction *aSetAnnotation;
QAction *aReduceLifeByPower;
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
private:
PlayerGraphicsItem *player;
const CardItem *card;
QList<QPair<QString, int>> playersInfo;
bool shortcutsActive;
void addRelatedCardActions();
void retranslateUi();
void initContextualPlayersMenu(QMenu *menu, QAction *allPlayersAction);
void setShortcutsActive();
void addRelatedCardView();
};
#endif // COCKATRICE_CARD_MENU_H

View file

@ -0,0 +1,42 @@
#include "custom_zone_menu.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
CustomZoneMenu::CustomZoneMenu(PlayerGraphicsItem *_player) : player(_player)
{
menuAction()->setVisible(false);
connect(player->getLogic(), &PlayerLogic::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
connect(player->getLogic(), &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
&CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu);
retranslateUi();
}
void CustomZoneMenu::retranslateUi()
{
setTitle(tr("C&ustom Zones"));
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
for (auto aViewZone : actions()) {
aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString()));
}
}
}
void CustomZoneMenu::clearCustomZonesMenu()
{
clear();
menuAction()->setVisible(false);
}
void CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu(QString zoneName)
{
menuAction()->setVisible(true);
QAction *aViewZone = addAction(tr("View custom zone '%1'").arg(zoneName));
aViewZone->setData(zoneName);
connect(aViewZone, &QAction::triggered, this,
[zoneName, this]() { player->getGameScene()->toggleZoneView(player->getLogic(), zoneName, -1); });
}

View file

@ -0,0 +1,35 @@
/**
* @file custom_zone_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
#define COCKATRICE_CUSTOM_ZONE_MENU_H
#include "abstract_player_component.h"
#include <QMenu>
class PlayerGraphicsItem;
class CustomZoneMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit CustomZoneMenu(PlayerGraphicsItem *player);
void retranslateUi() override;
void setShortcutsActive() override
{
}
void setShortcutsInactive() override
{
}
private:
PlayerGraphicsItem *player;
private slots:
void clearCustomZonesMenu();
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);
};
#endif // COCKATRICE_CUSTOM_ZONE_MENU_H

View file

@ -0,0 +1,124 @@
#include "grave_menu.h"
#include "../../game/abstract_game.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
#include <QAction>
#include <QMenu>
#include <libcockatrice/utility/zone_names.h>
GraveyardMenu::GraveyardMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createMoveActions();
createViewActions();
addAction(aViewGraveyard);
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
mRevealRandomGraveyardCard = addMenu(QString());
connect(mRevealRandomGraveyardCard, &QMenu::aboutToShow, this,
&GraveyardMenu::populateRevealRandomMenuWithActivePlayers);
addSeparator();
moveGraveMenu = addTearOffMenu(QString());
moveGraveMenu->addAction(aMoveGraveToTopLibrary);
moveGraveMenu->addAction(aMoveGraveToBottomLibrary);
moveGraveMenu->addSeparator();
moveGraveMenu->addAction(aMoveGraveToHand);
moveGraveMenu->addSeparator();
moveGraveMenu->addAction(aMoveGraveToRfg);
}
retranslateUi();
}
void GraveyardMenu::createMoveActions()
{
auto grave = player->getLogic()->getGraveZone();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveGraveToTopLibrary = new QAction(this);
aMoveGraveToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
aMoveGraveToBottomLibrary = new QAction(this);
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
aMoveGraveToHand = new QAction(this);
aMoveGraveToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
aMoveGraveToRfg = new QAction(this);
aMoveGraveToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
connect(aMoveGraveToHand, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
connect(aMoveGraveToRfg, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
}
}
void GraveyardMenu::createViewActions()
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
aViewGraveyard = new QAction(this);
connect(aViewGraveyard, &QAction::triggered, playerActions, &PlayerActions::actViewGraveyard);
}
void GraveyardMenu::populateRevealRandomMenuWithActivePlayers()
{
mRevealRandomGraveyardCard->clear();
QAction *allPlayers = mRevealRandomGraveyardCard->addAction(tr("&All players"));
allPlayers->setData(-1);
connect(allPlayers, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered);
mRevealRandomGraveyardCard->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealRandomGraveyardCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered);
}
}
void GraveyardMenu::onRevealRandomTriggered()
{
if (auto *a = qobject_cast<QAction *>(sender())) {
player->getLogic()->getPlayerActions()->actRevealRandomGraveyardCard(a->data().toInt());
}
}
void GraveyardMenu::retranslateUi()
{
setTitle(tr("&Graveyard"));
aViewGraveyard->setText(tr("&View graveyard"));
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
moveGraveMenu->setTitle(tr("&Move graveyard to..."));
aMoveGraveToTopLibrary->setText(tr("&Top of library"));
aMoveGraveToBottomLibrary->setText(tr("&Bottom of library"));
aMoveGraveToHand->setText(tr("&Hand"));
aMoveGraveToRfg->setText(tr("&Exile"));
mRevealRandomGraveyardCard->setTitle(tr("Reveal random card to..."));
}
}
void GraveyardMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aViewGraveyard->setShortcuts(shortcuts.getShortcut("Player/aViewGraveyard"));
}
void GraveyardMenu::setShortcutsInactive()
{
aViewGraveyard->setShortcut(QKeySequence());
}

View file

@ -0,0 +1,46 @@
/**
* @file grave_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_GRAVE_MENU_H
#define COCKATRICE_GRAVE_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "abstract_player_component.h"
#include <QAction>
#include <QMenu>
class PlayerGraphicsItem;
class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
signals:
void newPlayerActionCreated(QAction *action);
public:
explicit GraveyardMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
void createMoveActions();
void createViewActions();
void populateRevealRandomMenuWithActivePlayers();
void onRevealRandomTriggered();
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
QMenu *mRevealRandomGraveyardCard = nullptr;
QMenu *moveGraveMenu = nullptr;
QAction *aViewGraveyard = nullptr;
QAction *aMoveGraveToTopLibrary = nullptr;
QAction *aMoveGraveToBottomLibrary = nullptr;
QAction *aMoveGraveToHand = nullptr;
QAction *aMoveGraveToRfg = nullptr;
private:
PlayerGraphicsItem *player;
};
#endif // COCKATRICE_GRAVE_MENU_H

View file

@ -0,0 +1,223 @@
#include "hand_menu.h"
#include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h"
#include "../../../game_graphics/zones/hand_zone.h"
#include "../../game/abstract_game.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
#include <QAction>
#include <QMenu>
#include <libcockatrice/utility/zone_names.h>
HandMenu::HandMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
auto *actions = player->getLogic()->getPlayerActions();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aViewHand = new QAction(this);
connect(aViewHand, &QAction::triggered, actions, &PlayerActions::actViewHand);
addAction(aViewHand);
mSortHand = addMenu(QString());
aSortHandByName = new QAction(this);
aSortHandByName->setData(CardList::SortByName);
aSortHandByType = new QAction(this);
aSortHandByType->setData(CardList::SortByMainType);
aSortHandByManaValue = new QAction(this);
aSortHandByManaValue->setData(CardList::SortByManaValue);
connect(aSortHandByType, &QAction::triggered, actions, &PlayerActions::actSortHand);
connect(aSortHandByName, &QAction::triggered, actions, &PlayerActions::actSortHand);
connect(aSortHandByManaValue, &QAction::triggered, actions, &PlayerActions::actSortHand);
mSortHand->addAction(aSortHandByName);
mSortHand->addAction(aSortHandByType);
mSortHand->addAction(aSortHandByManaValue);
}
mRevealHand = addMenu(QString());
connect(mRevealHand, &QMenu::aboutToShow, this, &HandMenu::populateRevealHandMenuWithActivePlayers);
aRevealHandToAll = new QAction(this);
aRevealHandToAll->setData(-1);
connect(aRevealHandToAll, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
mRevealRandomHandCard = addMenu(QString());
connect(mRevealRandomHandCard, &QMenu::aboutToShow, this,
&HandMenu::populateRevealRandomHandCardMenuWithActivePlayers);
aRevealRandomHandCardToAll = new QAction(this);
aRevealRandomHandCardToAll->setData(-1);
connect(aRevealRandomHandCardToAll, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
// We still need to add these actions to menu here so that the shortcuts are active right away
mRevealHand->addAction(aRevealHandToAll);
mRevealRandomHandCard->addAction(aRevealRandomHandCardToAll);
addSeparator();
aMulligan = new QAction(this);
connect(aMulligan, &QAction::triggered, actions, &PlayerActions::actRequestMulliganDialog);
addAction(aMulligan);
// Mulligan same size
aMulliganSame = new QAction(this);
connect(aMulliganSame, &QAction::triggered, actions, &PlayerActions::actMulliganSameSize);
addAction(aMulliganSame);
// Mulligan -1
aMulliganMinusOne = new QAction(this);
connect(aMulliganMinusOne, &QAction::triggered, actions, &PlayerActions::actMulliganMinusOne);
addAction(aMulliganMinusOne);
addSeparator();
mMoveHandMenu = addTearOffMenu(QString());
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveHandToTopLibrary = new QAction(this);
aMoveHandToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
aMoveHandToBottomLibrary = new QAction(this);
aMoveHandToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
aMoveHandToGrave = new QAction(this);
aMoveHandToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
aMoveHandToRfg = new QAction(this);
aMoveHandToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
auto hand = player->getLogic()->getHandZone();
connect(aMoveHandToTopLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToBottomLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToGrave, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToRfg, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
mMoveHandMenu->addAction(aMoveHandToTopLibrary);
mMoveHandMenu->addAction(aMoveHandToBottomLibrary);
mMoveHandMenu->addSeparator();
mMoveHandMenu->addAction(aMoveHandToGrave);
mMoveHandMenu->addSeparator();
mMoveHandMenu->addAction(aMoveHandToRfg);
}
retranslateUi();
}
void HandMenu::retranslateUi()
{
setTitle(tr("&Hand"));
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aViewHand->setText(tr("&View hand"));
mSortHand->setTitle(tr("Sort hand by..."));
aSortHandByName->setText(tr("Name"));
aSortHandByType->setText(tr("Type"));
aSortHandByManaValue->setText(tr("Mana Value"));
aMulligan->setText(tr("Take &mulligan (Choose hand size)"));
aMulliganSame->setText(tr("Take mulligan (Same hand size)"));
aMulliganMinusOne->setText(tr("Take mulligan (Hand size - 1)"));
mMoveHandMenu->setTitle(tr("&Move hand to..."));
aMoveHandToTopLibrary->setText(tr("&Top of library"));
aMoveHandToBottomLibrary->setText(tr("&Bottom of library"));
aMoveHandToGrave->setText(tr("&Graveyard"));
aMoveHandToRfg->setText(tr("&Exile"));
mRevealHand->setTitle(tr("&Reveal hand to..."));
aRevealHandToAll->setText(tr("All players"));
mRevealRandomHandCard->setTitle(tr("Reveal r&andom card to..."));
aRevealRandomHandCardToAll->setText(tr("All players"));
}
}
void HandMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aViewHand->setShortcuts(shortcuts.getShortcut("Player/aViewHand"));
aSortHandByName->setShortcuts(shortcuts.getShortcut("Player/aSortHandByName"));
aSortHandByType->setShortcuts(shortcuts.getShortcut("Player/aSortHandByType"));
aSortHandByManaValue->setShortcuts(shortcuts.getShortcut("Player/aSortHandByManaValue"));
aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan"));
aMulliganSame->setShortcuts(shortcuts.getShortcut("Player/aMulliganSame"));
aMulliganMinusOne->setShortcuts(shortcuts.getShortcut("Player/aMulliganMinusOne"));
aRevealHandToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealHandToAll"));
aRevealRandomHandCardToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealRandomHandCardToAll"));
}
void HandMenu::setShortcutsInactive()
{
aViewHand->setShortcut(QKeySequence());
aSortHandByName->setShortcut(QKeySequence());
aSortHandByType->setShortcut(QKeySequence());
aSortHandByManaValue->setShortcut(QKeySequence());
aMulligan->setShortcut(QKeySequence());
aRevealHandToAll->setShortcut(QKeySequence());
aRevealRandomHandCardToAll->setShortcut(QKeySequence());
}
void HandMenu::populateRevealHandMenuWithActivePlayers()
{
mRevealHand->clear();
mRevealHand->addAction(aRevealHandToAll);
mRevealHand->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
}
}
void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
{
mRevealRandomHandCard->clear();
mRevealRandomHandCard->addAction(aRevealRandomHandCardToAll);
mRevealRandomHandCard->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
}
}
void HandMenu::onRevealHandTriggered()
{
auto *action = qobject_cast<QAction *>(sender());
if (!action) {
return;
}
const int targetId = action->data().toInt();
player->getLogic()->getPlayerActions()->actRevealHand(targetId);
}
void HandMenu::onRevealRandomHandCardTriggered()
{
auto *action = qobject_cast<QAction *>(sender());
if (!action) {
return;
}
const int targetId = action->data().toInt();
player->getLogic()->getPlayerActions()->actRevealRandomHandCard(targetId);
}

View file

@ -0,0 +1,71 @@
/**
* @file hand_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_HAND_MENU_H
#define COCKATRICE_HAND_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "abstract_player_component.h"
#include <QAction>
#include <QMenu>
class PlayerGraphicsItem;
class PlayerActions;
class HandMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
HandMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
QMenu *revealHandMenu() const
{
return mRevealHand;
}
QMenu *revealRandomHandCardMenu() const
{
return mRevealRandomHandCard;
}
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
private slots:
void populateRevealHandMenuWithActivePlayers();
void populateRevealRandomHandCardMenuWithActivePlayers();
void onRevealHandTriggered();
void onRevealRandomHandCardTriggered();
private:
PlayerGraphicsItem *player;
QAction *aViewHand = nullptr;
QAction *aMulligan = nullptr;
QAction *aMulliganSame = nullptr;
QAction *aMulliganMinusOne = nullptr;
QMenu *mSortHand = nullptr;
QAction *aSortHandByName = nullptr;
QAction *aSortHandByType = nullptr;
QAction *aSortHandByManaValue = nullptr;
QMenu *mRevealHand = nullptr;
QAction *aRevealHandToAll = nullptr;
QMenu *mRevealRandomHandCard = nullptr;
QAction *aRevealRandomHandCardToAll = nullptr;
QMenu *mMoveHandMenu = nullptr;
QAction *aMoveHandToTopLibrary = nullptr;
QAction *aMoveHandToBottomLibrary = nullptr;
QAction *aMoveHandToGrave = nullptr;
QAction *aMoveHandToRfg = nullptr;
};
#endif // COCKATRICE_HAND_MENU_H

View file

@ -0,0 +1,421 @@
#include "library_menu.h"
#include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h"
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../game/abstract_game.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
#include <QAction>
#include <QGraphicsView>
#include <QMenu>
LibraryMenu::LibraryMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createDrawActions();
createShuffleActions();
createMoveActions();
createViewActions();
addAction(aDrawCard);
addAction(aDrawCards);
addAction(aUndoDraw);
addSeparator();
addAction(aShuffle);
addSeparator();
addAction(aViewLibrary);
addAction(aViewTopCards);
addAction(aViewBottomCards);
addSeparator();
mRevealLibrary = addMenu(QString());
connect(mRevealLibrary, &QMenu::aboutToShow, this, &LibraryMenu::populateRevealLibraryMenuWithActivePlayers);
mLendLibrary = addMenu(QString());
connect(mLendLibrary, &QMenu::aboutToShow, this, &LibraryMenu::populateLendLibraryMenuWithActivePlayers);
mRevealTopCard = addMenu(QString());
connect(mRevealTopCard, &QMenu::aboutToShow, this, &LibraryMenu::populateRevealTopCardMenuWithActivePlayers);
addAction(aAlwaysRevealTopCard);
addAction(aAlwaysLookAtTopCard);
addSeparator();
topLibraryMenu = addTearOffMenu(QString());
bottomLibraryMenu = addTearOffMenu(QString());
addSeparator();
addAction(aOpenDeckInDeckEditor);
topLibraryMenu->addAction(aMoveTopToPlay);
topLibraryMenu->addAction(aMoveTopToPlayFaceDown);
topLibraryMenu->addAction(aMoveTopCardToBottom);
topLibraryMenu->addSeparator();
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
topLibraryMenu->addAction(aMoveTopCardsToGraveyardFaceDown);
topLibraryMenu->addAction(aMoveTopCardToExile);
topLibraryMenu->addAction(aMoveTopCardsToExile);
topLibraryMenu->addAction(aMoveTopCardsToExileFaceDown);
topLibraryMenu->addAction(aMoveTopCardsUntil);
topLibraryMenu->addSeparator();
topLibraryMenu->addAction(aShuffleTopCards);
bottomLibraryMenu->addAction(aDrawBottomCard);
bottomLibraryMenu->addAction(aDrawBottomCards);
bottomLibraryMenu->addSeparator();
bottomLibraryMenu->addAction(aMoveBottomToPlay);
bottomLibraryMenu->addAction(aMoveBottomToPlayFaceDown);
bottomLibraryMenu->addAction(aMoveBottomCardToTop);
bottomLibraryMenu->addSeparator();
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyardFaceDown);
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
bottomLibraryMenu->addAction(aMoveBottomCardsToExileFaceDown);
bottomLibraryMenu->addSeparator();
bottomLibraryMenu->addAction(aShuffleBottomCards);
connect(player->getLogic(), &PlayerLogic::resetTopCardMenuActions, this, &LibraryMenu::resetTopCardMenuActions);
connect(player->getLogic(), &PlayerLogic::deckChanged, this, &LibraryMenu::enableOpenInDeckEditorAction);
retranslateUi();
}
void LibraryMenu::enableOpenInDeckEditorAction() const
{
aOpenDeckInDeckEditor->setEnabled(true);
}
void LibraryMenu::resetTopCardMenuActions()
{
aAlwaysRevealTopCard->setChecked(false);
aAlwaysLookAtTopCard->setChecked(false);
}
void LibraryMenu::createDrawActions()
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aDrawCard = new QAction(this);
connect(aDrawCard, &QAction::triggered, playerActions, &PlayerActions::actDrawCard);
aDrawCards = new QAction(this);
connect(aDrawCards, &QAction::triggered, playerActions, &PlayerActions::actRequestDrawCardsDialog);
aUndoDraw = new QAction(this);
connect(aUndoDraw, &QAction::triggered, playerActions, &PlayerActions::actUndoDraw);
aDrawBottomCard = new QAction(this);
connect(aDrawBottomCard, &QAction::triggered, playerActions, &PlayerActions::actDrawBottomCard);
aDrawBottomCards = new QAction(this);
connect(aDrawBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestDrawBottomCardsDialog);
}
}
void LibraryMenu::createShuffleActions()
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aShuffle = new QAction(this);
connect(aShuffle, &QAction::triggered, playerActions, &PlayerActions::actShuffle);
aShuffleTopCards = new QAction(this);
connect(aShuffleTopCards, &QAction::triggered, playerActions, &PlayerActions::actRequestShuffleTopDialog);
aShuffleBottomCards = new QAction(this);
connect(aShuffleBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestShuffleBottomDialog);
}
}
void LibraryMenu::createMoveActions()
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveTopToPlay = new QAction(this);
connect(aMoveTopToPlay, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToPlay);
aMoveTopToPlayFaceDown = new QAction(this);
connect(aMoveTopToPlayFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveTopCardToPlayFaceDown);
aMoveTopCardToGraveyard = new QAction(this);
connect(aMoveTopCardToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToGrave);
aMoveTopCardToExile = new QAction(this);
connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile);
aMoveTopCardsToGraveyard = new QAction(this);
connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave);
aMoveTopCardsToGraveyardFaceDown = new QAction(this);
connect(aMoveTopCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveTopCardsToGraveFaceDown);
aMoveTopCardsToExile = new QAction(this);
connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile);
aMoveTopCardsToExileFaceDown = new QAction(this);
connect(aMoveTopCardsToExileFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveTopCardsToExileFaceDown);
aMoveTopCardsUntil = new QAction(this);
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions,
&PlayerActions::actRequestMoveTopCardsUntilDialog);
aMoveTopCardToBottom = new QAction(this);
connect(aMoveTopCardToBottom, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToBottom);
aMoveBottomToPlay = new QAction(this);
connect(aMoveBottomToPlay, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToPlay);
aMoveBottomToPlayFaceDown = new QAction(this);
connect(aMoveBottomToPlayFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveBottomCardToPlayFaceDown);
aMoveBottomCardToGraveyard = new QAction(this);
connect(aMoveBottomCardToGraveyard, &QAction::triggered, playerActions,
&PlayerActions::actMoveBottomCardToGrave);
aMoveBottomCardToExile = new QAction(this);
connect(aMoveBottomCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToExile);
aMoveBottomCardsToGraveyard = new QAction(this);
connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions,
&PlayerActions::actMoveBottomCardsToGrave);
aMoveBottomCardsToGraveyardFaceDown = new QAction(this);
connect(aMoveBottomCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveBottomCardsToGraveFaceDown);
aMoveBottomCardsToExile = new QAction(this);
connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile);
aMoveBottomCardsToExileFaceDown = new QAction(this);
connect(aMoveBottomCardsToExileFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveBottomCardsToExileFaceDown);
aMoveBottomCardToTop = new QAction(this);
connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop);
}
}
void LibraryMenu::createViewActions()
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aViewLibrary = new QAction(this);
connect(aViewLibrary, &QAction::triggered, playerActions, &PlayerActions::actViewLibrary);
aViewTopCards = new QAction(this);
connect(aViewTopCards, &QAction::triggered, playerActions, &PlayerActions::actRequestViewTopCardsDialog);
aViewBottomCards = new QAction(this);
connect(aViewBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestViewBottomCardsDialog);
aAlwaysRevealTopCard = new QAction(this);
aAlwaysRevealTopCard->setCheckable(true);
connect(aAlwaysRevealTopCard, &QAction::triggered, playerActions, &PlayerActions::actAlwaysRevealTopCard);
aAlwaysLookAtTopCard = new QAction(this);
aAlwaysLookAtTopCard->setCheckable(true);
connect(aAlwaysLookAtTopCard, &QAction::triggered, playerActions, &PlayerActions::actAlwaysLookAtTopCard);
aOpenDeckInDeckEditor = new QAction(this);
aOpenDeckInDeckEditor->setEnabled(false);
connect(aOpenDeckInDeckEditor, &QAction::triggered, playerActions, &PlayerActions::actOpenDeckInDeckEditor);
}
}
void LibraryMenu::retranslateUi()
{
setTitle(tr("&Library"));
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aViewLibrary->setText(tr("&View library"));
aViewTopCards->setText(tr("View &top cards of library..."));
aViewBottomCards->setText(tr("View bottom cards of library..."));
mRevealLibrary->setTitle(tr("Reveal &library to..."));
mLendLibrary->setTitle(tr("Lend library to..."));
mRevealTopCard->setTitle(tr("Reveal &top cards to..."));
topLibraryMenu->setTitle(tr("&Top of library..."));
bottomLibraryMenu->setTitle(tr("&Bottom of library..."));
aAlwaysRevealTopCard->setText(tr("&Always reveal top card"));
aAlwaysLookAtTopCard->setText(tr("&Always look at top card"));
aOpenDeckInDeckEditor->setText(tr("&Open deck in deck editor"));
aDrawCard->setText(tr("&Draw card"));
aDrawCards->setText(tr("D&raw cards..."));
aUndoDraw->setText(tr("&Undo last draw"));
aShuffle->setText(tr("Shuffle"));
aMoveTopToPlay->setText(tr("&Play top card"));
aMoveTopToPlayFaceDown->setText(tr("Play top card &face down"));
aMoveTopCardToBottom->setText(tr("Put top card on &bottom"));
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
aMoveTopCardsToGraveyardFaceDown->setText(tr("Move top cards to graveyard face down..."));
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
aMoveTopCardsToExileFaceDown->setText(tr("Move top cards to exile face down..."));
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
aShuffleTopCards->setText(tr("Shuffle top cards..."));
aDrawBottomCard->setText(tr("&Draw bottom card"));
aDrawBottomCards->setText(tr("D&raw bottom cards..."));
aMoveBottomToPlay->setText(tr("&Play bottom card"));
aMoveBottomToPlayFaceDown->setText(tr("Play bottom card &face down"));
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
aMoveBottomCardsToGraveyardFaceDown->setText(tr("Move bottom cards to graveyard face down..."));
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
aMoveBottomCardsToExileFaceDown->setText(tr("Move bottom cards to exile face down..."));
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
aShuffleBottomCards->setText(tr("Shuffle bottom cards..."));
}
}
void LibraryMenu::populateRevealLibraryMenuWithActivePlayers()
{
mRevealLibrary->clear();
QAction *allPlayers = mRevealLibrary->addAction(tr("&All players"));
allPlayers->setData(-1);
connect(allPlayers, &QAction::triggered, this, &LibraryMenu::onRevealLibraryTriggered);
mRevealLibrary->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealLibrary->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &LibraryMenu::onRevealLibraryTriggered);
}
}
void LibraryMenu::populateLendLibraryMenuWithActivePlayers()
{
mLendLibrary->clear();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mLendLibrary->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &LibraryMenu::onLendLibraryTriggered);
}
}
void LibraryMenu::populateRevealTopCardMenuWithActivePlayers()
{
mRevealTopCard->clear();
QAction *allPlayers = mRevealTopCard->addAction(tr("&All players"));
allPlayers->setData(-1);
connect(allPlayers, &QAction::triggered, this, &LibraryMenu::onRevealTopCardTriggered);
mRevealTopCard->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealTopCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &LibraryMenu::onRevealTopCardTriggered);
}
}
void LibraryMenu::onRevealLibraryTriggered()
{
if (auto *a = qobject_cast<QAction *>(sender())) {
player->getLogic()->getPlayerActions()->actRevealLibrary(a->data().toInt());
}
}
void LibraryMenu::onLendLibraryTriggered()
{
if (auto *a = qobject_cast<QAction *>(sender())) {
player->getLogic()->getPlayerActions()->actLendLibrary(a->data().toInt());
}
}
void LibraryMenu::onRevealTopCardTriggered()
{
QWidget *parent = nullptr;
if (auto *view = player->scene() ? player->scene()->views().value(0) : nullptr) {
parent = view->window();
}
if (auto *a = qobject_cast<QAction *>(sender())) {
int deckSize = player->getLogic()->getDeckZone()->getCards().size();
bool ok = true;
int number = QInputDialog::getInt(parent, tr("Reveal top cards of library"),
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberTopCards, 1,
deckSize, 1, &ok);
if (ok) {
player->getLogic()->getPlayerActions()->actRevealTopCards(a->data().toInt(), number);
defaultNumberTopCards = number;
}
}
}
void LibraryMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aViewLibrary->setShortcuts(shortcuts.getShortcut("Player/aViewLibrary"));
aViewTopCards->setShortcuts(shortcuts.getShortcut("Player/aViewTopCards"));
aViewBottomCards->setShortcuts(shortcuts.getShortcut("Player/aViewBottomCards"));
aDrawCard->setShortcuts(shortcuts.getShortcut("Player/aDrawCard"));
aDrawCards->setShortcuts(shortcuts.getShortcut("Player/aDrawCards"));
aUndoDraw->setShortcuts(shortcuts.getShortcut("Player/aUndoDraw"));
aShuffle->setShortcuts(shortcuts.getShortcut("Player/aShuffle"));
aShuffleTopCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleTopCards"));
aShuffleBottomCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleBottomCards"));
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"));
aMoveTopCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyardFaceDown"));
aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
aMoveTopCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExileFaceDown"));
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"));
aMoveBottomCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGraveFaceDown"));
aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
aMoveBottomCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExileFaceDown"));
aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
}
void LibraryMenu::setShortcutsInactive()
{
aViewLibrary->setShortcut(QKeySequence());
aViewTopCards->setShortcut(QKeySequence());
aViewBottomCards->setShortcut(QKeySequence());
aDrawCard->setShortcut(QKeySequence());
aDrawCards->setShortcut(QKeySequence());
aUndoDraw->setShortcut(QKeySequence());
aShuffle->setShortcut(QKeySequence());
aShuffleTopCards->setShortcut(QKeySequence());
aShuffleBottomCards->setShortcut(QKeySequence());
aAlwaysRevealTopCard->setShortcut(QKeySequence());
aAlwaysLookAtTopCard->setShortcut(QKeySequence());
aMoveTopToPlay->setShortcut(QKeySequence());
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
aMoveTopCardsToGraveyardFaceDown->setShortcut(QKeySequence());
aMoveTopCardToExile->setShortcut(QKeySequence());
aMoveTopCardsToExile->setShortcut(QKeySequence());
aMoveTopCardsToExileFaceDown->setShortcut(QKeySequence());
aMoveTopCardsUntil->setShortcut(QKeySequence());
aDrawBottomCard->setShortcut(QKeySequence());
aDrawBottomCards->setShortcut(QKeySequence());
aMoveBottomToPlay->setShortcut(QKeySequence());
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
aMoveBottomCardsToGraveyardFaceDown->setShortcut(QKeySequence());
aMoveBottomCardToExile->setShortcut(QKeySequence());
aMoveBottomCardsToExile->setShortcut(QKeySequence());
aMoveBottomCardsToExileFaceDown->setShortcut(QKeySequence());
}

View file

@ -0,0 +1,118 @@
/**
* @file library_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_LIBRARY_MENU_H
#define COCKATRICE_LIBRARY_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "abstract_player_component.h"
#include <QAction>
#include <QMenu>
class PlayerGraphicsItem;
class PlayerLogic;
class PlayerActions;
class LibraryMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
public slots:
void enableOpenInDeckEditorAction() const;
void resetTopCardMenuActions();
public:
LibraryMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
void createDrawActions();
void createShuffleActions();
void createMoveActions();
void createViewActions();
void retranslateUi() override;
void populateRevealLibraryMenuWithActivePlayers();
void populateLendLibraryMenuWithActivePlayers();
void populateRevealTopCardMenuWithActivePlayers();
void onRevealLibraryTriggered();
void onLendLibraryTriggered();
void onRevealTopCardTriggered();
void setShortcutsActive() override;
void setShortcutsInactive() override;
[[nodiscard]] bool isAlwaysRevealTopCardChecked() const
{
return aAlwaysRevealTopCard->isChecked();
}
[[nodiscard]] bool isAlwaysLookAtTopCardChecked() const
{
return aAlwaysLookAtTopCard->isChecked();
}
// expose useful actions/menus if PlayerMenu needs them
[[nodiscard]] QMenu *revealLibrary() const
{
return mRevealLibrary;
}
[[nodiscard]] QMenu *lendLibraryMenu() const
{
return mLendLibrary;
}
[[nodiscard]] QMenu *revealTopCardMenu() const
{
return mRevealTopCard;
}
QMenu *topLibraryMenu = nullptr;
QMenu *bottomLibraryMenu = nullptr;
// Expose submenus that PlayerMenu tracks in its lists
QMenu *mRevealLibrary = nullptr;
QMenu *mLendLibrary = nullptr;
QMenu *mRevealTopCard = nullptr;
QAction *aDrawCard = nullptr;
QAction *aDrawCards = nullptr;
QAction *aUndoDraw = nullptr;
QAction *aShuffle = nullptr;
QAction *aViewLibrary = nullptr;
QAction *aViewTopCards = nullptr;
QAction *aViewBottomCards = nullptr;
QAction *aAlwaysRevealTopCard = nullptr;
QAction *aAlwaysLookAtTopCard = nullptr;
QAction *aOpenDeckInDeckEditor = nullptr;
QAction *aMoveTopToPlay = nullptr;
QAction *aMoveTopToPlayFaceDown = nullptr;
QAction *aMoveTopCardToBottom = nullptr;
QAction *aMoveTopCardToGraveyard = nullptr;
QAction *aMoveTopCardToExile = nullptr;
QAction *aMoveTopCardsToGraveyard = nullptr;
QAction *aMoveTopCardsToGraveyardFaceDown = nullptr;
QAction *aMoveTopCardsToExile = nullptr;
QAction *aMoveTopCardsToExileFaceDown = nullptr;
QAction *aMoveTopCardsUntil = nullptr;
QAction *aShuffleTopCards = nullptr;
QAction *aDrawBottomCard = nullptr;
QAction *aDrawBottomCards = nullptr;
QAction *aMoveBottomToPlay = nullptr;
QAction *aMoveBottomToPlayFaceDown = nullptr;
QAction *aMoveBottomCardToTop = nullptr;
QAction *aMoveBottomCardToGraveyard = nullptr;
QAction *aMoveBottomCardToExile = nullptr;
QAction *aMoveBottomCardsToGraveyard = nullptr;
QAction *aMoveBottomCardsToGraveyardFaceDown = nullptr;
QAction *aMoveBottomCardsToExile = nullptr;
QAction *aMoveBottomCardsToExileFaceDown = nullptr;
QAction *aShuffleBottomCards = nullptr;
int defaultNumberTopCards = 1;
private:
PlayerGraphicsItem *player;
};
#endif // COCKATRICE_LIBRARY_MENU_H

View file

@ -0,0 +1,79 @@
#include "move_menu.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../card_menu_action_type.h"
#include "../player_graphics_item.h"
MoveMenu::MoveMenu(PlayerGraphicsItem *player) : QMenu(tr("Move to"))
{
aMoveToTopLibrary = new QAction(this);
aMoveToTopLibrary->setData(cmMoveToTopLibrary);
aMoveToBottomLibrary = new QAction(this);
aMoveToBottomLibrary->setData(cmMoveToBottomLibrary);
aMoveToXfromTopOfLibrary = new QAction(this);
aMoveToTable = new QAction(this);
aMoveToTable->setData(cmMoveToTable);
aMoveToGraveyard = new QAction(this);
aMoveToHand = new QAction(this);
aMoveToHand->setData(cmMoveToHand);
aMoveToGraveyard->setData(cmMoveToGraveyard);
aMoveToExile = new QAction(this);
aMoveToExile->setData(cmMoveToExile);
auto *actions = player->getLogic()->getPlayerActions();
auto invoke = [player](CardMenuActionType type) {
return [type, player]() {
player->getLogic()->getPlayerActions()->cardMenuAction(player->getGameScene()->selectedCards(), type);
};
};
connect(aMoveToTopLibrary, &QAction::triggered, actions, invoke(cmMoveToTopLibrary));
connect(aMoveToBottomLibrary, &QAction::triggered, actions, invoke(cmMoveToBottomLibrary));
connect(aMoveToXfromTopOfLibrary, &QAction::triggered, actions,
&PlayerActions::actRequestMoveCardXCardsFromTopDialog);
connect(aMoveToTable, &QAction::triggered, actions, invoke(cmMoveToTable));
connect(aMoveToHand, &QAction::triggered, actions, invoke(cmMoveToHand));
connect(aMoveToGraveyard, &QAction::triggered, actions, invoke(cmMoveToGraveyard));
connect(aMoveToExile, &QAction::triggered, actions, invoke(cmMoveToExile));
addAction(aMoveToTopLibrary);
addAction(aMoveToXfromTopOfLibrary);
addAction(aMoveToBottomLibrary);
addSeparator();
addAction(aMoveToTable);
addSeparator();
addAction(aMoveToHand);
addSeparator();
addAction(aMoveToGraveyard);
addSeparator();
addAction(aMoveToExile);
setShortcutsActive();
retranslateUi();
}
void MoveMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aMoveToTopLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToTopLibrary"));
aMoveToBottomLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToBottomLibrary"));
aMoveToTable->setShortcuts(shortcuts.getShortcut("Player/aMoveToTable"));
aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand"));
aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard"));
aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile"));
}
void MoveMenu::retranslateUi()
{
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"));
aMoveToTable->setText(tr("T&able"));
aMoveToHand->setText(tr("&Hand"));
aMoveToGraveyard->setText(tr("&Graveyard"));
aMoveToExile->setText(tr("&Exile"));
}

View file

@ -0,0 +1,31 @@
/**
* @file move_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_MOVE_MENU_H
#define COCKATRICE_MOVE_MENU_H
#include <QMenu>
class PlayerGraphicsItem;
class MoveMenu : public QMenu
{
Q_OBJECT
public:
explicit MoveMenu(PlayerGraphicsItem *player);
void setShortcutsActive();
void retranslateUi();
QAction *aMoveToTopLibrary = nullptr;
QAction *aMoveToXfromTopOfLibrary = nullptr;
QAction *aMoveToBottomLibrary = nullptr;
QAction *aMoveToHand = nullptr;
QAction *aMoveToTable = nullptr;
QAction *aMoveToGraveyard = nullptr;
QAction *aMoveToExile = nullptr;
};
#endif // COCKATRICE_MOVE_MENU_H

View file

@ -0,0 +1,140 @@
#include "player_menu.h"
#include "../../../game_graphics/zones/hand_zone.h"
#include "../../../game_graphics/zones/pile_zone.h"
#include "../../../game_graphics/zones/table_zone.h"
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../board/card_item.h"
#include "../player_graphics_item.h"
#include "card_menu.h"
#include "hand_menu.h"
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
PlayerMenu::PlayerMenu(PlayerGraphicsItem *_player) : QObject(_player), player(_player)
{
connect(player->getLogic(), &PlayerLogic::requestCardMenuUpdate, this, &PlayerMenu::updateCardMenu);
connect(this, &PlayerMenu::cardInfoRequested, player, &PlayerGraphicsItem::cardInfoRequested);
playerMenu = new TearOffMenu();
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
handMenu = addManagedMenu<HandMenu>(player, playerMenu);
libraryMenu = addManagedMenu<LibraryMenu>(player, playerMenu);
} else {
handMenu = nullptr;
libraryMenu = nullptr;
}
graveMenu = addManagedMenu<GraveyardMenu>(player, playerMenu);
rfgMenu = addManagedMenu<RfgMenu>(player, playerMenu);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
sideboardMenu = addManagedMenu<SideboardMenu>(player, playerMenu);
customZonesMenu = addManagedMenu<CustomZoneMenu>(player);
playerMenu->addSeparator();
countersMenu = playerMenu->addMenu(QString());
utilityMenu = createManagedComponent<UtilityMenu>(player, playerMenu);
} else {
sideboardMenu = nullptr;
customZonesMenu = nullptr;
countersMenu = nullptr;
utilityMenu = nullptr;
}
if (player->getLogic()->getPlayerInfo()->getLocal()) {
sayMenu = addManagedMenu<SayMenu>(player);
} else {
sayMenu = nullptr;
}
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&PlayerMenu::refreshShortcuts);
refreshShortcuts();
retranslateUi();
}
void PlayerMenu::setMenusForGraphicItems()
{
player->getTableZoneGraphicsItem()->setMenu(playerMenu);
player->getGraveyardZoneGraphicsItem()->setMenu(graveMenu, graveMenu->aViewGraveyard);
player->getRfgZoneGraphicsItem()->setMenu(rfgMenu, rfgMenu->aViewRfg);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
player->getHandZoneGraphicsItem()->setMenu(handMenu);
player->getDeckZoneGraphicsItem()->setMenu(libraryMenu, libraryMenu->aDrawCard);
player->getSideboardZoneGraphicsItem()->setMenu(sideboardMenu);
}
}
QMenu *PlayerMenu::updateCardMenu(const CardItem *card)
{
if (!card) {
emit cardMenuUpdated(nullptr);
return nullptr;
}
// If is spectator (as spectators don't need card menus), return
// only update the menu if the card is actually selected
if ((player->getLogic()->getGame()->getPlayerManager()->isSpectator() &&
!player->getLogic()->getGame()->getPlayerManager()->isJudge()) ||
player->getLogic()->getGame()->getActiveCard() != card) {
return nullptr;
}
CardMenu *menu = new CardMenu(player, card, shortcutsActive);
connect(menu, &CardMenu::cardInfoRequested, this, &PlayerMenu::cardInfoRequested);
emit cardMenuUpdated(menu);
return menu;
}
void PlayerMenu::retranslateUi()
{
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getLogic()->getPlayerInfo()->getName()));
for (auto *component : managedComponents) {
component->retranslateUi();
}
if (countersMenu) {
countersMenu->setTitle(tr("&Counters"));
}
emit retranslateRequested();
}
void PlayerMenu::refreshShortcuts()
{
if (shortcutsActive) {
// Judges get access to every player's menus but only want shortcuts to be set for their own.
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge() &&
!player->getLogic()->getPlayerInfo()->getLocal()) {
setShortcutsInactive();
} else {
setShortcutsActive();
}
} else {
setShortcutsInactive();
}
}
void PlayerMenu::setShortcutsActive()
{
shortcutsActive = true;
for (auto *c : managedComponents) {
c->setShortcutsActive();
}
emit shortcutsActivated();
}
void PlayerMenu::setShortcutsInactive()
{
shortcutsActive = false;
for (auto *c : managedComponents) {
c->setShortcutsInactive();
}
emit shortcutsDeactivated();
}

View file

@ -0,0 +1,117 @@
/**
* @file player_menu.h
* @ingroup GameMenusPlayers
* @brief Orchestrates lifecycle management for all player-bound UI components.
*/
#ifndef COCKATRICE_PLAYER_MENU_H
#define COCKATRICE_PLAYER_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "custom_zone_menu.h"
#include "grave_menu.h"
#include "hand_menu.h"
#include "library_menu.h"
#include "rfg_menu.h"
#include "say_menu.h"
#include "sideboard_menu.h"
#include "utility_menu.h"
#include <QList>
#include <QMenu>
#include <QObject>
class CardItem;
class CardMenu;
class PlayerGraphicsItem;
class PlayerMenu : public QObject
{
Q_OBJECT
signals:
void cardMenuUpdated(CardMenu *cardMenu);
void cardInfoRequested(const CardRef &cardRef);
void shortcutsActivated();
void shortcutsDeactivated();
void retranslateRequested();
public slots:
void setMenusForGraphicItems();
QMenu *updateCardMenu(const CardItem *card);
private slots:
void refreshShortcuts();
public:
explicit PlayerMenu(PlayerGraphicsItem *player);
/** @brief Retranslate all user-visible strings. Called on language change. */
void retranslateUi();
[[nodiscard]] QMenu *getPlayerMenu() const
{
return playerMenu;
}
[[nodiscard]] QMenu *getCountersMenu()
{
return countersMenu;
}
[[nodiscard]] LibraryMenu *getLibraryMenu() const
{
return libraryMenu;
}
[[nodiscard]] UtilityMenu *getUtilityMenu() const
{
return utilityMenu;
}
[[nodiscard]] bool getShortcutsActive() const
{
return shortcutsActive;
}
/** @brief Bind keyboard shortcuts. Called when this player gains focus. */
void setShortcutsActive();
/** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
void setShortcutsInactive();
private:
PlayerGraphicsItem *player;
TearOffMenu *playerMenu;
QMenu *countersMenu;
HandMenu *handMenu;
LibraryMenu *libraryMenu;
SideboardMenu *sideboardMenu;
GraveyardMenu *graveMenu;
RfgMenu *rfgMenu;
UtilityMenu *utilityMenu;
SayMenu *sayMenu;
CustomZoneMenu *customZonesMenu;
/** @brief Drives AbstractPlayerComponent lifecycle delegation. Counters are iterated separately via
* player->getCounters().
*/
QList<AbstractPlayerComponent *> managedComponents;
bool shortcutsActive = false;
/** @brief Creates component, adds it as a submenu of playerMenu, and registers in managedComponents. */
template <typename MenuT, typename... Args> MenuT *addManagedMenu(Args &&...args)
{
auto *menu = new MenuT(std::forward<Args>(args)...);
playerMenu->addMenu(menu);
managedComponents.append(menu);
return menu;
}
/** @brief Creates component and registers in managedComponents, but does NOT add it as a submenu. */
template <typename ComponentT, typename... Args> ComponentT *createManagedComponent(Args &&...args)
{
auto *component = new ComponentT(std::forward<Args>(args)...);
managedComponents.append(component);
return component;
}
};
#endif // COCKATRICE_PLAYER_MENU_H

View file

@ -0,0 +1,89 @@
#include "pt_menu.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
PtMenu::PtMenu(PlayerGraphicsItem *player) : QMenu(tr("Power / toughness"))
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
aIncP = new QAction(this);
connect(aIncP, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actIncP(player->getGameScene()->selectedCards()); });
aDecP = new QAction(this);
connect(aDecP, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actDecP(player->getGameScene()->selectedCards()); });
aIncT = new QAction(this);
connect(aIncT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actIncT(player->getGameScene()->selectedCards()); });
aDecT = new QAction(this);
connect(aDecT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actDecT(player->getGameScene()->selectedCards()); });
aIncPT = new QAction(this);
connect(aIncPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actIncPT(player->getGameScene()->selectedCards()); });
aDecPT = new QAction(this);
connect(aDecPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actDecPT(player->getGameScene()->selectedCards()); });
aFlowP = new QAction(this);
connect(aFlowP, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actFlowP(player->getGameScene()->selectedCards()); });
aFlowT = new QAction(this);
connect(aFlowT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actFlowT(player->getGameScene()->selectedCards()); });
aSetPT = new QAction(this);
connect(aSetPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actRequestSetPTDialog(player->getGameScene()->selectedCards()); });
aResetPT = new QAction(this);
connect(aResetPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actResetPT(player->getGameScene()->selectedCards()); });
addAction(aIncP);
addAction(aDecP);
addAction(aFlowP);
addSeparator();
addAction(aIncT);
addAction(aDecT);
addAction(aFlowT);
addSeparator();
addAction(aIncPT);
addAction(aDecPT);
addSeparator();
addAction(aSetPT);
addAction(aResetPT);
setShortcutsActive();
retranslateUi();
}
void PtMenu::retranslateUi()
{
aIncP->setText(tr("&Increase power"));
aDecP->setText(tr("&Decrease power"));
aIncT->setText(tr("I&ncrease toughness"));
aDecT->setText(tr("D&ecrease toughness"));
aIncPT->setText(tr("In&crease power and toughness"));
aDecPT->setText(tr("Dec&rease power and toughness"));
aFlowP->setText(tr("Increase power and decrease toughness"));
aFlowT->setText(tr("Decrease power and increase toughness"));
aSetPT->setText(tr("Set &power and toughness..."));
aResetPT->setText(tr("Reset p&ower and toughness"));
}
void PtMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aIncP->setShortcuts(shortcuts.getShortcut("Player/aIncP"));
aDecP->setShortcuts(shortcuts.getShortcut("Player/aDecP"));
aIncT->setShortcuts(shortcuts.getShortcut("Player/aIncT"));
aDecT->setShortcuts(shortcuts.getShortcut("Player/aDecT"));
aIncPT->setShortcuts(shortcuts.getShortcut("Player/aIncPT"));
aDecPT->setShortcuts(shortcuts.getShortcut("Player/aDecPT"));
aFlowP->setShortcuts(shortcuts.getShortcut("Player/aFlowP"));
aFlowT->setShortcuts(shortcuts.getShortcut("Player/aFlowT"));
aSetPT->setShortcuts(shortcuts.getShortcut("Player/aSetPT"));
aResetPT->setShortcuts(shortcuts.getShortcut("Player/aResetPT"));
}

View file

@ -0,0 +1,35 @@
/**
* @file pt_menu.h
* @ingroup GameMenusCards
*/
//! \todo Document this file.
#ifndef COCKATRICE_PT_MENU_H
#define COCKATRICE_PT_MENU_H
#include <QMenu>
class PlayerGraphicsItem;
class PtMenu : public QMenu
{
Q_OBJECT
public:
explicit PtMenu(PlayerGraphicsItem *player);
void retranslateUi();
void setShortcutsActive();
QAction *aIncP = nullptr;
QAction *aDecP = nullptr;
QAction *aFlowP = nullptr;
QAction *aIncT = nullptr;
QAction *aDecT = nullptr;
QAction *aFlowT = nullptr;
QAction *aIncPT = nullptr;
QAction *aDecPT = nullptr;
QAction *aSetPT = nullptr;
QAction *aResetPT = nullptr;
};
#endif // COCKATRICE_PT_MENU_H

View file

@ -0,0 +1,72 @@
#include "rfg_menu.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
#include <libcockatrice/utility/zone_names.h>
RfgMenu::RfgMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createMoveActions();
createViewActions();
addAction(aViewRfg);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
addSeparator();
moveRfgMenu = addTearOffMenu(QString());
moveRfgMenu->addAction(aMoveRfgToTopLibrary);
moveRfgMenu->addAction(aMoveRfgToBottomLibrary);
moveRfgMenu->addSeparator();
moveRfgMenu->addAction(aMoveRfgToHand);
moveRfgMenu->addSeparator();
moveRfgMenu->addAction(aMoveRfgToGrave);
}
retranslateUi();
}
void RfgMenu::createMoveActions()
{
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
auto rfg = player->getLogic()->getRfgZone();
aMoveRfgToTopLibrary = new QAction(this);
aMoveRfgToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
aMoveRfgToBottomLibrary = new QAction(this);
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
aMoveRfgToHand = new QAction(this);
aMoveRfgToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
aMoveRfgToGrave = new QAction(this);
aMoveRfgToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
connect(aMoveRfgToHand, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
connect(aMoveRfgToGrave, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
}
}
void RfgMenu::createViewActions()
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
aViewRfg = new QAction(this);
connect(aViewRfg, &QAction::triggered, playerActions, &PlayerActions::actViewRfg);
}
void RfgMenu::retranslateUi()
{
setTitle(tr("&Exile"));
aViewRfg->setText(tr("&View exile"));
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
moveRfgMenu->setTitle(tr("&Move exile to..."));
aMoveRfgToTopLibrary->setText(tr("&Top of library"));
aMoveRfgToBottomLibrary->setText(tr("&Bottom of library"));
aMoveRfgToHand->setText(tr("&Hand"));
aMoveRfgToGrave->setText(tr("&Graveyard"));
}
}

View file

@ -0,0 +1,44 @@
/**
* @file rfg_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_RFG_MENU_H
#define COCKATRICE_RFG_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "abstract_player_component.h"
#include <QAction>
#include <QMenu>
class PlayerGraphicsItem;
class RfgMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit RfgMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
void createMoveActions();
void createViewActions();
void retranslateUi() override;
void setShortcutsActive() override
{
}
void setShortcutsInactive() override
{
}
QMenu *moveRfgMenu = nullptr;
QAction *aViewRfg = nullptr;
QAction *aMoveRfgToTopLibrary = nullptr;
QAction *aMoveRfgToBottomLibrary = nullptr;
QAction *aMoveRfgToHand = nullptr;
QAction *aMoveRfgToGrave = nullptr;
private:
PlayerGraphicsItem *player;
};
#endif // COCKATRICE_RFG_MENU_H

View file

@ -0,0 +1,55 @@
#include "say_menu.h"
#include "../../../client/settings/cache_settings.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
SayMenu::SayMenu(PlayerGraphicsItem *_player) : player(_player)
{
connect(&SettingsCache::instance().messages(), &MessageSettings::messageMacrosChanged, this, &SayMenu::initSayMenu);
initSayMenu();
retranslateUi();
}
void SayMenu::retranslateUi()
{
setTitle(tr("S&ay"));
}
void SayMenu::setShortcutsActive()
{
shortcutsActive = true;
const auto menuActions = actions();
for (int i = 0; i < menuActions.size() && i < 10; ++i) {
menuActions[i]->setShortcut(QKeySequence("Ctrl+" + QString::number((i + 1) % 10)));
}
}
void SayMenu::setShortcutsInactive()
{
shortcutsActive = false;
for (auto *action : actions()) {
action->setShortcut(QKeySequence());
}
}
void SayMenu::initSayMenu()
{
clear();
int count = SettingsCache::instance().messages().getCount();
setEnabled(count > 0);
for (int i = 0; i < count; ++i) {
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
connect(newAction, &QAction::triggered, player->getLogic()->getPlayerActions(), &PlayerActions::actSayMessage);
addAction(newAction);
}
if (shortcutsActive) {
setShortcutsActive();
}
}

View file

@ -0,0 +1,33 @@
/**
* @file say_menu.h
* @ingroup GameMenusPlayers
*/
//! \todo Document this file.
#ifndef COCKATRICE_SAY_MENU_H
#define COCKATRICE_SAY_MENU_H
#include "abstract_player_component.h"
#include <QMenu>
class PlayerGraphicsItem;
class SayMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit SayMenu(PlayerGraphicsItem *player);
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
private slots:
void initSayMenu();
private:
PlayerGraphicsItem *player;
bool shortcutsActive = false;
};
#endif // COCKATRICE_SAY_MENU_H

View file

@ -0,0 +1,36 @@
#include "sideboard_menu.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
SideboardMenu::SideboardMenu(PlayerGraphicsItem *player, QMenu *playerMenu) : QMenu(playerMenu)
{
aViewSideboard = new QAction(this);
connect(aViewSideboard, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actViewSideboard);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
addAction(aViewSideboard);
}
retranslateUi();
}
void SideboardMenu::retranslateUi()
{
setTitle(tr("&Sideboard"));
aViewSideboard->setText(tr("&View sideboard"));
}
void SideboardMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aViewSideboard->setShortcuts(shortcuts.getShortcut("Player/aViewSideboard"));
}
void SideboardMenu::setShortcutsInactive()
{
aViewSideboard->setShortcut(QKeySequence());
}

View file

@ -0,0 +1,31 @@
/**
* @file sideboard_menu.h
* @ingroup GameMenusZones
*/
//! \todo Document this file.
#ifndef COCKATRICE_SIDEBOARD_MENU_H
#define COCKATRICE_SIDEBOARD_MENU_H
#include "abstract_player_component.h"
#include <QMenu>
class PlayerGraphicsItem;
class SideboardMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit SideboardMenu(PlayerGraphicsItem *player, QMenu *playerMenu);
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
private:
PlayerGraphicsItem *player;
QAction *aViewSideboard;
};
#endif // COCKATRICE_SIDEBOARD_MENU_H

View file

@ -0,0 +1,147 @@
#include "utility_menu.h"
#include "../../../interface/deck_loader/deck_loader.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player_graphics_item.h"
#include "player_menu.h"
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/inner_deck_list_node.h>
UtilityMenu::UtilityMenu(PlayerGraphicsItem *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
{
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
connect(playerActions, &PlayerActions::requestEnableAndSetCreateAnotherTokenAction, this,
&UtilityMenu::setAndEnableCreateAnotherTokenAction);
connect(playerActions, &PlayerActions::requestSetLastToken, this, &UtilityMenu::setLastToken);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aUntapAll = new QAction(this);
connect(aUntapAll, &QAction::triggered, playerActions, &PlayerActions::actUntapAll);
aRollDie = new QAction(this);
connect(aRollDie, &QAction::triggered, playerActions, &PlayerActions::actRequestRollDieDialog);
aFlipCoin = new QAction(this);
connect(aFlipCoin, &QAction::triggered, playerActions, &PlayerActions::actFlipCoin);
aCreateToken = new QAction(this);
connect(aCreateToken, &QAction::triggered, playerActions, [this]() {
player->getLogic()->getPlayerActions()->actRequestCreateTokenDialog(getPredefinedTokens());
});
aCreateAnotherToken = new QAction(this);
connect(aCreateAnotherToken, &QAction::triggered, playerActions, &PlayerActions::actCreateAnotherToken);
aCreateAnotherToken->setEnabled(false);
aIncrementAllCardCounters = new QAction(this);
connect(aIncrementAllCardCounters, &QAction::triggered, playerActions, [this]() {
player->getLogic()->getPlayerActions()->actIncrementAllCardCounters(
player->getGameScene()->selectedCards());
});
createPredefinedTokenMenu = new QMenu(QString());
createPredefinedTokenMenu->setEnabled(false);
connect(player->getLogic(), &PlayerLogic::deckChanged, this, &UtilityMenu::populatePredefinedTokensMenu);
playerMenu->addAction(aIncrementAllCardCounters);
playerMenu->addSeparator();
playerMenu->addAction(aUntapAll);
playerMenu->addSeparator();
playerMenu->addAction(aRollDie);
playerMenu->addAction(aFlipCoin);
playerMenu->addSeparator();
playerMenu->addAction(aCreateToken);
playerMenu->addAction(aCreateAnotherToken);
playerMenu->addMenu(createPredefinedTokenMenu);
playerMenu->addSeparator();
} else {
aCreateToken = nullptr;
aCreateAnotherToken = nullptr;
createPredefinedTokenMenu = nullptr;
aIncrementAllCardCounters = nullptr;
aUntapAll = nullptr;
aRollDie = nullptr;
aFlipCoin = nullptr;
}
retranslateUi();
}
void UtilityMenu::populatePredefinedTokensMenu()
{
clear();
setEnabled(false);
predefinedTokens.clear();
const DeckList &deckList = player->getLogic()->getDeck();
if (deckList.isEmpty()) {
return;
}
auto tokenCardNodes = deckList.getCardNodes({DECK_ZONE_TOKENS});
if (!tokenCardNodes.isEmpty()) {
setEnabled(true);
for (int i = 0; i < tokenCardNodes.size(); ++i) {
const QString tokenName = tokenCardNodes[i]->getName();
predefinedTokens.append(tokenName);
QAction *a = addAction(tokenName);
if (i < 10) {
a->setShortcut(QKeySequence("Alt+" + QString::number((i + 1) % 10)));
}
connect(a, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actCreatePredefinedToken);
}
}
}
void UtilityMenu::setLastToken(CardInfoPtr lastToken)
{
if (!createAnotherTokenActionExists()) {
return;
}
player->getLogic()->getPlayerActions()->setLastTokenInfo(lastToken);
}
void UtilityMenu::retranslateUi()
{
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aIncrementAllCardCounters->setText(tr("Increment all card counters"));
aUntapAll->setText(tr("&Untap all permanents"));
aRollDie->setText(tr("R&oll die..."));
aFlipCoin->setText(tr("Flip coin"));
aCreateToken->setText(tr("&Create token..."));
aCreateAnotherToken->setText(tr("C&reate another token"));
createPredefinedTokenMenu->setTitle(tr("Cr&eate predefined token"));
}
}
void UtilityMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aIncrementAllCardCounters->setShortcuts(shortcuts.getShortcut("Player/aIncrementAllCardCounters"));
aUntapAll->setShortcuts(shortcuts.getShortcut("Player/aUntapAll"));
aRollDie->setShortcuts(shortcuts.getShortcut("Player/aRollDie"));
aFlipCoin->setShortcuts(shortcuts.getShortcut("Player/aFlipCoin"));
aCreateToken->setShortcuts(shortcuts.getShortcut("Player/aCreateToken"));
aCreateAnotherToken->setShortcuts(shortcuts.getShortcut("Player/aCreateAnotherToken"));
}
}
void UtilityMenu::setShortcutsInactive()
{
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aUntapAll->setShortcut(QKeySequence());
aRollDie->setShortcut(QKeySequence());
aFlipCoin->setShortcut(QKeySequence());
aCreateToken->setShortcut(QKeySequence());
aCreateAnotherToken->setShortcut(QKeySequence());
aIncrementAllCardCounters->setShortcut(QKeySequence());
}
}

View file

@ -0,0 +1,56 @@
/**
* @file utility_menu.h
* @ingroup GameMenusPlayers
*/
//! \todo Document this file.
#ifndef COCKATRICE_UTILITY_MENU_H
#define COCKATRICE_UTILITY_MENU_H
#include "abstract_player_component.h"
#include <QMenu>
#include <libcockatrice/card/card_info.h>
class PlayerGraphicsItem;
class UtilityMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public slots:
void populatePredefinedTokensMenu();
void setLastToken(CardInfoPtr lastToken);
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
public:
explicit UtilityMenu(PlayerGraphicsItem *player, QMenu *playerMenu);
[[nodiscard]] bool createAnotherTokenActionExists() const
{
return aCreateAnotherToken != nullptr;
}
void setAndEnableCreateAnotherTokenAction(QString text)
{
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(text));
aCreateAnotherToken->setEnabled(true);
}
QStringList getPredefinedTokens() const
{
return predefinedTokens;
}
private:
PlayerGraphicsItem *player;
QStringList predefinedTokens;
QMenu *createPredefinedTokenMenu;
QAction *aIncrementAllCardCounters;
QAction *aUntapAll, *aRollDie, *aFlipCoin;
QAction *aCreateToken, *aCreateAnotherToken;
};
#endif // COCKATRICE_UTILITY_MENU_H