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
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,12 @@ gambit_SOURCES = \
src/gui/analysis.h \
src/gui/app.cc \
src/gui/app.h \
src/gui/editlabel.cc \
src/gui/editlabel.h \
src/gui/edittext.cc \
src/gui/edittext.h \
src/gui/labelcell.cc \
src/gui/labelcell.h \
src/gui/dlabout.cc \
src/gui/dlabout.h \
src/gui/dleditmove.cc \
Expand Down
74 changes: 61 additions & 13 deletions src/gui/dleditmove.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,24 @@
#include "gambit.h"
#include "dleditmove.h"
#include "valnumber.h"
#include "editlabel.h"

namespace Gambit::GUI {

class ActionPanel final : public wxScrolledWindow {
std::vector<wxString> m_actionProbValues;
std::vector<wxTextCtrl *> m_actionNames;
std::vector<LabelTextCtrl *> m_actionLabels;
std::vector<wxTextCtrl *> m_actionProbs;

public:
ActionPanel(wxWindow *p_parent, const GameInfoset &p_infoset);

int NumActions() const { return static_cast<int>(m_actionNames.size()); }
int NumActions() const { return static_cast<int>(m_actionLabels.size()); }

wxString GetActionName(int p_act) const;
wxString GetActionLabel(int p_act) const;
Array<Number> GetActionProbs() const;

void FocusActionLabel(int p_act) { m_actionLabels.at(p_act - 1)->SetFocus(); }
};

ActionPanel::ActionPanel(wxWindow *p_parent, const GameInfoset &p_infoset)
Expand All @@ -57,7 +60,7 @@ ActionPanel::ActionPanel(wxWindow *p_parent, const GameInfoset &p_infoset)
m_actionProbValues.reserve(p_infoset->GetActions().size());
m_actionProbs.reserve(p_infoset->GetActions().size());
}
m_actionNames.reserve(p_infoset->GetActions().size());
m_actionLabels.reserve(p_infoset->GetActions().size());

const int numColumns = isChance ? 3 : 2;

Expand All @@ -82,8 +85,9 @@ ActionPanel::ActionPanel(wxWindow *p_parent, const GameInfoset &p_infoset)
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);

auto *name =
new wxTextCtrl(this, wxID_ANY, wxString(action->GetLabel().c_str(), *wxConvCurrent));
m_actionNames.push_back(name);
new LabelTextCtrl(this, wxID_ANY, wxString(action->GetLabel().c_str(), *wxConvCurrent),
LabelCharacterPolicy::AsciiOnly);
m_actionLabels.push_back(name);
gridSizer->Add(name, 1, wxEXPAND);

if (isChance) {
Expand All @@ -110,9 +114,9 @@ ActionPanel::ActionPanel(wxWindow *p_parent, const GameInfoset &p_infoset)
SetMinSize(wxSize(FromDIP(isChance ? 400 : 300), std::min(bestSize.GetHeight(), FromDIP(250))));
}

wxString ActionPanel::GetActionName(int p_act) const
wxString ActionPanel::GetActionLabel(int p_act) const
{
return m_actionNames.at(p_act - 1)->GetValue();
return m_actionLabels.at(p_act - 1)->GetNormalizedValue();
}

Array<Number> ActionPanel::GetActionProbs() const
Expand All @@ -138,9 +142,10 @@ EditMoveDialog::EditMoveDialog(wxWindow *p_parent, const GameInfoset &p_infoset)
auto *labelSizer = new wxBoxSizer(wxHORIZONTAL);
labelSizer->Add(new wxStaticText(this, wxID_STATIC, _("Information set label")), 0,
wxALL | wxALIGN_CENTER_VERTICAL, 5);
m_infosetName =
new wxTextCtrl(this, wxID_ANY, wxString(p_infoset->GetLabel().c_str(), *wxConvCurrent));
labelSizer->Add(m_infosetName, 1, wxALL | wxEXPAND, 5);
m_infosetLabel =
new LabelTextCtrl(this, wxID_ANY, wxString(p_infoset->GetLabel().c_str(), *wxConvCurrent),
LabelCharacterPolicy::AsciiOnly);
labelSizer->Add(m_infosetLabel, 1, wxALL | wxEXPAND, 5);
topSizer->Add(labelSizer, 0, wxEXPAND);

