Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
- Max regret is calculated correctly for strategy and behavior profiles on games with zero player
strategies or actions (is defined to be 0 trivially) (#904)

### Changed
- Added a new welcome/landing window on launching the GUI without a game. This has the effect of
avoiding creating a window with a trivial extensive game which the user then has to dismiss if
they do not require it. (#80)

### Removed
- Built-in plotting of logit QRE for strategic games has been removed in the GUI (#809)

Expand Down
6 changes: 5 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ gambit_SOURCES = \
src/gui/dlnash.h \
src/gui/dlnashmon.cc \
src/gui/dlnashmon.h \
src/gui/dlnewtable.cc \
src/gui/dlnewtable.h \
src/gui/dlnfglogit.cc \
src/gui/dlnfglogit.h \
src/gui/efgdisplay.cc \
Expand All @@ -521,7 +523,9 @@ gambit_SOURCES = \
src/gui/style.cc \
src/gui/style.h \
src/gui/valnumber.cc \
src/gui/valnumber.h
src/gui/valnumber.h \
src/gui/welcome.cc \
src/gui/welcome.h

# Add wxWidgets compilation flags for the GUI program
gambit_CXXFLAGS = $(AM_CXXFLAGS) $(WX_CXXFLAGS)
Expand Down
31 changes: 14 additions & 17 deletions src/gui/app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include "app.h"
#include "gameframe.h"
#include "welcome.h"

#include "bitmaps/gambitbig.xpm"

Expand Down Expand Up @@ -66,13 +67,6 @@ wxBEGIN_EVENT_TABLE(Application, wxApp) EVT_TIMER(wxID_ANY, Application::OnSplas

bool Application::OnInit()
{
const wxBitmap bitmap(gambitbig_xpm);
m_splashTimer.Start();
m_splash = new wxSplashScreen(MakeScaledSplashBitmap(bitmap, 0.45),
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, nullptr,
wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE);
m_splash->Show();
m_splash->Update();
wxConfigBase::Set(new wxConfig(_T("Gambit"), _T("Gambit")));
m_fileHistory.Load(*wxConfigBase::Get());
// Immediately saving this back forces the entries to be created at
Expand All @@ -87,20 +81,23 @@ wxBEGIN_EVENT_TABLE(Application, wxApp) EVT_TIMER(wxID_ANY, Application::OnSplas
}

if (m_documents.empty()) {
const Game efg = NewTree();
efg->NewPlayer()->SetLabel("Player 1");
efg->NewPlayer()->SetLabel("Player 2");
efg->SetTitle("Untitled Extensive Game");

auto *game = new GameDocument(efg);
(void)new GameFrame(nullptr, game);
auto *frame = new WelcomeFrame(nullptr);
frame->Show(true);
SetTopWindow(frame);
}
else {
const wxBitmap bitmap(gambitbig_xpm);
m_splashTimer.Start();
m_splash = new wxSplashScreen(MakeScaledSplashBitmap(bitmap, 0.45),
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, nullptr,
wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE);
m_splash->Show();
m_splash->Update();
this->CallAfter(&Application::DismissSplash);
}

// Set up the help system.
wxInitAllImageHandlers();

this->CallAfter(&Application::DismissSplash);

return true;
}

Expand Down
140 changes: 140 additions & 0 deletions src/gui/dlnewtable.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include "dlnewtable.h"

#include <algorithm>
#include <vector>

#include <wx/choice.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/stattext.h>
#include <wx/button.h>

namespace Gambit::GUI {

namespace {
constexpr int ID_PLAYER_COUNT = wxID_HIGHEST + 401;
constexpr int ID_FIRST_STRATEGY_COUNT = wxID_HIGHEST + 500;
} // namespace

NewTableDialog::NewTableDialog(wxWindow *parent)
: wxDialog(parent, wxID_ANY, wxT("New strategic-form game"), wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
CreateControls();
LayoutControls();
RebuildStrategyControls();
Fit();
CentreOnParent();
}

std::vector<int> NewTableDialog::GetDimensions() const
{
std::vector<int> dimensions;
dimensions.reserve(m_strategyCtrls.size());

for (const auto *ctrl : m_strategyCtrls) {
dimensions.push_back(ctrl->GetValue());
}

return dimensions;
}

void NewTableDialog::CreateControls()
{
auto *playerCountLabel = new wxStaticText(this, wxID_ANY, wxT("Number of players:"));
m_playerCountCtrl = new wxSpinCtrl(this, ID_PLAYER_COUNT);
m_playerCountCtrl->SetRange(2, 16);
m_playerCountCtrl->SetValue(2);

m_strategyRowsSizer = new wxBoxSizer(wxVERTICAL);

Bind(wxEVT_SPINCTRL, &NewTableDialog::OnPlayerCountChanged, this, ID_PLAYER_COUNT);

// Store labels locally for layout construction.
playerCountLabel->SetName("playerCountLabel");
}

void NewTableDialog::LayoutControls()
{
m_topSizer = new wxBoxSizer(wxVERTICAL);

auto *formSizer = new wxFlexGridSizer(2, 2, 8, 12);
formSizer->AddGrowableCol(1, 1);

auto *playerCountLabel = FindWindowByName("playerCountLabel", this);
formSizer->Add(playerCountLabel, 0, wxALIGN_CENTER_VERTICAL);
formSizer->Add(m_playerCountCtrl, 0);

auto *strategyBox = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Strategies per player"));
strategyBox->Add(m_strategyRowsSizer, 0, wxEXPAND | wxALL, 8);

auto *buttonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);

m_topSizer->Add(formSizer, 0, wxEXPAND | wxALL, 12);
m_topSizer->Add(strategyBox, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 12);
m_topSizer->Add(buttonSizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 12);

SetSizer(m_topSizer);
}

void NewTableDialog::RebuildStrategyControls()
{
for (auto *label : m_strategyLabels) {
label->Destroy();
}
for (auto *ctrl : m_strategyCtrls) {
ctrl->Destroy();
}

m_strategyLabels.clear();
m_strategyCtrls.clear();

m_strategyRowsSizer->Clear(false);

const int playerCount = m_playerCountCtrl->GetValue();

auto *grid = new wxFlexGridSizer(playerCount, 2, 8, 12);
grid->AddGrowableCol(1, 1);

for (int i = 0; i < playerCount; ++i) {
auto *label = new wxStaticText(this, wxID_ANY, wxString::Format(wxT("Player %d:"), i + 1));
auto *ctrl = new wxSpinCtrl(this, ID_FIRST_STRATEGY_COUNT + i);

ctrl->SetRange(1, 99);
ctrl->SetValue(2);

grid->Add(label, 0, wxALIGN_CENTER_VERTICAL);
grid->Add(ctrl, 0);

m_strategyLabels.push_back(label);
m_strategyCtrls.push_back(ctrl);
}

m_strategyRowsSizer->Add(grid, 0, wxEXPAND);
Layout();
Fit();
}

void NewTableDialog::OnPlayerCountChanged(wxSpinEvent &p_event)
{
const int oldCount = static_cast<int>(m_strategyCtrls.size());
const int newCount = p_event.GetValue();

std::vector<int> existingValues;
existingValues.reserve(m_strategyCtrls.size());
for (const auto *ctrl : m_strategyCtrls) {
existingValues.push_back(ctrl->GetValue());
}

RebuildStrategyControls();

for (int i = 0; i < std::min(oldCount, newCount); ++i) {
m_strategyCtrls[i]->SetValue(existingValues[i]);
}

for (int i = oldCount; i < newCount; ++i) {
m_strategyCtrls[i]->SetValue(2);
}
}

} // namespace Gambit::GUI
40 changes: 40 additions & 0 deletions src/gui/dlnewtable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef GAMBIT_GUI_DLNEWTABLE_H
#define GAMBIT_GUI_DLNEWTABLE_H

#include <vector>

#include <wx/dialog.h>

class wxChoice;
class wxSpinCtrl;
class wxStaticText;
class wxBoxSizer;

namespace Gambit::GUI {

class NewTableDialog : public wxDialog {
public:
explicit NewTableDialog(wxWindow *parent);

std::vector<int> GetDimensions() const;

private:
void CreateControls();
void LayoutControls();

void RebuildStrategyControls();

void OnPlayerCountChanged(wxSpinEvent &p_event);

wxSpinCtrl *m_playerCountCtrl{nullptr};

wxBoxSizer *m_topSizer{nullptr};
wxBoxSizer *m_strategyRowsSizer{nullptr};

std::vector<wxStaticText *> m_strategyLabels;
std::vector<wxSpinCtrl *> m_strategyCtrls;
};

} // namespace Gambit::GUI

#endif // GAMBIT_GUI_DLNEWTABLE_H
20 changes: 20 additions & 0 deletions src/gui/gamedoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,26 @@ class GameDocument {
void DoAddOutput(AnalysisOutput &p_list, const wxString &p_output);
};

inline GameDocument *NewTreeDocument()
{
const Game efg = NewTree();
efg->SetTitle("Untitled Extensive Game");
efg->NewPlayer()->SetLabel("Player 1");
efg->NewPlayer()->SetLabel("Player 2");
return new GameDocument(efg);
}

inline GameDocument *NewTableDocument(const std::vector<int> &p_dim)
{
const Game nfg = NewTable(p_dim);
nfg->SetTitle("Untitled Strategic Game");
int pl = 1;
for (auto player : nfg->GetPlayers()) {
player->SetLabel("Player " + std::to_string(pl++));
}
return new GameDocument(nfg);
}

class GameView {
protected:
GameDocument *m_doc;
Expand Down
25 changes: 7 additions & 18 deletions src/gui/gameframe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include "dleditmove.h"
#include "dlefglayout.h"
#include "dlefglegend.h"
#include "dlnewtable.h"

namespace Gambit::GUI {

Expand Down Expand Up @@ -611,27 +612,15 @@ void GameFrame::MakeToolbar()
// GameFrame: Menu handlers - File menu
//----------------------------------------------------------------------

void GameFrame::OnFileNewEfg(wxCommandEvent &)
{
const Game efg = NewTree();
efg->SetTitle("Untitled Extensive Game");
efg->NewPlayer()->SetLabel("Player 1");
efg->NewPlayer()->SetLabel("Player 2");
auto *doc = new GameDocument(efg);
(void)new GameFrame(nullptr, doc);
}
void GameFrame::OnFileNewEfg(wxCommandEvent &) { new GameFrame(nullptr, NewTreeDocument()); }

void GameFrame::OnFileNewNfg(wxCommandEvent &)
{
std::vector<int> dim(2);
dim[0] = 2;
dim[1] = 2;
const Game nfg = NewTable(dim);
nfg->SetTitle("Untitled Strategic Game");
nfg->GetPlayer(1)->SetLabel("Player 1");
nfg->GetPlayer(2)->SetLabel("Player 2");
auto *doc = new GameDocument(nfg);
(void)new GameFrame(nullptr, doc);
NewTableDialog dialog(this);
if (dialog.ShowModal() != wxID_OK) {
return;
}
new GameFrame(nullptr, NewTableDocument(dialog.GetDimensions()));
}

void GameFrame::OnFileOpen(wxCommandEvent &)
Expand Down
Loading
Loading