[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 committed by GitHub
parent 4b106419f5
commit 5c30c52714
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 719 additions and 3 deletions

View file

@ -0,0 +1,56 @@
#ifndef TOURNAMENT_WIDGET_H
#define TOURNAMENT_WIDGET_H
#include <QWidget>
#include <libcockatrice/protocol/pb/event_tournament_state.pb.h>
class QLabel;
class QPushButton;
class QTableWidget;
class QTableWidgetItem;
/**
* @class TournamentWidget
* @ingroup GameViews
* @brief Displays live standings and pairings for a tournament game.
*
* Updated exclusively via updateTournamentState(); the widget holds no
* logic of its own beyond mapping protocol state to table rows. Navigation
* decisions (which pairing belongs to the local player) are resolved here so
* callers only need to react to openMatchGameRequested().
*/
class TournamentWidget : public QWidget
{
Q_OBJECT
public:
explicit TournamentWidget(QWidget *parent = nullptr);
void updateTournamentState(const Event_TournamentState &state);
void setLocalPlayerId(int playerId);
void retranslateUi();
signals:
/*! Emitted when the user asks to open the match game of their current pairing. */
void openMatchGameRequested(int gameId);
private:
void rebuildTables(const Event_TournamentState &state);
void resolveCurrentGameId(const Event_TournamentState &state);
void updateOpenMatchButton();
[[nodiscard]] QString getPlayerName(const Event_TournamentState &state, int playerId) const;
[[nodiscard]] int getGamesPerMatch(const Event_TournamentState &state) const;
QLabel *statusLabel;
QLabel *roundLabel;
QTableWidget *standingsTable;
QTableWidget *pairingsTable;
QPushButton *openMatchButton;
int localPlayerId = -1;
int currentGameId = -1;
bool hasOwnLivePairing = false;
bool hasAnyLivePairing = false;
Event_TournamentState lastState;
};
#endif // TOURNAMENT_WIDGET_H