{
Expand Down Expand Up @@ -195,8 +200,51 @@ EditMoveDialog::EditMoveDialog(wxWindow *p_parent, const GameInfoset &p_infoset)
Bind(wxEVT_BUTTON, &EditMoveDialog::OnOK, this, wxID_OK);
}

bool EditMoveDialog::ValidateLabels()
{
const wxString infosetLabel = m_infosetLabel->GetNormalizedValue();
if (!infosetLabel.empty()) {
for (const auto &infoset : m_infoset->GetPlayer()->GetInfosets()) {
if (infoset != m_infoset && infoset->GetLabel() == infosetLabel) {
wxRichMessageDialog(this, _("Information set label must be unique for the player."),
_("Error"), wxOK | wxCENTRE | wxICON_ERROR)
.ShowModal();
m_infosetLabel->SetFocus();
return false;
}
}
}

std::set<wxString> actionLabels;
for (int act = 1; act <= m_actionPanel->NumActions(); ++act) {
const wxString actionLabel = m_actionPanel->GetActionLabel(act);
if (actionLabel.empty()) {
wxRichMessageDialog(this, _("Action labels cannot be empty."), _("Error"),
wxOK | wxCENTRE | wxICON_ERROR)
.ShowModal();
m_actionPanel->FocusActionLabel(act);
return false;
}

if (contains(actionLabels, actionLabel)) {
wxRichMessageDialog(this, _("Action labels must be unique within the information set."),
_("Error"), wxOK | wxCENTRE | wxICON_ERROR)
.ShowModal();
m_actionPanel->FocusActionLabel(act);
return false;
}

actionLabels.insert(actionLabel);
}
return true;
}

