mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-03-21 17:55:21 -05:00
1553 lines
58 KiB
C++
1553 lines
58 KiB
C++
#include "tab_game.h"
|
|
|
|
#include "../../../client/settings/cache_settings.h"
|
|
#include "../game/board/arrow_item.h"
|
|
#include "../game/board/card_item.h"
|
|
#include "../game/deckview/deck_view_container.h"
|
|
#include "../game/deckview/tabbed_deck_view_container.h"
|
|
#include "../game/game.h"
|
|
#include "../game/game_scene.h"
|
|
#include "../game/game_view.h"
|
|
#include "../game/log/message_log_widget.h"
|
|
#include "../game/phases_toolbar.h"
|
|
#include "../game/player/player.h"
|
|
#include "../game/player/player_list_widget.h"
|
|
#include "../game/replay.h"
|
|
#include "../interface/card_picture_loader/card_picture_loader.h"
|
|
#include "../interface/widgets/cards/card_info_frame_widget.h"
|
|
#include "../interface/widgets/dialogs/dlg_create_game.h"
|
|
#include "../interface/widgets/server/user/user_list_manager.h"
|
|
#include "../interface/widgets/utility/line_edit_completer.h"
|
|
#include "../interface/window_main.h"
|
|
#include "../main.h"
|
|
#include "../utility/visibility_change_listener.h"
|
|
#include "libcockatrice/utility/qt_utils.h"
|
|
#include "tab_supervisor.h"
|
|
|
|
#include <QAction>
|
|
#include <QCompleter>
|
|
#include <QDebug>
|
|
#include <QDockWidget>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
#include <QStackedWidget>
|
|
#include <QTimer>
|
|
#include <QWidget>
|
|
#include <libcockatrice/card/database/card_database.h>
|
|
#include <libcockatrice/card/database/card_database_manager.h>
|
|
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
|
#include <libcockatrice/protocol/pb/event_game_joined.pb.h>
|
|
#include <libcockatrice/protocol/pb/game_replay.pb.h>
|
|
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
|
|
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
|
#include <libcockatrice/utility/trice_limits.h>
|
|
|
|
TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
|
: Tab(_tabSupervisor), sayLabel(nullptr), sayEdit(nullptr)
|
|
{
|
|
// THIS CTOR IS USED ON REPLAY
|
|
game = new Replay(this, _replay);
|
|
|
|
createCardInfoDock(true);
|
|
createPlayerListDock(true);
|
|
createMessageDock(true);
|
|
createPlayAreaWidget(true);
|
|
createDeckViewContainerWidget(true);
|
|
createReplayDock(_replay);
|
|
|
|
addDockWidget(Qt::RightDockWidgetArea, cardInfoDock);
|
|
addDockWidget(Qt::RightDockWidgetArea, playerListDock);
|
|
addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock);
|
|
addDockWidget(Qt::BottomDockWidgetArea, replayDock);
|
|
|
|
mainWidget = new QStackedWidget(this);
|
|
mainWidget->addWidget(deckViewContainerWidget);
|
|
mainWidget->addWidget(gamePlayAreaWidget);
|
|
setCentralWidget(mainWidget);
|
|
|
|
createReplayMenuItems();
|
|
createViewMenuItems();
|
|
|
|
connectToGameState();
|
|
connectToPlayerManager();
|
|
connectToGameEventHandler();
|
|
connectPlayerListToGameEventHandler();
|
|
connectMessageLogToGameEventHandler();
|
|
|
|
retranslateUi();
|
|
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
|
&TabGame::refreshShortcuts);
|
|
refreshShortcuts();
|
|
messageLog->logReplayStarted(game->getGameMetaInfo()->gameId());
|
|
|
|
QTimer::singleShot(0, this, &TabGame::loadLayout);
|
|
}
|
|
|
|
TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
|
QList<AbstractClient *> &_clients,
|
|
const Event_GameJoined &event,
|
|
const QMap<int, QString> &_roomGameTypes)
|
|
: Tab(_tabSupervisor), userListProxy(_tabSupervisor->getUserListManager())
|
|
{
|
|
// THIS CTOR IS USED ON GAMES
|
|
game = new Game(this, _clients, event, _roomGameTypes);
|
|
|
|
createCardInfoDock();
|
|
createPlayerListDock();
|
|
createMessageDock();
|
|
createPlayAreaWidget();
|
|
createDeckViewContainerWidget();
|
|
replayDock = nullptr;
|
|
|
|
addDockWidget(Qt::RightDockWidgetArea, cardInfoDock);
|
|
addDockWidget(Qt::RightDockWidgetArea, playerListDock);
|
|
addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock);
|
|
|
|
mainWidget = new QStackedWidget(this);
|
|
mainWidget->addWidget(deckViewContainerWidget);
|
|
mainWidget->addWidget(gamePlayAreaWidget);
|
|
mainWidget->setContentsMargins(0, 0, 0, 0);
|
|
setCentralWidget(mainWidget);
|
|
|
|
createMenuItems();
|
|
createViewMenuItems();
|
|
|
|
connectToGameState();
|
|
connectToPlayerManager();
|
|
connectToGameEventHandler();
|
|
connectPlayerListToGameEventHandler();
|
|
connectMessageLogToGameEventHandler();
|
|
|
|
retranslateUi();
|
|
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
|
&TabGame::refreshShortcuts);
|
|
refreshShortcuts();
|
|
|
|
// append game to rooms game list for others to see
|
|
for (int i = game->getGameMetaInfo()->gameTypesSize() - 1; i >= 0; i--)
|
|
gameTypes.append(game->getGameMetaInfo()->findRoomGameType(i));
|
|
|
|
QTimer::singleShot(0, this, &TabGame::loadLayout);
|
|
|
|
auto mainWindow = QtUtils::findParentOfType<QMainWindow>(this);
|
|
|
|
if (mainWindow) {
|
|
tutorialController = new TutorialController(mainWindow);
|
|
} else {
|
|
tutorialController = new TutorialController(this);
|
|
}
|
|
|
|
TutorialSequence lobbySequence;
|
|
|
|
TutorialStep introStep(deckViewContainerWidget, tr("Let's try this out."));
|
|
lobbySequence.addStep(introStep);
|
|
|
|
tutorialController->addSequence(lobbySequence);
|
|
}
|
|
|
|
void TabGame::showEvent(QShowEvent *event)
|
|
{
|
|
QWidget::showEvent(event);
|
|
if (!tutorialStarted) {
|
|
tutorialStarted = true;
|
|
// Start on next event loop iteration so everything is fully painted
|
|
QTimer::singleShot(3, tutorialController, [this] { tutorialController->start(); });
|
|
}
|
|
}
|
|
|
|
void TabGame::finishTutorialInitialization()
|
|
{
|
|
if (tutorialInitialized) {
|
|
return;
|
|
} else {
|
|
tutorialInitialized = true;
|
|
}
|
|
|
|
auto deckViewSequence = deckViewContainers.first()->generateTutorialSequence();
|
|
|
|
tutorialController->addSequence(deckViewSequence);
|
|
|
|
TutorialSequence deckSelectSequence;
|
|
deckSelectSequence.name = tr("Deck selection and readying up");
|
|
|
|
TutorialStep loadDeckStep;
|
|
loadDeckStep.targetWidget = deckViewContainers.first();
|
|
loadDeckStep.text = tr("Let's load a deck now.");
|
|
loadDeckStep.allowClickThrough = true;
|
|
loadDeckStep.requiresInteraction = true;
|
|
loadDeckStep.autoAdvanceOnValid = true;
|
|
loadDeckStep.validationTiming = ValidationTiming::OnSignal;
|
|
loadDeckStep.signalSource = game->getGameEventHandler();
|
|
loadDeckStep.signalName = SIGNAL(logDeckSelect(Player *, QString, int));
|
|
loadDeckStep.validator = [] { return true; };
|
|
|
|
deckSelectSequence.addStep(loadDeckStep);
|
|
|
|
TutorialStep readyUpStep;
|
|
readyUpStep.targetWidget = deckViewContainers.first();
|
|
readyUpStep.text = tr("Let's ready up now.");
|
|
readyUpStep.allowClickThrough = true;
|
|
readyUpStep.requiresInteraction = true;
|
|
readyUpStep.autoAdvanceOnValid = true;
|
|
readyUpStep.validationTiming = ValidationTiming::OnSignal;
|
|
readyUpStep.signalSource = this;
|
|
readyUpStep.signalName = SIGNAL(localPlayerReadyStateChanged(bool));
|
|
readyUpStep.validator = [] { return true; };
|
|
|
|
deckSelectSequence.addStep(readyUpStep);
|
|
|
|
tutorialController->addSequence(deckSelectSequence);
|
|
|
|
TutorialSequence gamePlaySequence;
|
|
gamePlaySequence.name = tr("Gameplay");
|
|
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("Welcome to your first game! It's just a singleplayer game for now to teach you the controls.")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("Welcome to your first game! It's just a singleplayer game for now to teach you the controls.")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("Unfortunately, due to the way the game tab works, we can't highlight any specific gameplay elements but "
|
|
"we're confident you'll be able to spot all the relevant elements on-screen.")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("Let's go over them quickly, left-to-right.\n\nThe phase toolbar\nThe player area\nThe battlefield")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("First up, is the phase toolbar. This toolbar shows the current phase of the turn. You can advance it by "
|
|
"pressing\n\n"
|
|
"- Tab (simply advances the phase)\n"
|
|
"- Ctrl+Space (advances the phase and performes any associated actions)\n"
|
|
"- Clicking directly on the phase you want to change to.\n\n"
|
|
"You can also pass the turn here, although, you should note that most players prefer you simply leave your "
|
|
"turn on the end step and allow them to 'take' the turn from you by pressing 'Next turn' themselves.")});
|
|
gamePlaySequence.addStep({gamePlayAreaWidget, tr("Next up, is your player area.\n\nHere you can find:\n\n- Your "
|
|
"avatar\n- Your life-counter\n- Various counters you can use to "
|
|
"track temporary resources (i.e. mana)\n- Your "
|
|
"library,\n- Your hand\n- Your graveyard\n- Your exile")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("To the right of your player area, and taking up most of the screen, is your battlefield.\nThe relevant "
|
|
"zones here are, left-to-right, top-to-bottom:\n- The Stack\n- The Battlefield (Currently highlighted "
|
|
"because it is your turn)\n- Your Hand")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget,
|
|
tr("Before we dive any deeper into the actual controls, remember this:\n\nYou can perform almost "
|
|
"EVERY action by right-clicking the relevant object or zone!")});
|
|
gamePlaySequence.addStep(
|
|
{gamePlayAreaWidget, tr("However, there are shortcuts and conveniences to speed up your games and make your "
|
|
"life easier.\n\nLet's run through a typical game start now to get you up to speed.")});
|
|
|
|
TutorialStep lifeCounterStep;
|
|
lifeCounterStep.targetWidget = gamePlayAreaWidget;
|
|
lifeCounterStep.text =
|
|
tr("To control your life total, you can:\n\nSet it directly using Ctrl+L\nLeft-click the "
|
|
"number on your avatar to increment it.\nRight-click the number on your avatar to decrement "
|
|
"it.\nMiddle-click the number on your avatar to open up an interval menu up to +-10.");
|
|
lifeCounterStep.requiresInteraction = true;
|
|
lifeCounterStep.allowClickThrough = true;
|
|
lifeCounterStep.autoAdvanceOnValid = true;
|
|
lifeCounterStep.validationTiming = ValidationTiming::OnSignal;
|
|
lifeCounterStep.signalSource = game->getPlayerManager()
|
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
|
->getPlayerEventHandler();
|
|
lifeCounterStep.signalName = SIGNAL(logSetCounter(Player *, QString, int, int));
|
|
lifeCounterStep.validator = [this] {
|
|
auto counters =
|
|
game->getPlayerManager()->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())->getCounters();
|
|
for (auto counter : counters) {
|
|
if (counter->getName() == "life") {
|
|
return counter->getValue() == 10;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
lifeCounterStep.validationHint = tr("Set your life total to 10 using any of these methods.");
|
|
|
|
gamePlaySequence.addStep(lifeCounterStep);
|
|
|
|
TutorialStep diceRollStep;
|
|
diceRollStep.targetWidget = gamePlayAreaWidget;
|
|
diceRollStep.text = tr("Fantastic! Let's roll a dice now. Many players use this to determine the initial turn "
|
|
"order.\nYou can right-click the battlefield and choose the menu "
|
|
"option or use the shortcut (Default Ctrl+I).");
|
|
diceRollStep.requiresInteraction = true;
|
|
diceRollStep.allowClickThrough = true;
|
|
diceRollStep.autoAdvanceOnValid = true;
|
|
diceRollStep.validationTiming = ValidationTiming::OnSignal;
|
|
diceRollStep.signalSource = game->getPlayerManager()
|
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
|
->getPlayerEventHandler();
|
|
diceRollStep.signalName = SIGNAL(logRollDie(Player *, int, const QList<uint> &));
|
|
diceRollStep.validator = [this] { return true; };
|
|
diceRollStep.validationHint = tr("Roll a dice using any of these methods.");
|
|
|
|
gamePlaySequence.addStep(diceRollStep);
|
|
|
|
TutorialStep mulliganStep;
|
|
mulliganStep.targetWidget = gamePlayAreaWidget;
|
|
mulliganStep.text =
|
|
tr("Alright, with that out of the way, we can get down to business:\n\nDrawing cards!\n\nTo draw your initial "
|
|
"hand:\n\n- Right-click your hand in the player area and select 'Take mulligan'\n-n Right-click your hand "
|
|
"zone on the battlefield and select 'Take mulligan'\n- Use the default shortcut (Ctrl+M)");
|
|
mulliganStep.requiresInteraction = true;
|
|
mulliganStep.allowClickThrough = true;
|
|
mulliganStep.autoAdvanceOnValid = true;
|
|
mulliganStep.validationTiming = ValidationTiming::OnSignal;
|
|
mulliganStep.signalSource = game->getPlayerManager()
|
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
|
->getPlayerEventHandler();
|
|
mulliganStep.signalName = SIGNAL(logDrawCards(Player *, int, bool));
|
|
mulliganStep.validator = [this] {
|
|
return game->getPlayerManager()
|
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
|
->getHandZone()
|
|
->getCards()
|
|
.size() == 7;
|
|
};
|
|
mulliganStep.validationHint = tr("Mulligan to 7 cards using any of these methods.");
|
|
|
|
gamePlaySequence.addStep(mulliganStep);
|
|
|
|
gamePlaySequence.addStep({gamePlayAreaWidget, tr("")});
|
|
gamePlaySequence.addStep({gamePlayAreaWidget, tr("")});
|
|
|
|
gamePlaySequence.addStep({gamePlayAreaWidget, tr("")});
|
|
tutorialController->addSequence(gamePlaySequence);
|
|
}
|
|
|
|
void TabGame::connectToGameState()
|
|
{
|
|
connect(game->getGameState(), &GameState::gameStarted, this, &TabGame::startGame);
|
|
connect(game->getGameState(), &GameState::gameStopped, this, &TabGame::stopGame);
|
|
connect(game->getGameState(), &GameState::activePhaseChanged, this, &TabGame::setActivePhase);
|
|
connect(game->getGameState(), &GameState::activePlayerChanged, this, &TabGame::setActivePlayer);
|
|
}
|
|
|
|
void TabGame::connectToPlayerManager()
|
|
{
|
|
connect(game->getPlayerManager(), &PlayerManager::playerAdded, this, &TabGame::addPlayer);
|
|
connect(game->getPlayerManager(), &PlayerManager::playerRemoved, this, &TabGame::processPlayerLeave);
|
|
// update menu text when player concedes so that "concede" gets updated to "unconcede"
|
|
connect(game->getPlayerManager(), &PlayerManager::playerConceded, this, &TabGame::retranslateUi);
|
|
connect(game->getPlayerManager(), &PlayerManager::playerUnconceded, this, &TabGame::retranslateUi);
|
|
}
|
|
|
|
void TabGame::connectToGameEventHandler()
|
|
{
|
|
connect(this, &TabGame::gameLeft, game->getGameEventHandler(), &GameEventHandler::handleGameLeft);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::emitUserEvent, this, &TabGame::emitUserEvent);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::gameStopped, this, &TabGame::stopGame);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::gameClosed, this, &TabGame::closeGame);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::localPlayerReadyStateChanged, this,
|
|
&TabGame::processLocalPlayerReadyStateChanged);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::localPlayerSideboardLocked, this,
|
|
&TabGame::processLocalPlayerSideboardLocked);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::localPlayerDeckSelected, this,
|
|
&TabGame::processLocalPlayerDeckSelect);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::remotePlayerDeckSelected, this,
|
|
&TabGame::processRemotePlayerDeckSelect);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::remotePlayersDecksSelected, this,
|
|
&TabGame::processMultipleRemotePlayerDeckSelect);
|
|
}
|
|
|
|
void TabGame::connectMessageLogToGameEventHandler()
|
|
{
|
|
connect(game->getGameEventHandler(), &GameEventHandler::gameFlooded, messageLog, &MessageLogWidget::logGameFlooded);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::containerProcessingStarted, messageLog,
|
|
&MessageLogWidget::containerProcessingStarted);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::containerProcessingDone, messageLog,
|
|
&MessageLogWidget::containerProcessingDone);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::setContextJudgeName, messageLog,
|
|
&MessageLogWidget::setContextJudgeName);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logSpectatorSay, messageLog,
|
|
&MessageLogWidget::logSpectatorSay);
|
|
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logJoinPlayer, messageLog, &MessageLogWidget::logJoin);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logJoinSpectator, messageLog,
|
|
&MessageLogWidget::logJoinSpectator);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logLeave, messageLog, &MessageLogWidget::logLeave);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logKicked, messageLog, &MessageLogWidget::logKicked);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logConnectionStateChanged, messageLog,
|
|
&MessageLogWidget::logConnectionStateChanged);
|
|
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logDeckSelect, messageLog,
|
|
&MessageLogWidget::logDeckSelect);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logSideboardLockSet, messageLog,
|
|
&MessageLogWidget::logSetSideboardLock);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logReadyStart, messageLog,
|
|
&MessageLogWidget::logReadyStart);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logNotReadyStart, messageLog,
|
|
&MessageLogWidget::logNotReadyStart);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logGameStart, messageLog, &MessageLogWidget::logGameStart);
|
|
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logActivePlayer, messageLog,
|
|
&MessageLogWidget::logSetActivePlayer);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logActivePhaseChanged, messageLog,
|
|
&MessageLogWidget::logSetActivePhase);
|
|
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logTurnReversed, messageLog,
|
|
&MessageLogWidget::logReverseTurn);
|
|
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logConcede, messageLog, &MessageLogWidget::logConcede);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logUnconcede, messageLog, &MessageLogWidget::logUnconcede);
|
|
|
|
connect(game->getGameEventHandler(), &GameEventHandler::logGameClosed, messageLog,
|
|
&MessageLogWidget::logGameClosed);
|
|
}
|
|
|
|
void TabGame::connectPlayerListToGameEventHandler()
|
|
{
|
|
connect(game->getGameEventHandler(), &GameEventHandler::playerJoined, playerListWidget,
|
|
&PlayerListWidget::addPlayer);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::playerLeft, playerListWidget,
|
|
&PlayerListWidget::removePlayer);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::spectatorJoined, playerListWidget,
|
|
&PlayerListWidget::addPlayer);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::spectatorLeft, playerListWidget,
|
|
&PlayerListWidget::removePlayer);
|
|
connect(game->getGameEventHandler(), &GameEventHandler::playerPropertiesChanged, playerListWidget,
|
|
&PlayerListWidget::updatePlayerProperties);
|
|
}
|
|
|
|
void TabGame::addMentionTag(const QString &value)
|
|
{
|
|
sayEdit->insert(value + " ");
|
|
sayEdit->setFocus();
|
|
}
|
|
|
|
void TabGame::linkCardToChat(const QString &cardName)
|
|
{
|
|
sayEdit->insert("[[" + cardName + "]] ");
|
|
sayEdit->setFocus();
|
|
}
|
|
|
|
void TabGame::resetChatAndPhase()
|
|
{
|
|
// reset chat log
|
|
messageLog->clearChat();
|
|
|
|
// reset phase markers
|
|
game->getGameState()->setCurrentPhase(-1);
|
|
}
|
|
|
|
void TabGame::emitUserEvent()
|
|
{
|
|
bool globalEvent =
|
|
!game->getPlayerManager()->isSpectator() || SettingsCache::instance().getSpectatorNotificationsEnabled();
|
|
emit userEvent(globalEvent);
|
|
updatePlayerListDockTitle();
|
|
}
|
|
|
|
TabGame::~TabGame()
|
|
{
|
|
if (replayManager) {
|
|
delete replayManager->replay;
|
|
}
|
|
}
|
|
|
|
void TabGame::updatePlayerListDockTitle()
|
|
{
|
|
QString type = replayDock ? tr("Replay") : tr("Game");
|
|
QString tabText = " | " + type + " #" + QString::number(game->getGameMetaInfo()->gameId());
|
|
QString userCountInfo =
|
|
QString(" %1/%2").arg(game->getPlayerManager()->getPlayerCount()).arg(game->getGameMetaInfo()->maxPlayers());
|
|
playerListDock->setWindowTitle(tr("Player List") + userCountInfo +
|
|
(playerListDock->isWindow() ? tabText : QString()));
|
|
}
|
|
|
|
void TabGame::retranslateUi()
|
|
{
|
|
QString type = replayDock ? tr("Replay") : tr("Game");
|
|
QString tabText = " | " + type + " #" + QString::number(game->getGameMetaInfo()->gameId());
|
|
|
|
updatePlayerListDockTitle();
|
|
cardInfoDock->setWindowTitle(tr("Card Info") + (cardInfoDock->isWindow() ? tabText : QString()));
|
|
messageLayoutDock->setWindowTitle(tr("Messages") + (messageLayoutDock->isWindow() ? tabText : QString()));
|
|
if (replayDock)
|
|
replayDock->setWindowTitle(tr("Replay Timeline") + (replayDock->isWindow() ? tabText : QString()));
|
|
|
|
if (phasesMenu) {
|
|
for (int i = 0; i < phaseActions.size(); ++i)
|
|
phaseActions[i]->setText(phasesToolbar->getLongPhaseName(i));
|
|
phasesMenu->setTitle(tr("&Phases"));
|
|
}
|
|
|
|
gameMenu->setTitle(tr("&Game"));
|
|
if (aNextPhase) {
|
|
aNextPhase->setText(tr("Next &phase"));
|
|
}
|
|
if (aNextPhaseAction) {
|
|
aNextPhaseAction->setText(tr("Next phase with &action"));
|
|
}
|
|
if (aNextTurn) {
|
|
aNextTurn->setText(tr("Next &turn"));
|
|
}
|
|
if (aReverseTurn) {
|
|
aReverseTurn->setText(tr("Reverse turn order"));
|
|
}
|
|
if (aRemoveLocalArrows) {
|
|
aRemoveLocalArrows->setText(tr("&Remove all local arrows"));
|
|
}
|
|
if (aRotateViewCW) {
|
|
aRotateViewCW->setText(tr("Rotate View Cl&ockwise"));
|
|
}
|
|
if (aRotateViewCCW) {
|
|
aRotateViewCCW->setText(tr("Rotate View Co&unterclockwise"));
|
|
}
|
|
if (aGameInfo)
|
|
aGameInfo->setText(tr("Game &information"));
|
|
if (aConcede) {
|
|
if (game->getPlayerManager()->isMainPlayerConceded()) {
|
|
aConcede->setText(tr("Un&concede"));
|
|
} else {
|
|
aConcede->setText(tr("&Concede"));
|
|
}
|
|
}
|
|
if (aLeaveGame) {
|
|
if (replayDock) {
|
|
aLeaveGame->setText(tr("C&lose replay"));
|
|
} else {
|
|
aLeaveGame->setText(tr("&Leave game"));
|
|
}
|
|
}
|
|
if (aFocusChat) {
|
|
aFocusChat->setText(tr("&Focus Chat"));
|
|
}
|
|
if (sayLabel) {
|
|
sayLabel->setText(tr("&Say:"));
|
|
}
|
|
|
|
if (aCardMenu) {
|
|
aCardMenu->setText(tr("Selected cards"));
|
|
}
|
|
|
|
viewMenu->setTitle(tr("&View"));
|
|
|
|
dockToActions[cardInfoDock].menu->setTitle(tr("Card Info"));
|
|
dockToActions[messageLayoutDock].menu->setTitle(tr("Messages"));
|
|
dockToActions[playerListDock].menu->setTitle(tr("Player List"));
|
|
|
|
if (replayDock) {
|
|
dockToActions[replayDock].menu->setTitle(tr("Replay Timeline"));
|
|
}
|
|
|
|
for (auto &actions : dockToActions.values()) {
|
|
actions.aVisible->setText(tr("Visible"));
|
|
actions.aFloating->setText(tr("Floating"));
|
|
}
|
|
|
|
aResetLayout->setText(tr("Reset layout"));
|
|
|
|
cardInfoFrameWidget->retranslateUi();
|
|
|
|
QMapIterator<int, Player *> i(game->getPlayerManager()->getPlayers());
|
|
|
|
while (i.hasNext())
|
|
i.next().value()->getGraphicsItem()->retranslateUi();
|
|
QMapIterator<int, TabbedDeckViewContainer *> j(deckViewContainers);
|
|
while (j.hasNext())
|
|
j.next().value()->playerDeckView->retranslateUi();
|
|
|
|
scene->retranslateUi();
|
|
}
|
|
|
|
void TabGame::refreshShortcuts()
|
|
{
|
|
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
|
for (int i = 0; i < phaseActions.size(); ++i) {
|
|
QAction *temp = phaseActions.at(i);
|
|
switch (i) {
|
|
case 0:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase0"));
|
|
break;
|
|
case 1:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase1"));
|
|
break;
|
|
case 2:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase2"));
|
|
break;
|
|
case 3:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase3"));
|
|
break;
|
|
case 4:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase4"));
|
|
break;
|
|
case 5:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase5"));
|
|
break;
|
|
case 6:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase6"));
|
|
break;
|
|
case 7:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase7"));
|
|
break;
|
|
case 8:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase8"));
|
|
break;
|
|
case 9:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase9"));
|
|
break;
|
|
case 10:
|
|
temp->setShortcuts(shortcuts.getShortcut("Player/phase10"));
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
|
|
if (aNextPhase) {
|
|
aNextPhase->setShortcuts(shortcuts.getShortcut("Player/aNextPhase"));
|
|
}
|
|
if (aNextPhaseAction) {
|
|
aNextPhaseAction->setShortcuts(shortcuts.getShortcut("Player/aNextPhaseAction"));
|
|
}
|
|
if (aNextTurn) {
|
|
aNextTurn->setShortcuts(shortcuts.getShortcut("Player/aNextTurn"));
|
|
}
|
|
if (aReverseTurn) {
|
|
aReverseTurn->setShortcuts(shortcuts.getShortcut("Player/aReverseTurn"));
|
|
}
|
|
if (aRemoveLocalArrows) {
|
|
aRemoveLocalArrows->setShortcuts(shortcuts.getShortcut("Player/aRemoveLocalArrows"));
|
|
}
|
|
if (aRotateViewCW) {
|
|
aRotateViewCW->setShortcuts(shortcuts.getShortcut("Player/aRotateViewCW"));
|
|
}
|
|
if (aRotateViewCCW) {
|
|
aRotateViewCCW->setShortcuts(shortcuts.getShortcut("Player/aRotateViewCCW"));
|
|
}
|
|
if (aConcede) {
|
|
aConcede->setShortcuts(shortcuts.getShortcut("Player/aConcede"));
|
|
}
|
|
if (aLeaveGame) {
|
|
aLeaveGame->setShortcuts(shortcuts.getShortcut("Player/aLeaveGame"));
|
|
}
|
|
if (aResetLayout) {
|
|
aResetLayout->setShortcuts(shortcuts.getShortcut("Player/aResetLayout"));
|
|
}
|
|
if (aFocusChat) {
|
|
aFocusChat->setShortcuts(shortcuts.getShortcut("Player/aFocusChat"));
|
|
}
|
|
}
|
|
|
|
bool TabGame::closeRequest()
|
|
{
|
|
if (!leaveGame()) {
|
|
return false;
|
|
}
|
|
|
|
return close();
|
|
}
|
|
|
|
void TabGame::closeEvent(QCloseEvent *event)
|
|
{
|
|
emit gameClosing(this);
|
|
event->accept();
|
|
}
|
|
|
|
void TabGame::updateTimeElapsedLabel(const QString newTime)
|
|
{
|
|
timeElapsedLabel->setText(newTime);
|
|
}
|
|
|
|
void TabGame::adminLockChanged(bool lock)
|
|
{
|
|
bool v = !(game->getPlayerManager()->isSpectator() && !game->getGameMetaInfo()->spectatorsCanChat() && lock);
|
|
sayLabel->setVisible(v);
|
|
sayEdit->setVisible(v);
|
|
}
|
|
|
|
void TabGame::actGameInfo()
|
|
{
|
|
DlgCreateGame dlg(game->getGameMetaInfo()->proto(), game->getGameMetaInfo()->getRoomGameTypes(), this);
|
|
dlg.exec();
|
|
}
|
|
|
|
void TabGame::actConcede()
|
|
{
|
|
Player *player = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
|
|
if (player == nullptr)
|
|
return;
|
|
if (!player->getConceded()) {
|
|
if (QMessageBox::question(this, tr("Concede"), tr("Are you sure you want to concede this game?"),
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
|
|
return;
|
|
emit game->getPlayerManager()->activeLocalPlayerConceded();
|
|
player->setConceded(true);
|
|
} else {
|
|
if (QMessageBox::question(this, tr("Unconcede"),
|
|
tr("You have already conceded. Do you want to return to this game?"),
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
|
|
return;
|
|
emit game->getPlayerManager()->activeLocalPlayerUnconceded();
|
|
player->setConceded(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Confirms the leave game and sends the leave game command, if applicable.
|
|
*
|
|
* @return True if the leave game is confirmed
|
|
*/
|
|
bool TabGame::leaveGame()
|
|
{
|
|
if (!game->getGameState()->isGameClosed()) {
|
|
if (!game->getPlayerManager()->isSpectator()) {
|
|
tabSupervisor->setCurrentWidget(this);
|
|
if (QMessageBox::question(this, tr("Leave game"), tr("Are you sure you want to leave this game?"),
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
|
|
return false;
|
|
}
|
|
|
|
if (!replayDock)
|
|
emit gameLeft();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void TabGame::actSay()
|
|
{
|
|
if (completer->popup()->isVisible())
|
|
return;
|
|
|
|
if (sayEdit->text().startsWith("/card ")) {
|
|
cardInfoFrameWidget->setCard(sayEdit->text().mid(6));
|
|
sayEdit->clear();
|
|
return;
|
|
}
|
|
|
|
if (!sayEdit->text().isEmpty()) {
|
|
emit chatMessageSent(sayEdit->text());
|
|
sayEdit->clear();
|
|
}
|
|
}
|
|
|
|
void TabGame::addPlayerToAutoCompleteList(QString playerName)
|
|
{
|
|
if (sayEdit && !autocompleteUserList.contains(playerName)) {
|
|
autocompleteUserList << playerName;
|
|
sayEdit->setCompletionList(autocompleteUserList);
|
|
}
|
|
}
|
|
|
|
void TabGame::removePlayerFromAutoCompleteList(QString playerName)
|
|
{
|
|
if (sayEdit && autocompleteUserList.removeOne(playerName)) {
|
|
sayEdit->setCompletionList(autocompleteUserList);
|
|
}
|
|
}
|
|
|
|
void TabGame::removeSpectator(int spectatorId, ServerInfo_User spectator)
|
|
{
|
|
Q_UNUSED(spectator);
|
|
QString playerName = "@" + game->getPlayerManager()->getSpectatorName(spectatorId);
|
|
removePlayerFromAutoCompleteList(playerName);
|
|
}
|
|
|
|
void TabGame::actPhaseAction()
|
|
{
|
|
int phase = phaseActions.indexOf(static_cast<QAction *>(sender()));
|
|
emit phaseChanged(phase);
|
|
}
|
|
|
|
void TabGame::actNextPhase()
|
|
{
|
|
int phase = game->getGameState()->getCurrentPhase();
|
|
if (++phase >= phasesToolbar->phaseCount())
|
|
phase = 0;
|
|
|
|
emit phaseChanged(phase);
|
|
}
|
|
|
|
void TabGame::actNextPhaseAction()
|
|
{
|
|
int phase = game->getGameState()->getCurrentPhase() + 1;
|
|
if (phase >= phasesToolbar->phaseCount()) {
|
|
phase = 0;
|
|
}
|
|
|
|
if (phase == 0) {
|
|
emit turnAdvanced();
|
|
} else {
|
|
emit phaseChanged(phase);
|
|
}
|
|
|
|
phasesToolbar->triggerPhaseAction(phase);
|
|
}
|
|
|
|
void TabGame::actRemoveLocalArrows()
|
|
{
|
|
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
|
|
while (playerIterator.hasNext()) {
|
|
Player *player = playerIterator.next().value();
|
|
if (!player->getPlayerInfo()->getLocal())
|
|
continue;
|
|
QMapIterator<int, ArrowItem *> arrowIterator(player->getArrows());
|
|
while (arrowIterator.hasNext()) {
|
|
ArrowItem *a = arrowIterator.next().value();
|
|
emit arrowDeletionRequested(a->getId());
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabGame::actRotateViewCW()
|
|
{
|
|
scene->adjustPlayerRotation(-1);
|
|
}
|
|
|
|
void TabGame::actRotateViewCCW()
|
|
{
|
|
scene->adjustPlayerRotation(1);
|
|
}
|
|
|
|
void TabGame::actCompleterChanged()
|
|
{
|
|
SettingsCache::instance().getChatMentionCompleter() ? completer->setCompletionRole(2)
|
|
: completer->setCompletionRole(1);
|
|
}
|
|
|
|
void TabGame::notifyPlayerJoin(QString playerName)
|
|
{
|
|
if (trayIcon) {
|
|
QString gameId(QString::number(game->getGameMetaInfo()->gameId()));
|
|
trayIcon->showMessage(tr("A player has joined game #%1").arg(gameId),
|
|
tr("%1 has joined the game").arg(playerName));
|
|
}
|
|
}
|
|
|
|
void TabGame::notifyPlayerKicked()
|
|
{
|
|
tabSupervisor->setCurrentIndex(tabSupervisor->indexOf(this));
|
|
QMessageBox msgBox(this);
|
|
msgBox.setWindowTitle(getTabText());
|
|
msgBox.setText(tr("You have been kicked out of the game."));
|
|
msgBox.setIcon(QMessageBox::Information);
|
|
msgBox.exec();
|
|
}
|
|
|
|
Player *TabGame::addPlayer(Player *newPlayer)
|
|
{
|
|
QString newPlayerName = "@" + newPlayer->getPlayerInfo()->getName();
|
|
addPlayerToAutoCompleteList(newPlayerName);
|
|
|
|
scene->addPlayer(newPlayer);
|
|
|
|
connect(newPlayer, &Player::newCardAdded, this, &TabGame::newCardAdded);
|
|
connect(newPlayer->getPlayerMenu(), &PlayerMenu::cardMenuUpdated, this, &TabGame::setCardMenu);
|
|
|
|
messageLog->connectToPlayerEventHandler(newPlayer->getPlayerEventHandler());
|
|
|
|
if (game->getGameState()->getIsLocalGame() ||
|
|
(game->getPlayerManager()->isLocalPlayer(newPlayer->getPlayerInfo()->getId()) &&
|
|
!game->getPlayerManager()->isSpectator())) {
|
|
if (game->getGameState()->getIsLocalGame()) {
|
|
newPlayer->getPlayerInfo()->setLocal(true);
|
|
}
|
|
addLocalPlayer(newPlayer, newPlayer->getPlayerInfo()->getId());
|
|
}
|
|
|
|
gameMenu->insertMenu(playersSeparator, newPlayer->getPlayerMenu()->getPlayerMenu());
|
|
|
|
createZoneForPlayer(newPlayer, newPlayer->getPlayerInfo()->getId());
|
|
|
|
return newPlayer;
|
|
}
|
|
|
|
void TabGame::addLocalPlayer(Player *newPlayer, int playerId)
|
|
{
|
|
if (game->getGameState()->getClients().size() == 1) {
|
|
newPlayer->getPlayerMenu()->setShortcutsActive();
|
|
}
|
|
|
|
auto *deckView = new TabbedDeckViewContainer(playerId, this);
|
|
connect(deckView->playerDeckView, &DeckViewContainer::newCardAdded, this, &TabGame::newCardAdded);
|
|
deckViewContainers.insert(playerId, deckView);
|
|
deckViewContainerLayout->addWidget(deckView);
|
|
|
|
// auto load deck for player if that debug setting is enabled
|
|
QString deckPath = SettingsCache::instance().debug().getDeckPathForPlayer(newPlayer->getPlayerInfo()->getName());
|
|
if (!deckPath.isEmpty()) {
|
|
QTimer::singleShot(0, this, [deckView, deckPath] {
|
|
deckView->playerDeckView->loadDeckFromFile(deckPath);
|
|
deckView->playerDeckView->readyAndUpdate();
|
|
});
|
|
}
|
|
|
|
finishTutorialInitialization();
|
|
}
|
|
|
|
void TabGame::processPlayerLeave(Player *leavingPlayer)
|
|
{
|
|
QString playerName = "@" + leavingPlayer->getPlayerInfo()->getName();
|
|
removePlayerFromAutoCompleteList(playerName);
|
|
|
|
scene->removePlayer(leavingPlayer);
|
|
|
|
// When we inserted the playerMenu into the gameMenu earlier, Qt wrapped the playerMenu into a QAction*, which lives
|
|
// independently and does not get cleaned up when the source menu gets destroyed. We have to manually clean here.
|
|
if (leavingPlayer->getPlayerMenu()) {
|
|
QMenu *menu = leavingPlayer->getPlayerMenu()->getPlayerMenu();
|
|
if (menu) {
|
|
// Find and remove the QAction pointing to this menu
|
|
QList<QAction *> actions = gameMenu->actions();
|
|
for (QAction *act : actions) {
|
|
if (act->menu() == menu) {
|
|
gameMenu->removeAction(act);
|
|
delete act; // deletes the QAction wrapper around the submenu
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabGame::processRemotePlayerDeckSelect(QString deckList, int playerId, QString playerName)
|
|
{
|
|
DeckList loader;
|
|
loader.loadFromString_Native(deckList);
|
|
QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
i.value()->addOpponentDeckView(loader, playerId, playerName);
|
|
}
|
|
}
|
|
|
|
void TabGame::processMultipleRemotePlayerDeckSelect(QVector<QPair<int, QPair<QString, QString>>> playerIdDeckMap)
|
|
{
|
|
for (const auto &entry : playerIdDeckMap) {
|
|
int playerId = entry.first;
|
|
QString playerName = entry.second.first;
|
|
QString deckList = entry.second.second;
|
|
|
|
processRemotePlayerDeckSelect(deckList, playerId, playerName);
|
|
}
|
|
}
|
|
|
|
void TabGame::processLocalPlayerDeckSelect(Player *localPlayer, int playerId, ServerInfo_Player playerInfo)
|
|
{
|
|
loadDeckForLocalPlayer(localPlayer, playerId, playerInfo);
|
|
processLocalPlayerReady(playerId, playerInfo);
|
|
}
|
|
|
|
void TabGame::loadDeckForLocalPlayer(Player *localPlayer, int playerId, ServerInfo_Player playerInfo)
|
|
{
|
|
TabbedDeckViewContainer *deckViewContainer = deckViewContainers.value(playerId);
|
|
if (playerInfo.has_deck_list()) {
|
|
DeckList deckList = DeckList(QString::fromStdString(playerInfo.deck_list()));
|
|
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(deckList.getCardRefList()));
|
|
deckViewContainer->playerDeckView->setDeck(deckList);
|
|
localPlayer->setDeck(deckList);
|
|
|
|
emit localPlayerDeckSelected();
|
|
}
|
|
}
|
|
|
|
void TabGame::processLocalPlayerReady(int playerId, ServerInfo_Player playerInfo)
|
|
{
|
|
processLocalPlayerReadyStateChanged(playerId, playerInfo.properties().ready_start());
|
|
processLocalPlayerSideboardLocked(playerId, playerInfo.properties().sideboard_locked());
|
|
}
|
|
|
|
void TabGame::processLocalPlayerSideboardLocked(int playerId, bool sideboardLocked)
|
|
{
|
|
deckViewContainers.value(playerId)->playerDeckView->setSideboardLocked(sideboardLocked);
|
|
}
|
|
|
|
void TabGame::processLocalPlayerReadyStateChanged(int playerId, bool ready)
|
|
{
|
|
deckViewContainers.value(playerId)->playerDeckView->setReadyStart(ready);
|
|
emit localPlayerReadyStateChanged(ready);
|
|
}
|
|
|
|
void TabGame::createZoneForPlayer(Player *newPlayer, int playerId)
|
|
{
|
|
if (!game->getPlayerManager()->getSpectators().contains(playerId)) {
|
|
|
|
// Loop for each player, the idea is to have one assigned zone for each non-spectator player
|
|
for (int i = 1; i <= game->getPlayerManager()->getPlayerCount(); ++i) {
|
|
bool aPlayerHasThisZone = false;
|
|
for (auto &player : game->getPlayerManager()->getPlayers()) {
|
|
if (player->getZoneId() == i) {
|
|
aPlayerHasThisZone = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!aPlayerHasThisZone) {
|
|
newPlayer->setZoneId(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabGame::startGame(bool _resuming)
|
|
{
|
|
game->getGameState()->setCurrentPhase(-1);
|
|
|
|
QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
i.value()->playerDeckView->setReadyStart(false);
|
|
i.value()->playerDeckView->setVisualDeckStorageExists(false);
|
|
i.value()->hide();
|
|
}
|
|
|
|
mainWidget->setCurrentWidget(gamePlayAreaWidget);
|
|
|
|
if (!_resuming) {
|
|
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
|
|
while (playerIterator.hasNext())
|
|
playerIterator.next().value()->setGameStarted();
|
|
}
|
|
|
|
playerListWidget->setGameStarted(true, game->getGameState()->isResuming());
|
|
game->getGameMetaInfo()->setStarted(true);
|
|
static_cast<GameScene *>(gameView->scene())->rearrange();
|
|
|
|
if (aConcede != nullptr) {
|
|
aConcede->setText(tr("&Concede"));
|
|
aConcede->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void TabGame::stopGame()
|
|
{
|
|
QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
i.value()->show();
|
|
}
|
|
|
|
mainWidget->setCurrentWidget(deckViewContainerWidget);
|
|
|
|
playerListWidget->setActivePlayer(-1);
|
|
playerListWidget->setGameStarted(false, false);
|
|
|
|
scene->clearViews();
|
|
|
|
if (aConcede != nullptr) {
|
|
aConcede->setText(tr("&Concede"));
|
|
aConcede->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void TabGame::closeGame()
|
|
{
|
|
gameMenu->clear();
|
|
gameMenu->addAction(aLeaveGame);
|
|
}
|
|
|
|
Player *TabGame::setActivePlayer(int id)
|
|
{
|
|
Player *player = game->getPlayerManager()->getPlayer(id);
|
|
if (!player)
|
|
return nullptr;
|
|
|
|
playerListWidget->setActivePlayer(id);
|
|
QMapIterator<int, Player *> i(game->getPlayerManager()->getPlayers());
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
if (i.value() == player) {
|
|
i.value()->setActive(true);
|
|
if (game->getGameState()->getClients().size() > 1) {
|
|
i.value()->getPlayerMenu()->setShortcutsActive();
|
|
}
|
|
} else {
|
|
i.value()->setActive(false);
|
|
if (game->getGameState()->getClients().size() > 1) {
|
|
i.value()->getPlayerMenu()->setShortcutsInactive();
|
|
}
|
|
}
|
|
}
|
|
game->getGameState()->setCurrentPhase(-1);
|
|
emitUserEvent();
|
|
return player;
|
|
}
|
|
|
|
void TabGame::setActivePhase(int phase)
|
|
{
|
|
phasesToolbar->setActivePhase(phase);
|
|
}
|
|
|
|
void TabGame::newCardAdded(AbstractCardItem *card)
|
|
{
|
|
connect(card, &AbstractCardItem::hovered, cardInfoFrameWidget,
|
|
qOverload<AbstractCardItem *>(&CardInfoFrameWidget::setCard));
|
|
connect(card, &AbstractCardItem::showCardInfoPopup, this, &TabGame::showCardInfoPopup);
|
|
connect(card, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
|
|
connect(card, &AbstractCardItem::cardShiftClicked, this, &TabGame::linkCardToChat);
|
|
}
|
|
|
|
QString TabGame::getTabText() const
|
|
{
|
|
QString gameTypeInfo;
|
|
if (!gameTypes.empty()) {
|
|
gameTypeInfo = gameTypes.at(0);
|
|
if (gameTypes.size() > 1)
|
|
gameTypeInfo.append("...");
|
|
}
|
|
|
|
QString gameDesc(game->getGameMetaInfo()->description());
|
|
QString gameId(QString::number(game->getGameMetaInfo()->gameId()));
|
|
|
|
QString tabText;
|
|
if (replayDock)
|
|
tabText.append(tr("Replay") + " ");
|
|
if (!gameTypeInfo.isEmpty())
|
|
tabText.append(gameTypeInfo + " ");
|
|
if (!gameDesc.isEmpty()) {
|
|
if (gameDesc.length() >= 15)
|
|
tabText.append("| " + gameDesc.left(15) + "... ");
|
|
else
|
|
tabText.append("| " + gameDesc + " ");
|
|
}
|
|
if (!tabText.isEmpty())
|
|
tabText.append("| ");
|
|
tabText.append("#" + gameId);
|
|
|
|
return tabText;
|
|
}
|
|
|
|
/**
|
|
* @param menu The menu to set. Pass in nullptr to set the menu to empty.
|
|
*/
|
|
void TabGame::setCardMenu(QMenu *menu)
|
|
{
|
|
if (!aCardMenu) {
|
|
return;
|
|
}
|
|
|
|
if (menu) {
|
|
aCardMenu->setMenu(menu);
|
|
} else {
|
|
aCardMenu->setMenu(new QMenu);
|
|
}
|
|
}
|
|
|
|
void TabGame::createMenuItems()
|
|
{
|
|
aNextPhase = new QAction(this);
|
|
connect(aNextPhase, &QAction::triggered, this, &TabGame::actNextPhase);
|
|
connect(this, &TabGame::phaseChanged, game->getGameEventHandler(), &GameEventHandler::handleActivePhaseChanged);
|
|
aNextPhaseAction = new QAction(this);
|
|
connect(aNextPhaseAction, &QAction::triggered, this, &TabGame::actNextPhaseAction);
|
|
connect(this, &TabGame::turnAdvanced, game->getGameEventHandler(), &GameEventHandler::handleNextTurn);
|
|
aNextTurn = new QAction(this);
|
|
connect(aNextTurn, &QAction::triggered, game->getGameEventHandler(), &GameEventHandler::handleNextTurn);
|
|
aReverseTurn = new QAction(this);
|
|
connect(aReverseTurn, &QAction::triggered, game->getGameEventHandler(), &GameEventHandler::handleReverseTurn);
|
|
aRemoveLocalArrows = new QAction(this);
|
|
connect(aRemoveLocalArrows, &QAction::triggered, this, &TabGame::actRemoveLocalArrows);
|
|
connect(this, &TabGame::arrowDeletionRequested, game->getGameEventHandler(),
|
|
&GameEventHandler::handleArrowDeletion);
|
|
aRotateViewCW = new QAction(this);
|
|
connect(aRotateViewCW, &QAction::triggered, this, &TabGame::actRotateViewCW);
|
|
aRotateViewCCW = new QAction(this);
|
|
connect(aRotateViewCCW, &QAction::triggered, this, &TabGame::actRotateViewCCW);
|
|
aGameInfo = new QAction(this);
|
|
connect(aGameInfo, &QAction::triggered, this, &TabGame::actGameInfo);
|
|
aConcede = new QAction(this);
|
|
connect(aConcede, &QAction::triggered, this, &TabGame::actConcede);
|
|
if (!game->getGameMetaInfo()->started()) {
|
|
aConcede->setEnabled(false);
|
|
}
|
|
connect(game->getPlayerManager(), &PlayerManager::activeLocalPlayerConceded, game->getGameEventHandler(),
|
|
&GameEventHandler::handleActiveLocalPlayerConceded);
|
|
connect(game->getPlayerManager(), &PlayerManager::activeLocalPlayerUnconceded, game->getGameEventHandler(),
|
|
&GameEventHandler::handleActiveLocalPlayerUnconceded);
|
|
aLeaveGame = new QAction(this);
|
|
connect(aLeaveGame, &QAction::triggered, this, &TabGame::closeRequest);
|
|
aFocusChat = new QAction(this);
|
|
connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus));
|
|
|
|
phasesMenu = new TearOffMenu(this);
|
|
|
|
for (int i = 0; i < phasesToolbar->phaseCount(); ++i) {
|
|
auto *temp = new QAction(QString(), this);
|
|
connect(temp, &QAction::triggered, this, &TabGame::actPhaseAction);
|
|
phasesMenu->addAction(temp);
|
|
phaseActions.append(temp);
|
|
}
|
|
|
|
phasesMenu->addSeparator();
|
|
phasesMenu->addAction(aNextPhase);
|
|
phasesMenu->addAction(aNextPhaseAction);
|
|
|
|
gameMenu = new QMenu(this);
|
|
playersSeparator = gameMenu->addSeparator();
|
|
gameMenu->addMenu(phasesMenu);
|
|
gameMenu->addAction(aNextTurn);
|
|
gameMenu->addAction(aReverseTurn);
|
|
gameMenu->addSeparator();
|
|
gameMenu->addAction(aRemoveLocalArrows);
|
|
gameMenu->addAction(aRotateViewCW);
|
|
gameMenu->addAction(aRotateViewCCW);
|
|
gameMenu->addSeparator();
|
|
gameMenu->addAction(aGameInfo);
|
|
gameMenu->addAction(aConcede);
|
|
gameMenu->addAction(aFocusChat);
|
|
gameMenu->addAction(aLeaveGame);
|
|
|
|
gameMenu->addSeparator();
|
|
|
|
aCardMenu = gameMenu->addMenu(new QMenu(this));
|
|
|
|
addTabMenu(gameMenu);
|
|
}
|
|
|
|
void TabGame::createReplayMenuItems()
|
|
{
|
|
aNextPhase = nullptr;
|
|
aNextPhaseAction = nullptr;
|
|
aNextTurn = nullptr;
|
|
aReverseTurn = nullptr;
|
|
aRemoveLocalArrows = nullptr;
|
|
aRotateViewCW = nullptr;
|
|
aRotateViewCCW = nullptr;
|
|
aResetLayout = nullptr;
|
|
aGameInfo = nullptr;
|
|
aConcede = nullptr;
|
|
aFocusChat = nullptr;
|
|
aLeaveGame = new QAction(this);
|
|
connect(aLeaveGame, &QAction::triggered, this, &TabGame::closeRequest);
|
|
|
|
phasesMenu = nullptr;
|
|
gameMenu = new QMenu(this);
|
|
gameMenu->addAction(aLeaveGame);
|
|
|
|
aCardMenu = nullptr;
|
|
|
|
addTabMenu(gameMenu);
|
|
}
|
|
|
|
void TabGame::createViewMenuItems()
|
|
{
|
|
viewMenu = new QMenu(this);
|
|
|
|
registerDockWidget(viewMenu, cardInfoDock);
|
|
registerDockWidget(viewMenu, messageLayoutDock);
|
|
registerDockWidget(viewMenu, playerListDock);
|
|
|
|
if (replayDock) {
|
|
registerDockWidget(viewMenu, replayDock);
|
|
}
|
|
|
|
viewMenu->addSeparator();
|
|
|
|
aResetLayout = viewMenu->addAction(QString());
|
|
connect(aResetLayout, &QAction::triggered, this, &TabGame::actResetLayout);
|
|
viewMenu->addAction(aResetLayout);
|
|
|
|
addTabMenu(viewMenu);
|
|
}
|
|
|
|
void TabGame::registerDockWidget(QMenu *_viewMenu, QDockWidget *widget)
|
|
{
|
|
QMenu *menu = _viewMenu->addMenu(QString());
|
|
|
|
QAction *aVisible = menu->addAction(QString());
|
|
aVisible->setCheckable(true);
|
|
|
|
QAction *aFloating = menu->addAction(QString());
|
|
aFloating->setCheckable(true);
|
|
aFloating->setEnabled(false);
|
|
|
|
// user interaction
|
|
connect(aVisible, &QAction::triggered, widget, [widget](bool checked) { widget->setVisible(checked); });
|
|
connect(aFloating, &QAction::triggered, this, [widget](bool checked) { widget->setFloating(checked); });
|
|
|
|
// sync aFloating's enabled state with aVisible's checked state
|
|
connect(aVisible, &QAction::toggled, aFloating, [aFloating](bool checked) { aFloating->setEnabled(checked); });
|
|
|
|
// sync aFloating with dockWidget's floating state
|
|
connect(widget, &QDockWidget::topLevelChanged, aFloating,
|
|
[aFloating](bool topLevel) { aFloating->setChecked(topLevel); });
|
|
|
|
// sync aVisible with dockWidget's visible state
|
|
auto filter = new VisibilityChangeListener(widget);
|
|
connect(filter, &VisibilityChangeListener::visibilityChanged, aVisible,
|
|
[aVisible](bool visible) { aVisible->setChecked(visible); });
|
|
|
|
dockToActions.insert(widget, {menu, aVisible, aFloating});
|
|
}
|
|
|
|
void TabGame::loadLayout()
|
|
{
|
|
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
|
if (replayDock) {
|
|
restoreGeometry(layouts.getReplayPlayAreaGeometry());
|
|
restoreState(layouts.getReplayPlayAreaLayoutState());
|
|
|
|
cardInfoDock->setMinimumSize(layouts.getReplayCardInfoSize());
|
|
cardInfoDock->setMaximumSize(layouts.getReplayCardInfoSize());
|
|
messageLayoutDock->setMinimumSize(layouts.getReplayMessageLayoutSize());
|
|
messageLayoutDock->setMaximumSize(layouts.getReplayMessageLayoutSize());
|
|
playerListDock->setMinimumSize(layouts.getReplayPlayerListSize());
|
|
playerListDock->setMaximumSize(layouts.getReplayPlayerListSize());
|
|
replayDock->setMinimumSize(layouts.getReplayReplaySize());
|
|
replayDock->setMaximumSize(layouts.getReplayReplaySize());
|
|
} else {
|
|
restoreGeometry(layouts.getGamePlayAreaGeometry());
|
|
restoreState(layouts.getGamePlayAreaLayoutState());
|
|
|
|
cardInfoDock->setMinimumSize(layouts.getGameCardInfoSize());
|
|
cardInfoDock->setMaximumSize(layouts.getGameCardInfoSize());
|
|
messageLayoutDock->setMinimumSize(layouts.getGameMessageLayoutSize());
|
|
messageLayoutDock->setMaximumSize(layouts.getGameMessageLayoutSize());
|
|
playerListDock->setMinimumSize(layouts.getGamePlayerListSize());
|
|
playerListDock->setMaximumSize(layouts.getGamePlayerListSize());
|
|
}
|
|
|
|
QTimer::singleShot(100, this, &TabGame::freeDocksSize);
|
|
}
|
|
|
|
void TabGame::freeDocksSize()
|
|
{
|
|
cardInfoDock->setMinimumSize(100, 100);
|
|
cardInfoDock->setMaximumSize(5000, 5000);
|
|
|
|
messageLayoutDock->setMinimumSize(100, 100);
|
|
messageLayoutDock->setMaximumSize(5000, 5000);
|
|
|
|
playerListDock->setMinimumSize(100, 100);
|
|
playerListDock->setMaximumSize(5000, 5000);
|
|
|
|
if (replayDock) {
|
|
replayDock->setMinimumSize(100, 100);
|
|
replayDock->setMaximumSize(5000, 5000);
|
|
}
|
|
}
|
|
|
|
void TabGame::actResetLayout()
|
|
{
|
|
cardInfoDock->setVisible(true);
|
|
playerListDock->setVisible(true);
|
|
messageLayoutDock->setVisible(true);
|
|
|
|
cardInfoDock->setFloating(false);
|
|
playerListDock->setFloating(false);
|
|
messageLayoutDock->setFloating(false);
|
|
|
|
addDockWidget(Qt::RightDockWidgetArea, cardInfoDock);
|
|
addDockWidget(Qt::RightDockWidgetArea, playerListDock);
|
|
addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock);
|
|
|
|
if (replayDock) {
|
|
replayDock->setVisible(true);
|
|
replayDock->setFloating(false);
|
|
addDockWidget(Qt::BottomDockWidgetArea, replayDock);
|
|
|
|
cardInfoDock->setMinimumSize(250, 360);
|
|
cardInfoDock->setMaximumSize(250, 360);
|
|
messageLayoutDock->setMinimumSize(250, 200);
|
|
messageLayoutDock->setMaximumSize(250, 200);
|
|
playerListDock->setMinimumSize(250, 50);
|
|
playerListDock->setMaximumSize(250, 50);
|
|
replayDock->setMinimumSize(900, 100);
|
|
replayDock->setMaximumSize(900, 100);
|
|
} else {
|
|
cardInfoDock->setMinimumSize(250, 360);
|
|
cardInfoDock->setMaximumSize(250, 360);
|
|
messageLayoutDock->setMinimumSize(250, 250);
|
|
messageLayoutDock->setMaximumSize(250, 250);
|
|
playerListDock->setMinimumSize(250, 50);
|
|
playerListDock->setMaximumSize(250, 50);
|
|
}
|
|
|
|
QTimer::singleShot(100, this, &TabGame::freeDocksSize);
|
|
}
|
|
|
|
void TabGame::createPlayAreaWidget(bool bReplay)
|
|
{
|
|
phasesToolbar = new PhasesToolbar;
|
|
if (!bReplay)
|
|
connect(phasesToolbar, &PhasesToolbar::sendGameCommand, game->getGameEventHandler(),
|
|
qOverload<const ::google::protobuf::Message &, int>(&GameEventHandler::sendGameCommand));
|
|
scene = new GameScene(phasesToolbar, this);
|
|
connect(game->getPlayerManager(), &PlayerManager::playerConceded, scene, &GameScene::rearrange);
|
|
connect(game->getPlayerManager(), &PlayerManager::playerCountChanged, scene, &GameScene::rearrange);
|
|
gameView = new GameView(scene);
|
|
|
|
auto gamePlayAreaVBox = new QVBoxLayout;
|
|
gamePlayAreaVBox->setContentsMargins(0, 0, 0, 0);
|
|
gamePlayAreaVBox->addWidget(gameView);
|
|
|
|
gamePlayAreaWidget = new QWidget;
|
|
gamePlayAreaWidget->setObjectName("gamePlayAreaWidget");
|
|
gamePlayAreaWidget->setLayout(gamePlayAreaVBox);
|
|
}
|
|
|
|
void TabGame::createReplayDock(GameReplay *replay)
|
|
{
|
|
replayManager = new ReplayManager(this, replay);
|
|
|
|
replayDock = new QDockWidget(this);
|
|
replayDock->setObjectName("replayDock");
|
|
replayDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
|
QDockWidget::DockWidgetMovable);
|
|
replayDock->setWidget(replayManager);
|
|
replayDock->setFloating(false);
|
|
}
|
|
|
|
void TabGame::createDeckViewContainerWidget(bool bReplay)
|
|
{
|
|
Q_UNUSED(bReplay);
|
|
|
|
deckViewContainerWidget = new QWidget();
|
|
deckViewContainerWidget->setObjectName("deckViewContainerWidget");
|
|
deckViewContainerLayout = new QVBoxLayout;
|
|
deckViewContainerLayout->setContentsMargins(0, 0, 0, 0);
|
|
deckViewContainerWidget->setLayout(deckViewContainerLayout);
|
|
}
|
|
|
|
void TabGame::viewCardInfo(const CardRef &cardRef) const
|
|
{
|
|
cardInfoFrameWidget->setCard(cardRef);
|
|
}
|
|
|
|
void TabGame::createCardInfoDock(bool bReplay)
|
|
{
|
|
Q_UNUSED(bReplay);
|
|
|
|
cardInfoFrameWidget = new CardInfoFrameWidget();
|
|
auto cardHInfoLayout = new QHBoxLayout;
|
|
auto cardVInfoLayout = new QVBoxLayout;
|
|
cardVInfoLayout->setContentsMargins(0, 0, 0, 0);
|
|
cardVInfoLayout->addWidget(cardInfoFrameWidget);
|
|
cardVInfoLayout->addLayout(cardHInfoLayout);
|
|
|
|
auto cardBoxLayoutWidget = new QWidget;
|
|
cardBoxLayoutWidget->setLayout(cardVInfoLayout);
|
|
|
|
cardInfoDock = new QDockWidget(this);
|
|
cardInfoDock->setObjectName("cardInfoDock");
|
|
cardInfoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
|
QDockWidget::DockWidgetMovable);
|
|
cardInfoDock->setWidget(cardBoxLayoutWidget);
|
|
cardInfoDock->setFloating(false);
|
|
}
|
|
|
|
void TabGame::createPlayerListDock(bool bReplay)
|
|
{
|
|
if (bReplay) {
|
|
playerListWidget = new PlayerListWidget(nullptr, nullptr, game);
|
|
} else {
|
|
playerListWidget = new PlayerListWidget(tabSupervisor, game->getGameState()->getClients().first(), game);
|
|
connect(playerListWidget, SIGNAL(openMessageDialog(QString, bool)), this,
|
|
SIGNAL(openMessageDialog(QString, bool)));
|
|
}
|
|
playerListWidget->setFocusPolicy(Qt::NoFocus);
|
|
|
|
playerListDock = new QDockWidget(this);
|
|
playerListDock->setObjectName("playerListDock");
|
|
playerListDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
|
QDockWidget::DockWidgetMovable);
|
|
playerListDock->setWidget(playerListWidget);
|
|
playerListDock->setFloating(false);
|
|
}
|
|
|
|
void TabGame::createMessageDock(bool bReplay)
|
|
{
|
|
auto messageLogLayout = new QVBoxLayout;
|
|
messageLogLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
// clock
|
|
if (!bReplay) {
|
|
timeElapsedLabel = new QLabel;
|
|
timeElapsedLabel->setAlignment(Qt::AlignCenter);
|
|
connect(game->getGameState(), &GameState::updateTimeElapsedLabel, this, &TabGame::updateTimeElapsedLabel);
|
|
|
|
messageLogLayout->addWidget(timeElapsedLabel);
|
|
}
|
|
|
|
// message log
|
|
messageLog = new MessageLogWidget(tabSupervisor, game);
|
|
connect(messageLog, &MessageLogWidget::cardNameHovered, cardInfoFrameWidget,
|
|
qOverload<const QString &>(&CardInfoFrameWidget::setCard));
|
|
connect(messageLog, &MessageLogWidget::showCardInfoPopup, this, &TabGame::showCardInfoPopup);
|
|
connect(messageLog, &MessageLogWidget::deleteCardInfoPopup, this, &TabGame::deleteCardInfoPopup);
|
|
|
|
if (!bReplay) {
|
|
connect(messageLog, &MessageLogWidget::openMessageDialog, this, &TabGame::openMessageDialog);
|
|
connect(messageLog, &MessageLogWidget::addMentionTag, this, &TabGame::addMentionTag);
|
|
connect(&SettingsCache::instance(), &SettingsCache::chatMentionCompleterChanged, this,
|
|
&TabGame::actCompleterChanged);
|
|
}
|
|
|
|
messageLogLayout->addWidget(messageLog);
|
|
|
|
// chat entry
|
|
if (!bReplay) {
|
|
sayLabel = new QLabel;
|
|
sayEdit = new LineEditCompleter;
|
|
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
|
|
sayLabel->setBuddy(sayEdit);
|
|
connect(this, &TabGame::chatMessageSent, game->getGameEventHandler(), &GameEventHandler::handleChatMessageSent);
|
|
completer = new QCompleter(autocompleteUserList, sayEdit);
|
|
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
|
completer->setMaxVisibleItems(5);
|
|
completer->setFilterMode(Qt::MatchStartsWith);
|
|
|
|
sayEdit->setCompleter(completer);
|
|
actCompleterChanged();
|
|
|
|
if (game->getPlayerManager()->isSpectator()) {
|
|
/* Spectators can only talk if:
|
|
* (a) the game creator allows it
|
|
* (b) the spectator is a moderator/administrator
|
|
* (c) the spectator is a judge
|
|
*/
|
|
bool isModOrJudge = !tabSupervisor->getAdminLocked() || game->getPlayerManager()->isJudge();
|
|
if (!isModOrJudge && !game->getGameMetaInfo()->spectatorsCanChat()) {
|
|
sayLabel->hide();
|
|
sayEdit->hide();
|
|
}
|
|
}
|
|
|
|
connect(tabSupervisor, &TabSupervisor::adminLockChanged, this, &TabGame::adminLockChanged);
|
|
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabGame::actSay);
|
|
|
|
auto sayHLayout = new QHBoxLayout;
|
|
sayHLayout->addWidget(sayLabel);
|
|
sayHLayout->addWidget(sayEdit);
|
|
|
|
messageLogLayout->addLayout(sayHLayout);
|
|
}
|
|
|
|
// dock
|
|
auto messageLogLayoutWidget = new QWidget;
|
|
messageLogLayoutWidget->setLayout(messageLogLayout);
|
|
|
|
messageLayoutDock = new QDockWidget(this);
|
|
messageLayoutDock->setObjectName("messageLayoutDock");
|
|
messageLayoutDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
|
QDockWidget::DockWidgetMovable);
|
|
messageLayoutDock->setWidget(messageLogLayoutWidget);
|
|
messageLayoutDock->setFloating(false);
|
|
}
|
|
|
|
void TabGame::hideEvent(QHideEvent *event)
|
|
{
|
|
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
|
if (replayDock) {
|
|
layouts.setReplayPlayAreaState(saveState());
|
|
layouts.setReplayPlayAreaGeometry(saveGeometry());
|
|
layouts.setReplayCardInfoSize(cardInfoDock->size());
|
|
layouts.setReplayMessageLayoutSize(messageLayoutDock->size());
|
|
layouts.setReplayPlayerListSize(playerListDock->size());
|
|
layouts.setReplayReplaySize(replayDock->size());
|
|
} else {
|
|
layouts.setGamePlayAreaState(saveState());
|
|
layouts.setGamePlayAreaGeometry(saveGeometry());
|
|
layouts.setGameCardInfoSize(cardInfoDock->size());
|
|
layouts.setGameMessageLayoutSize(messageLayoutDock->size());
|
|
layouts.setGamePlayerListSize(playerListDock->size());
|
|
}
|
|
|
|
Tab::hideEvent(event);
|
|
}
|