[Client] Add tournament UI for creating and following lobby tournaments

Wires the tournament protocol into the client:
- DlgCreateGame gains a tournament checkbox with a games-per-match
  settings sub-dialog; both values are sent with Command_CreateGame and
  mirrored in the join-info variant of the dialog
- TournamentWidget renders live standings (with deck-submission state)
  and pairings for the local player's perspective, and asks to open the
  current match game via openMatchGameRequested()
- TournamentTabGameExtension attaches an overview page to TabGame's
  stacked views, mirrors phase and submission progress onto a deck-view
  status strip, and provides round-trip navigation between game view and
  standings; hosts get an in-game settings dialog during deck building
- Open-match falls back to joining as spectator through TabSupervisor;
  sub-games now return to their parent tab on close, falling back to
  the normal leave-game flow when the parent is gone
This commit is contained in:
Lukas Brübach 2026-08-24 12:04:00 +02:00
parent a101cf75ee
commit 372d4fd63b
13 changed files with 719 additions and 3 deletions

View file

@ -33,6 +33,7 @@
#include "card_database_display_model.h"
#include "card_database_model.h"
#include "tab_supervisor.h"
#include "tournament_tab_game_extension.h"
#include <QAction>
#include <QApplication>
@ -134,6 +135,10 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
createMenuItems();
createViewMenuItems();
if (game->getGameMetaInfo()->isTournament()) {
tournamentExtension = new TournamentTabGameExtension(this);
}
connectToGameState();
connectToPlayerManager();
connectToGameEventHandler();
@ -150,6 +155,10 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
gameTypes.append(game->getGameMetaInfo()->findRoomGameType(i));
}
if (tournamentExtension) {
tournamentExtension->initializeTournamentMode();
}
QTimer::singleShot(0, this, &TabGame::loadLayout);
}
@ -400,6 +409,10 @@ void TabGame::retranslateUi()
}
scene->retranslateUi();
if (tournamentExtension) {
tournamentExtension->retranslateUi();
}
}
void TabGame::refreshShortcuts()
@ -928,8 +941,22 @@ void TabGame::stopGame()
}
}
bool TabGame::switchToGameTab(int gameId)
{
return tabSupervisor->switchToGameTabIfAlreadyExists(gameId);
}
void TabGame::closeGame()
{
int parentId = game->getGameMetaInfo()->parentGameId();
if (parentId >= 0) {
if (switchToGameTab(parentId)) {
close();
}
// If the parent tab is gone, fall through to the normal leave-game
// flow instead of stranding the user on a dead sub-game tab.
}
gameMenu->clear();
gameMenu->addAction(aLeaveGame);
}