void EditMoveDialog::OnOK(wxCommandEvent &p_event)
{
if (!ValidateLabels()) {
return;
}

if (!m_infoset->IsChanceInfoset()) {
p_event.Skip();
return;
Expand All @@ -215,9 +263,9 @@ void EditMoveDialog::OnOK(wxCommandEvent &p_event)

int EditMoveDialog::NumActions() const { return m_actionPanel->NumActions(); }

wxString EditMoveDialog::GetActionName(int p_act) const
wxString EditMoveDialog::GetActionLabel(int p_act) const
{
return m_actionPanel->GetActionName(p_act);
return m_actionPanel->GetActionLabel(p_act);
}

Array<Number> EditMoveDialog::GetActionProbs() const { return m_actionPanel->GetActionProbs(); }
Expand Down
9 changes: 6 additions & 3 deletions src/gui/dleditmove.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,30 @@
#ifndef GAMBIT_GUI_DLEDITMOVE_H
#define GAMBIT_GUI_DLEDITMOVE_H

#include "editlabel.h"

namespace Gambit::GUI {
class ActionPanel;

class EditMoveDialog final : public wxDialog {
GameInfoset m_infoset;
wxChoice *m_player;
wxTextCtrl *m_infosetName;
LabelTextCtrl *m_infosetLabel;
ActionPanel *m_actionPanel;

bool ValidateLabels();
void OnOK(wxCommandEvent &);

public:
// Lifecycle
EditMoveDialog(wxWindow *p_parent, const GameInfoset &p_infoset);

// Data access (only valid when ShowModal() returns with wxID_OK)
wxString GetInfosetName() const { return m_infosetName->GetValue(); }
wxString GetInfosetLabel() const { return m_infosetLabel->GetNormalizedValue(); }
int GetPlayer() const { return (m_player->GetSelection() + 1); }

int NumActions() const;
wxString GetActionName(int p_act) const;
wxString GetActionLabel(int p_act) const;
Array<Number> GetActionProbs() const;
};
} // namespace Gambit::GUI
Expand Down
30 changes: 24 additions & 6 deletions src/gui/dleditnode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif // WX_PRECOMP
#include <wx/richmsgdlg.h>
#include "gambit.h"
#include "dleditnode.h"

Expand All @@ -39,9 +40,9 @@ EditNodeDialog::EditNodeDialog(wxWindow *p_parent, const GameNode &p_node)

auto *labelSizer = new wxBoxSizer(wxHORIZONTAL);
labelSizer->Add(new wxStaticText(this, wxID_STATIC, _("Node label")), 0, wxALL | wxCENTER, 5);
m_nodeName =
new wxTextCtrl(this, wxID_ANY, wxString(m_node->GetLabel().c_str(), *wxConvCurrent));
labelSizer->Add(m_nodeName, 1, wxALL | wxCENTER | wxEXPAND, 5);
m_nodeLabel =
new LabelTextCtrl(this, wxID_ANY, wxString(m_node->GetLabel().c_str(), *wxConvCurrent));
labelSizer->Add(m_nodeLabel, 1, wxALL | wxCENTER | wxEXPAND, 5);
topSizer->Add(labelSizer, 0, wxALL | wxEXPAND, 5);

auto *infosetSizer = new wxBoxSizer(wxHORIZONTAL);
Expand Down Expand Up @@ -153,15 +154,32 @@ EditNodeDialog::EditNodeDialog(wxWindow *p_parent, const GameNode &p_node)

wxTopLevelWindowBase::Layout();
CenterOnParent();

Bind(wxEVT_BUTTON, &EditNodeDialog::OnOK, this, wxID_OK);
}

void EditNodeDialog::OnOK(wxCommandEvent &p_event)
{
const wxString nodeLabel = m_nodeLabel->GetNormalizedValue();
if (!nodeLabel.empty()) {
for (const auto &node : m_node->GetGame()->GetNodes()) {
if (node != m_node && node->GetLabel() == nodeLabel) {
wxRichMessageDialog(this, _("Node label must be unique in the game."), _("Error"),
wxOK | wxCENTRE | wxICON_ERROR)
.ShowModal();
m_nodeLabel->SetFocus();
return;
}
}
}
p_event.Skip();
}

GameInfoset EditNodeDialog::GetInfoset() const
{
if (m_infoset->GetSelection() == 0) {
return nullptr;
}
else {
return m_infosetList[m_infoset->GetSelection()];
}
return m_infosetList[m_infoset->GetSelection()];
}
} // namespace Gambit::GUI
8 changes: 6 additions & 2 deletions src/gui/dleditnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,23 @@
#ifndef GAMBIT_GUI_DLEDITNODE_H
#define GAMBIT_GUI_DLEDITNODE_H

#include "editlabel.h"

namespace Gambit::GUI {
class EditNodeDialog final : public wxDialog {
GameNode m_node;
wxTextCtrl *m_nodeName;
LabelTextCtrl *m_nodeLabel;
wxChoice *m_outcome, *m_infoset;
Array<GameInfoset> m_infosetList;

void OnOK(wxCommandEvent &);

public:
// Lifecycle
EditNodeDialog(wxWindow *p_parent, const GameNode &p_node);

// Data access (only valid when ShowModal() returns with wxID_OK)
wxString GetNodeName() const { return m_nodeName->GetValue(); }
wxString GetNodeLabel() const { return m_nodeLabel->GetValue(); }
int GetOutcome() const { return m_outcome->GetSelection(); }
GameInfoset GetInfoset() const;
};
Expand Down
7 changes: 4 additions & 3 deletions src/gui/dlexcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@
#define DLEXCEPT_H

#include <wx/wx.h>
#include <wx/richmsgdlg.h>

namespace Gambit::GUI {

// A general-purpose dialog box to display the description of an internal exception.
class ExceptionDialog final : public wxMessageDialog {
class ExceptionDialog final : public wxRichMessageDialog {
public:
ExceptionDialog(wxWindow *p_parent, const std::string &p_message)
: wxMessageDialog(p_parent, wxString(p_message.c_str(), *wxConvCurrent),
wxT("Internal exception in Gambit"), wxICON_ERROR | wxCANCEL)
: wxRichMessageDialog(p_parent, wxString(p_message.c_str(), *wxConvCurrent),
wxT("Internal exception in Gambit"), wxOK | wxCENTRE | wxICON_ERROR)
{
}
};
Expand Down
Loading
Loading