diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index fd2e97c2f..5812985c7 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -27,6 +27,7 @@ set(cockatrice_SOURCES src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp src/interface/widgets/dialogs/dlg_create_game.cpp src/interface/widgets/dialogs/dlg_default_tags_editor.cpp + src/interface/widgets/dialogs/game_zone_options_widget.cpp src/interface/widgets/dialogs/dlg_edit_avatar.cpp src/interface/widgets/dialogs/dlg_edit_password.cpp src/interface/widgets/dialogs/dlg_edit_tokens.cpp @@ -39,6 +40,7 @@ set(cockatrice_SOURCES src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp src/interface/widgets/dialogs/dlg_load_remote_deck.cpp + src/interface/widgets/dialogs/dlg_local_game_options.cpp src/interface/widgets/dialogs/dlg_manage_sets.cpp src/interface/widgets/dialogs/dlg_register.cpp src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp @@ -82,8 +84,8 @@ set(cockatrice_SOURCES src/game/phase.cpp src/game/phases_toolbar.cpp src/game/player/menu/card_menu.cpp - src/game/player/menu/custom_zone_menu.cpp src/game/player/menu/command_zone_menu.cpp + src/game/player/menu/custom_zone_menu.cpp src/game/player/menu/grave_menu.cpp src/game/player/menu/hand_menu.cpp src/game/player/menu/library_menu.cpp @@ -105,18 +107,18 @@ set(cockatrice_SOURCES src/game/player/player_target.cpp src/game/replay.cpp src/game/zones/card_zone.cpp + src/game/zones/command_zone.cpp src/game/zones/command_zone_state.cpp src/game/zones/hand_zone.cpp - src/game/zones/command_zone.cpp - src/game/zones/logic/command_zone_logic.cpp src/game/zones/logic/card_zone_logic.cpp + src/game/zones/logic/command_zone_logic.cpp src/game/zones/logic/hand_zone_logic.cpp src/game/zones/logic/pile_zone_logic.cpp src/game/zones/logic/stack_zone_logic.cpp src/game/zones/logic/table_zone_logic.cpp src/game/zones/logic/view_zone_logic.cpp - src/game/zones/zone_toggle_button.cpp src/game/zones/pile_zone.cpp + src/game/zones/zone_toggle_button.cpp src/game/zones/select_zone.cpp src/game/zones/stack_zone.cpp src/game/zones/table_zone.cpp diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp index 7f109f600..146ad6462 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp @@ -2,6 +2,7 @@ #include "../../../client/settings/cache_settings.h" #include "../interface/widgets/tabs/tab_room.h" +#include "game_zone_options_widget.h" #include #include @@ -102,6 +103,7 @@ void DlgCreateGame::sharedCtor() startingLifeTotalLabel->setBuddy(startingLifeTotalEdit); shareDecklistsOnLoadCheckBox = new QCheckBox(tr("Open decklists in lobby")); + zoneOptionsWidget = new GameZoneOptionsWidget(this); createGameAsJudgeCheckBox = new QCheckBox(tr("Create game as judge")); @@ -109,8 +111,9 @@ void DlgCreateGame::sharedCtor() gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0); gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1); gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 0); + gameSetupOptionsLayout->addWidget(zoneOptionsWidget, 2, 0, 1, 2); if (room && room->getUserInfo()->user_level() & ServerInfo_User::IsJudge) { - gameSetupOptionsLayout->addWidget(createGameAsJudgeCheckBox, 2, 0); + gameSetupOptionsLayout->addWidget(createGameAsJudgeCheckBox, 3, 0); } else { createGameAsJudgeCheckBox->setChecked(false); createGameAsJudgeCheckBox->setHidden(true); @@ -171,6 +174,7 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap &_gameType createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().getCreateGameAsSpectator()); startingLifeTotalEdit->setValue(SettingsCache::instance().getDefaultStartingLifeTotal()); shareDecklistsOnLoadCheckBox->setChecked(SettingsCache::instance().getShareDecklistsOnLoad()); + zoneOptionsWidget->loadFromSettings(); if (!rememberGameSettings->isChecked()) { actReset(); @@ -204,6 +208,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMapsetEnabled(false); startingLifeTotalEdit->setEnabled(false); shareDecklistsOnLoadCheckBox->setEnabled(false); + zoneOptionsWidget->setReadOnly(true); descriptionEdit->setText(QString::fromStdString(gameInfo.description())); maxPlayersEdit->setValue(gameInfo.max_players()); @@ -249,6 +254,7 @@ void DlgCreateGame::actReset() startingLifeTotalEdit->setValue(20); shareDecklistsOnLoadCheckBox->setChecked(false); + zoneOptionsWidget->resetToDefaults(); createGameAsJudgeCheckBox->setChecked(false); QMapIterator gameTypeCheckBoxIterator(gameTypeCheckBoxes); @@ -279,6 +285,9 @@ void DlgCreateGame::actOK() cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked()); cmd.set_starting_life_total(startingLifeTotalEdit->value()); cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked()); + cmd.set_enable_command_zone(zoneOptionsWidget->enableCommandZone()); + cmd.set_enable_companion_zone(zoneOptionsWidget->enableCompanionZone()); + cmd.set_enable_background_zone(zoneOptionsWidget->enableBackgroundZone()); auto _gameTypes = QString(); QMapIterator gameTypeCheckBoxIterator(gameTypeCheckBoxes); @@ -303,6 +312,7 @@ void DlgCreateGame::actOK() SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked()); SettingsCache::instance().setDefaultStartingLifeTotal(startingLifeTotalEdit->value()); SettingsCache::instance().setShareDecklistsOnLoad(shareDecklistsOnLoadCheckBox->isChecked()); + zoneOptionsWidget->saveToSettings(); SettingsCache::instance().setGameTypes(_gameTypes); } PendingCommand *pend = room->prepareRoomCommand(cmd); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_create_game.h b/cockatrice/src/interface/widgets/dialogs/dlg_create_game.h index e28363311..c07154b05 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_create_game.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_create_game.h @@ -11,6 +11,7 @@ #include #include +class GameZoneOptionsWidget; class QCheckBox; class QDialogButtonBox; class QGroupBox; @@ -48,6 +49,7 @@ private: QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox, *spectatorsSeeEverythingCheckBox, *createGameAsJudgeCheckBox, *createGameAsSpectatorCheckBox; QCheckBox *shareDecklistsOnLoadCheckBox; + GameZoneOptionsWidget *zoneOptionsWidget; QDialogButtonBox *buttonBox; QPushButton *clearButton; QCheckBox *rememberGameSettings; diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.cpp new file mode 100644 index 000000000..864018f61 --- /dev/null +++ b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.cpp @@ -0,0 +1,124 @@ +#include "dlg_local_game_options.h" + +#include "../../../client/settings/cache_settings.h" +#include "game_zone_options_widget.h" + +#include +#include +#include +#include +#include +#include +#include + +DlgLocalGameOptions::DlgLocalGameOptions(QWidget *parent) : QDialog(parent) +{ + // General settings group + numberPlayersLabel = new QLabel(tr("P&layers:")); + numberPlayersEdit = new QSpinBox(); + numberPlayersEdit->setMinimum(1); + numberPlayersEdit->setMaximum(8); + numberPlayersEdit->setValue(1); + numberPlayersLabel->setBuddy(numberPlayersEdit); + + auto *generalGrid = new QGridLayout; + generalGrid->addWidget(numberPlayersLabel, 0, 0); + generalGrid->addWidget(numberPlayersEdit, 0, 1); + generalGroupBox = new QGroupBox(tr("General")); + generalGroupBox->setLayout(generalGrid); + + // Game setup options group + startingLifeTotalLabel = new QLabel(tr("Starting life total:")); + startingLifeTotalEdit = new QSpinBox(); + startingLifeTotalEdit->setMinimum(1); + startingLifeTotalEdit->setMaximum(99999); + startingLifeTotalEdit->setValue(20); + startingLifeTotalLabel->setBuddy(startingLifeTotalEdit); + + zoneOptionsWidget = new GameZoneOptionsWidget(this); + spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands")); + + auto *gameSetupGrid = new QGridLayout; + gameSetupGrid->addWidget(startingLifeTotalLabel, 0, 0); + gameSetupGrid->addWidget(startingLifeTotalEdit, 0, 1); + gameSetupGrid->addWidget(zoneOptionsWidget, 1, 0, 1, 2); + gameSetupGrid->addWidget(spectatorsSeeEverythingCheckBox, 2, 0, 1, 2); + gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options")); + gameSetupOptionsGroupBox->setLayout(gameSetupGrid); + + // Remember settings checkbox + rememberSettingsCheckBox = new QCheckBox(tr("Re&member settings")); + + // Button box + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLocalGameOptions::actOK); + connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLocalGameOptions::reject); + + // Main layout + auto *mainLayout = new QVBoxLayout; + mainLayout->addWidget(generalGroupBox); + mainLayout->addWidget(gameSetupOptionsGroupBox); + mainLayout->addWidget(rememberSettingsCheckBox); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + // Load settings + rememberSettingsCheckBox->setChecked(SettingsCache::instance().getRememberGameSettings()); + if (rememberSettingsCheckBox->isChecked()) { + numberPlayersEdit->setValue(SettingsCache::instance().getMaxPlayers()); + startingLifeTotalEdit->setValue(SettingsCache::instance().getDefaultStartingLifeTotal()); + zoneOptionsWidget->loadFromSettings(); + spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything()); + } else { + zoneOptionsWidget->resetToDefaults(); + } + + setWindowTitle(tr("Local game options")); + setFixedHeight(sizeHint().height()); + + numberPlayersEdit->setFocus(); +} + +void DlgLocalGameOptions::actOK() +{ + // Save settings if remember is checked + SettingsCache::instance().setRememberGameSettings(rememberSettingsCheckBox->isChecked()); + if (rememberSettingsCheckBox->isChecked()) { + SettingsCache::instance().setMaxPlayers(numberPlayersEdit->value()); + SettingsCache::instance().setDefaultStartingLifeTotal(startingLifeTotalEdit->value()); + zoneOptionsWidget->saveToSettings(); + SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked()); + } + + accept(); +} + +int DlgLocalGameOptions::getNumberPlayers() const +{ + return numberPlayersEdit->value(); +} + +int DlgLocalGameOptions::getStartingLifeTotal() const +{ + return startingLifeTotalEdit->value(); +} + +bool DlgLocalGameOptions::getEnableCommandZone() const +{ + return zoneOptionsWidget->enableCommandZone(); +} + +bool DlgLocalGameOptions::getEnableCompanionZone() const +{ + return zoneOptionsWidget->enableCompanionZone(); +} + +bool DlgLocalGameOptions::getEnableBackgroundZone() const +{ + return zoneOptionsWidget->enableBackgroundZone(); +} + +bool DlgLocalGameOptions::getSpectatorsSeeEverything() const +{ + return spectatorsSeeEverythingCheckBox->isChecked(); +} diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.h b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.h new file mode 100644 index 000000000..bfa96c40d --- /dev/null +++ b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.h @@ -0,0 +1,52 @@ +/** + * @file dlg_local_game_options.h + * @ingroup RoomDialogs + * @brief Dialog for configuring local game options. + */ + +#ifndef DLG_LOCAL_GAME_OPTIONS_H +#define DLG_LOCAL_GAME_OPTIONS_H + +#include + +class GameZoneOptionsWidget; +class QCheckBox; +class QDialogButtonBox; +class QGroupBox; +class QLabel; +class QSpinBox; + +class DlgLocalGameOptions : public QDialog +{ + Q_OBJECT +public: + explicit DlgLocalGameOptions(QWidget *parent = nullptr); + + int getNumberPlayers() const; + int getStartingLifeTotal() const; + bool getEnableCommandZone() const; + bool getEnableCompanionZone() const; + bool getEnableBackgroundZone() const; + bool getSpectatorsSeeEverything() const; + +private slots: + void actOK(); + +private: + QGroupBox *generalGroupBox; + QGroupBox *gameSetupOptionsGroupBox; + + QLabel *numberPlayersLabel; + QSpinBox *numberPlayersEdit; + + QLabel *startingLifeTotalLabel; + QSpinBox *startingLifeTotalEdit; + + GameZoneOptionsWidget *zoneOptionsWidget; + QCheckBox *spectatorsSeeEverythingCheckBox; + QCheckBox *rememberSettingsCheckBox; + + QDialogButtonBox *buttonBox; +}; + +#endif // DLG_LOCAL_GAME_OPTIONS_H diff --git a/cockatrice/src/interface/widgets/dialogs/game_zone_options_widget.cpp b/cockatrice/src/interface/widgets/dialogs/game_zone_options_widget.cpp new file mode 100644 index 000000000..b9e4c2a5c --- /dev/null +++ b/cockatrice/src/interface/widgets/dialogs/game_zone_options_widget.cpp @@ -0,0 +1,78 @@ +#include "game_zone_options_widget.h" + +#include "../../../client/settings/cache_settings.h" + +#include +#include + +GameZoneOptionsWidget::GameZoneOptionsWidget(QWidget *parent) : QWidget(parent) +{ + enableCommandZoneCheckBox = new QCheckBox(tr("Enable command zone (Commander)"), this); + enableCompanionZoneCheckBox = new QCheckBox(tr("Enable companion zone"), this); + enableBackgroundZoneCheckBox = new QCheckBox(tr("Enable background zone"), this); + + auto *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(enableCommandZoneCheckBox); + layout->addWidget(enableCompanionZoneCheckBox); + layout->addWidget(enableBackgroundZoneCheckBox); + setLayout(layout); +} + +bool GameZoneOptionsWidget::enableCommandZone() const +{ + return enableCommandZoneCheckBox->isChecked(); +} + +bool GameZoneOptionsWidget::enableCompanionZone() const +{ + return enableCompanionZoneCheckBox->isChecked(); +} + +bool GameZoneOptionsWidget::enableBackgroundZone() const +{ + return enableBackgroundZoneCheckBox->isChecked(); +} + +void GameZoneOptionsWidget::setCommandZoneEnabled(bool enabled) +{ + enableCommandZoneCheckBox->setChecked(enabled); +} + +void GameZoneOptionsWidget::setCompanionZoneEnabled(bool enabled) +{ + enableCompanionZoneCheckBox->setChecked(enabled); +} + +void GameZoneOptionsWidget::setBackgroundZoneEnabled(bool enabled) +{ + enableBackgroundZoneCheckBox->setChecked(enabled); +} + +void GameZoneOptionsWidget::loadFromSettings() +{ + enableCommandZoneCheckBox->setChecked(SettingsCache::instance().getEnableCommandZone()); + enableCompanionZoneCheckBox->setChecked(SettingsCache::instance().getEnableCompanionZone()); + enableBackgroundZoneCheckBox->setChecked(SettingsCache::instance().getEnableBackgroundZone()); +} + +void GameZoneOptionsWidget::saveToSettings() +{ + SettingsCache::instance().setEnableCommandZone(enableCommandZoneCheckBox->isChecked()); + SettingsCache::instance().setEnableCompanionZone(enableCompanionZoneCheckBox->isChecked()); + SettingsCache::instance().setEnableBackgroundZone(enableBackgroundZoneCheckBox->isChecked()); +} + +void GameZoneOptionsWidget::resetToDefaults() +{ + enableCommandZoneCheckBox->setChecked(false); + enableCompanionZoneCheckBox->setChecked(true); + enableBackgroundZoneCheckBox->setChecked(true); +} + +void GameZoneOptionsWidget::setReadOnly(bool readOnly) +{ + enableCommandZoneCheckBox->setEnabled(!readOnly); + enableCompanionZoneCheckBox->setEnabled(!readOnly); + enableBackgroundZoneCheckBox->setEnabled(!readOnly); +} diff --git a/cockatrice/src/interface/widgets/dialogs/game_zone_options_widget.h b/cockatrice/src/interface/widgets/dialogs/game_zone_options_widget.h new file mode 100644 index 000000000..6abc2c0cc --- /dev/null +++ b/cockatrice/src/interface/widgets/dialogs/game_zone_options_widget.h @@ -0,0 +1,67 @@ +/** + * @file game_zone_options_widget.h + * @ingroup RoomDialogs + * @brief Reusable widget for Commander format zone options. + * + * This widget encapsulates the zone enable/disable checkboxes used in both + * DlgCreateGame and DlgLocalGameOptions. It provides a simple interface + * while hiding settings persistence details. + */ + +#ifndef GAME_ZONE_OPTIONS_WIDGET_H +#define GAME_ZONE_OPTIONS_WIDGET_H + +#include + +class QCheckBox; +class QVBoxLayout; + +/** + * @class GameZoneOptionsWidget + * @brief Widget for configuring Commander format zone options. + * + * Provides checkboxes for enabling command zone, companion zone, and + * background zone. Handles settings persistence internally, so callers + * don't need to know about SettingsCache keys or default values. + */ +class GameZoneOptionsWidget : public QWidget +{ + Q_OBJECT + +public: + explicit GameZoneOptionsWidget(QWidget *parent = nullptr); + + [[nodiscard]] bool enableCommandZone() const; + [[nodiscard]] bool enableCompanionZone() const; + [[nodiscard]] bool enableBackgroundZone() const; + + void setCommandZoneEnabled(bool enabled); + void setCompanionZoneEnabled(bool enabled); + void setBackgroundZoneEnabled(bool enabled); + + void loadFromSettings(); + void saveToSettings(); + void resetToDefaults(); + + void setReadOnly(bool readOnly); + + QCheckBox *getCommandZoneCheckBox() const + { + return enableCommandZoneCheckBox; + } + QCheckBox *getCompanionZoneCheckBox() const + { + return enableCompanionZoneCheckBox; + } + QCheckBox *getBackgroundZoneCheckBox() const + { + return enableBackgroundZoneCheckBox; + } + +private: + QCheckBox *enableCommandZoneCheckBox; + QCheckBox *enableCompanionZoneCheckBox; + QCheckBox *enableBackgroundZoneCheckBox; +}; + +#endif // GAME_ZONE_OPTIONS_WIDGET_H diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp index 3724ff29d..fa71f074b 100644 --- a/cockatrice/src/interface/window_main.cpp +++ b/cockatrice/src/interface/window_main.cpp @@ -39,6 +39,7 @@ #include "../main.h" #include "logger.h" #include "version_string.h" +#include "widgets/dialogs/dlg_local_game_options.h" #include "widgets/utility/get_text_with_max.h" #include @@ -225,16 +226,20 @@ void MainWindow::actDisconnect() void MainWindow::actSinglePlayer() { - bool ok; - int numberPlayers = - QInputDialog::getInt(this, tr("Number of players"), tr("Please enter the number of players."), 1, 1, 8, 1, &ok); - if (!ok) + DlgLocalGameOptions dlg(this); + if (!dlg.exec()) return; - startLocalGame(numberPlayers); + startLocalGame(dlg.getNumberPlayers(), dlg.getStartingLifeTotal(), dlg.getEnableCommandZone(), + dlg.getEnableCompanionZone(), dlg.getEnableBackgroundZone(), dlg.getSpectatorsSeeEverything()); } -void MainWindow::startLocalGame(int numberPlayers) +void MainWindow::startLocalGame(int numberPlayers, + int startingLifeTotal, + bool enableCommandZone, + bool enableCompanionZone, + bool enableBackgroundZone, + bool spectatorsSeeEverything) { aConnect->setEnabled(false); aRegister->setEnabled(false); @@ -258,6 +263,11 @@ void MainWindow::startLocalGame(int numberPlayers) Command_CreateGame createCommand; createCommand.set_max_players(static_cast(numberPlayers)); + createCommand.set_starting_life_total(startingLifeTotal); + createCommand.set_enable_command_zone(enableCommandZone); + createCommand.set_enable_companion_zone(enableCompanionZone); + createCommand.set_enable_background_zone(enableBackgroundZone); + createCommand.set_spectators_see_everything(spectatorsSeeEverything); mainClient->sendCommand(LocalClient::prepareRoomCommand(createCommand, 0)); } @@ -913,7 +923,11 @@ MainWindow::MainWindow(QWidget *parent) void MainWindow::startupConfigCheck() { if (SettingsCache::instance().debug().getLocalGameOnStartup()) { - startLocalGame(SettingsCache::instance().debug().getLocalGamePlayerCount()); + startLocalGame( + SettingsCache::instance().debug().getLocalGamePlayerCount(), + SettingsCache::instance().getDefaultStartingLifeTotal(), SettingsCache::instance().getEnableCommandZone(), + SettingsCache::instance().getEnableCompanionZone(), SettingsCache::instance().getEnableBackgroundZone(), + SettingsCache::instance().getSpectatorsCanSeeEverything()); } if (SettingsCache::instance().getCheckUpdatesOnStartup()) { diff --git a/cockatrice/src/interface/window_main.h b/cockatrice/src/interface/window_main.h index 75b0f5062..4314f2463 100644 --- a/cockatrice/src/interface/window_main.h +++ b/cockatrice/src/interface/window_main.h @@ -137,7 +137,12 @@ private: void createCardUpdateProcess(bool background = false); void exitCardDatabaseUpdate(); - void startLocalGame(int numberPlayers); + void startLocalGame(int numberPlayers, + int startingLifeTotal, + bool enableCommandZone, + bool enableCompanionZone, + bool enableBackgroundZone, + bool spectatorsSeeEverything); QList tabMenus; QMenu *cockatriceMenu, *dbMenu, *tabsMenu, *helpMenu, *trayIconMenu;