penguins  1.0.0
game_end_dialog.cc
Go to the documentation of this file.
1 #include "gui/game_end_dialog.hh"
2 #include "game.h"
3 #include <algorithm>
4 #include <wx/event.h>
5 #include <wx/font.h>
6 #include <wx/gdicmn.h>
7 #include <wx/grid.h>
8 #include <wx/sizer.h>
9 #include <wx/statline.h>
10 #include <wx/stattext.h>
11 #include <wx/string.h>
12 #include <wx/vector.h>
13 
15  wxWindow* parent, wxWindowID id, const Game* game, const wxVector<wxString>& player_names
16 )
17 : wxDialog(parent, id, "Game summary", wxDefaultPosition, wxDefaultSize) {
19 
20  wxVector<int> players_by_score(game->players_count);
21  for (int i = 0; i < game->players_count; i++) {
22  players_by_score[i] = i;
23  }
24  std::sort(
25  players_by_score.begin(),
26  players_by_score.end(),
27  [&](const int& a, const int& b) -> bool {
28  return game_get_player(game, a)->points > game_get_player(game, b)->points;
29  }
30  );
31 
32  int winners_count = 0;
33  int max_score = 0;
34  for (int i = 0; i < game->players_count; i++) {
35  Player* player = game_get_player(game, players_by_score.at(i));
36  if (i == 0) {
37  max_score = player->points;
38  }
39  if (player->points >= max_score) {
40  winners_count += 1;
41  } else {
42  break;
43  }
44  }
45 
46  wxString winners_str;
47  if (winners_count > 1) {
48  if (winners_count == game->players_count) {
49  winners_str << "It is a tie between ";
50  } else {
51  winners_str << "The winners are ";
52  }
53  for (int i = 0; i < winners_count; i++) {
54  winners_str << player_names.at(players_by_score.at(i));
55  if (i < winners_count - 2) {
56  winners_str << ", ";
57  } else if (i < winners_count - 1) {
58  winners_str << " and ";
59  }
60  }
61  winners_str << "!";
62  } else if (winners_count == 1) {
63  winners_str << "The winner is " << player_names.at(players_by_score.at(0)) << "!";
64  } else {
65  winners_str << "There are no winners???";
66  }
67 
68  auto content_vbox = new wxBoxSizer(wxVERTICAL);
69 
70  this->header_label = new wxStaticText(this, wxID_ANY, "The game has ended");
71  this->header_label->SetFont(this->header_label->GetFont().MakeBold().Scale(1.4f));
72  content_vbox->Add(this->header_label, wxSizerFlags().Centre().DoubleBorder(wxBOTTOM));
73 
74  this->winner_label = new wxStaticText(this, wxID_ANY, winners_str);
75  this->winner_label->SetFont(this->winner_label->GetFont().MakeBold().Scale(1.2f));
76  content_vbox->Add(this->winner_label, wxSizerFlags().Centre().DoubleBorder(wxBOTTOM));
77 
78  this->grid =
81  this->grid->EnableEditing(false);
84  this->grid->DisableDragGridSize();
85  this->grid->DisableDragRowSize();
86  this->grid->DisableDragColSize();
87 
88  this->grid->HideRowLabels();
89  this->grid->SetColLabelValue(0, "Name");
90  this->grid->SetColLabelValue(1, "Score");
91  this->grid->SetColLabelValue(2, "Moves");
93  for (int j = 0; j < game->players_count; j++) {
94  int i = players_by_score.at(j);
95  Player* player = game_get_player(game, i);
96  this->grid->SetCellValue(j, 0, player_names.at(i));
97  this->grid->SetCellValue(j, 1, wxString::Format("%d", player->points));
98  this->grid->SetCellValue(j, 2, wxString::Format("%d", player->moves_count));
99  }
100  this->grid->AutoSize();
101  content_vbox->Add(this->grid, wxSizerFlags().Expand());
102 
103  auto outer_vbox = new wxBoxSizer(wxVERTICAL);
104  outer_vbox->Add(content_vbox, wxSizerFlags().Expand().DoubleBorder());
106  this->SetEscapeId(wxID_OK);
107  outer_vbox->Add(new wxStaticLine(this), wxSizerFlags().Expand());
108  wxSizerFlags buttons_sizer_flags = wxSizerFlags().Expand().DoubleBorder(wxALL);
109 #ifdef __WXGTK__
110  buttons_sizer_flags.DoubleBorder(wxTOP | wxBOTTOM);
111 #endif
112  outer_vbox->Add(this->buttons_sizer, buttons_sizer_flags);
113  this->SetSizerAndFit(outer_vbox);
114 }
115 
116 void GameEndDialog::on_ok(wxCommandEvent& WXUNUSED(event)) {
117  this->EndModal(wxID_OK);
118 }
119 
121  wxWindow* parent,
122  wxWindowID id,
123  const wxPoint& pos,
124  const wxSize& size,
125  long style,
126  const wxString& name
127 )
128 : wxGrid(parent, id, pos, size, style, name) {
129  this->Bind(wxEVT_SIZE, &GameEndDialogGrid::on_resize, this);
130 }
131 
133  wxEventType type = event.GetEventType();
134  // wxGrid by default handles keyboard events for Tab, Return and other such
135  // keys for keyboard navigation within the table. In my case the table is
136  // purely informative and most of the interaction with it is disabled, so
137  // this is not particularly useful and even annoying because I want the
138  // Return key, for example, to be handled by the dialog (to close it). I
139  // guess this is not the prettiest way to disable the handling of these
140  // events, but oh well.
141  if (type == wxEVT_KEY_DOWN || type == wxEVT_KEY_UP || type == wxEVT_CHAR) {
142  event.Skip(); // Will cause the native handler to be called
143  return true; // Will skip handlers defined on this window
144  }
145  return wxGrid::TryBefore(event);
146 }
147 
149  int ncols = this->GetNumberCols();
150  int cols_total_size = 0;
151  for (int i = 0; i < ncols; i++) {
152  cols_total_size += this->GetColSize(i);
153  }
154  int cols_available_size = this->GetClientSize().x;
155  int cols_free_size = cols_available_size - cols_total_size;
156  int cols_ideal_size = cols_available_size / ncols;
157  int growable_cols = 0;
158  int growable_cols_total_size = 0;
159  for (int i = 0; i < ncols; i++) {
160  if (this->GetColSize(i) < cols_ideal_size) {
161  growable_cols += 1;
162  growable_cols_total_size += this->GetColSize(i);
163  }
164  }
165  if (growable_cols == 0) {
166  return;
167  }
168  this->BeginBatch();
169  // Width distribution algorithm was taken from
170  // <https://github.com/wxWidgets/wxWidgets/blob/v3.2.2.1/src/common/statbar.cpp#L200-L213>.
171  growable_cols_total_size += cols_free_size;
172  for (int i = ncols - 1, grown = growable_cols; i >= 0; i--) {
173  if (this->GetColSize(i) < cols_ideal_size) {
174  int size = growable_cols_total_size / grown;
175  this->SetColSize(i, size);
176  growable_cols_total_size -= size;
177  grown -= 1;
178  }
179  }
180  this->EndBatch();
181 }
182 
184  event.Skip();
185  // HACK: Don't really like this, we need a better way of getting the size
186  // allocated by the sizer.
187  this->CallAfter(&GameEndDialogGrid::equally_size_columns);
188  // this->AutoSize();
189  // this->equally_size_columns();
190 }
GameEndDialogGrid(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0, const wxString &name=wxGridNameStr)
virtual bool TryBefore(wxEvent &event) override
void on_resize(wxSizeEvent &event)
void on_ok(wxCommandEvent &event)
wxStdDialogButtonSizer * buttons_sizer
wxStaticText * header_label
GameEndDialogGrid * grid
wxStaticText * winner_label
GameEndDialog(wxWindow *parent, wxWindowID id, const Game *game, const wxVector< wxString > &player_names)
void SetEscapeId(int id)
void Centre(int direction=wxBOTH)
virtual void EndModal(int retCode)
wxStdDialogButtonSizer * CreateStdDialogButtonSizer(long flags)
void Bind(const EventTag &eventType, Functor functor, int id=wxID_ANY, int lastId=wxID_ANY, wxObject *userData=NULL)
wxFont & MakeBold()
wxFont & Scale(float x)
bool CreateGrid(int numRows, int numCols, wxGridSelectionModes selmode=wxGridSelectCells)
void EnableEditing(bool edit)
void EndBatch()
wxGridSelectNone
void AutoSize()
void DisableDragColSize()
void SetColLabelValue(int col, const wxString &value)
void SetCellHighlightROPenWidth(int width)
void DisableDragRowSize()
void SetCellHighlightPenWidth(int width)
void DisableDragGridSize()
void SetCellValue(int row, int col, const wxString &s)
int GetColSize(int col) const
void HideRowLabels()
void SetColSize(int col, int width)
int GetNumberCols() const
void SetDefaultCellAlignment(int horiz, int vert)
void BeginBatch()
wxSizerFlags & Expand()
wxSizerFlags & DoubleBorder(int direction=wxALL)
wxUniChar at(size_t n) const
static wxString Format(const wxString &format,...)
void SetSizerAndFit(wxSizer *sizer, bool deleteOld=true)
virtual bool SetFont(const wxFont &font)
wxFont GetFont() const
wxVERTICAL
wxALIGN_CENTRE
#define wxOK
wxALL
wxBOTTOM
wxTOP
wxID_ANY
wxID_OK
wxBORDER_SIMPLE
Player * game_get_player(const Game *self, int idx)
Returns a pointer to the player at the given index. Fails if the index isn't within the bounds of the...
Definition: game.h:394
The core of the unified game logic library, contains the Game struct.
const wxSize wxDefaultSize
const wxPoint wxDefaultPosition
wxEventType wxEVT_KEY_UP
wxEventType wxEVT_BUTTON
int wxEventType
wxEventType wxEVT_KEY_DOWN
wxEventType wxEVT_CHAR
wxEventType wxEVT_SIZE
The central struct of the application, holds the game data and settings.
Definition: game.h:237
int players_count
Use game_set_players_count for setting this.
Definition: game.h:251
Holds the data of the players of the Game.
Definition: game.h:68
int moves_count
The number of moves (penguin placements and movements) made by the player.
Definition: game.h:81
int points
The score of the player, i.e. the number of collected fish.
Definition: game.h:74
int wxWindowID