1 //
2 // This file is part of Gambit
3 // Copyright (c) 1994-2016, The Gambit Project (http://www.gambit-project.org)
4 //
5 // FILE: src/gui/efgpanel.cc
6 // Main viewing panel for extensive forms
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 //
22
23 #include <wx/wxprec.h>
24 #ifndef WX_PRECOMP
25 #include <wx/wx.h>
26 #endif // WX_PRECOMP
27 #include <wx/dnd.h> // for drag-and-drop features
28 #include <wx/image.h> // for creating drag-and-drop cursor
29 #include <wx/print.h> // for printing support
30 #include <wx/colordlg.h> // for picking player colors
31 #if wxCHECK_VERSION(2, 9, 0)
32 #include <wx/dcsvg.h> // for SVG output
33 #else
34 #include "dcsvg.h"
35 #endif /* wxCHECK_VERSION */
36
37 #include "efgpanel.h"
38 #include "efgdisplay.h" // FIXME: communicate with tree window via events.
39 #include "menuconst.h"
40 #include "edittext.h"
41
42 //=====================================================================
43 // class gbtBehavDominanceToolbar
44 //=====================================================================
45
46 //!
47 //! This panel serves as a toolbar for interactively viewing
48 //! dominance information on extensive forms.
49 //!
50 class gbtBehavDominanceToolbar : public wxPanel, public gbtGameView {
51 private:
52 wxButton *m_topButton, *m_prevButton, *m_nextButton, *m_allButton;
53 wxStaticText *m_level;
54
55 // Overriding gbtGameView members
56 void OnUpdate(void);
57
58 // Event handlers
59 void OnStrength(wxCommandEvent &);
60 void OnTopLevel(wxCommandEvent &);
61 void OnPreviousLevel(wxCommandEvent &);
62 void OnNextLevel(wxCommandEvent &);
63 void OnLastLevel(wxCommandEvent &);
64 void OnShowReachable(wxCommandEvent &);
65
66 public:
67 gbtBehavDominanceToolbar(wxWindow *p_parent, gbtGameDocument *p_doc);
~gbtBehavDominanceToolbar()68 virtual ~gbtBehavDominanceToolbar() { }
69 };
70
71 #include "bitmaps/next.xpm"
72 #include "bitmaps/prev.xpm"
73 #include "bitmaps/tobegin.xpm"
74 #include "bitmaps/toend.xpm"
75
gbtBehavDominanceToolbar(wxWindow * p_parent,gbtGameDocument * p_doc)76 gbtBehavDominanceToolbar::gbtBehavDominanceToolbar(wxWindow *p_parent,
77 gbtGameDocument *p_doc)
78 : wxPanel(p_parent, -1), gbtGameView(p_doc)
79 {
80 wxBoxSizer *topSizer = new wxBoxSizer(wxHORIZONTAL);
81
82 topSizer->Add(new wxStaticText(this, wxID_STATIC,
83 wxT("Hide actions which are ")),
84 0, wxALL | wxALIGN_CENTER, 5);
85
86 wxString domChoices[] = { wxT("strictly"), wxT("strictly or weakly") };
87 wxChoice *choice = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize,
88 2, domChoices);
89 choice->SetSelection(0);
90 Connect(choice->GetId(), wxEVT_COMMAND_CHOICE_SELECTED,
91 wxCommandEventHandler(gbtBehavDominanceToolbar::OnStrength));
92 topSizer->Add(choice, 0, wxALL | wxALIGN_CENTER, 5);
93
94 topSizer->Add(new wxStaticText(this, wxID_STATIC, wxT("dominated:")),
95 0, wxALL | wxALIGN_CENTER, 5);
96
97 m_topButton = new wxBitmapButton(this, -1, wxBitmap(tobegin_xpm));
98 m_topButton->SetToolTip(_("Show all strategies"));
99 Connect(m_topButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
100 wxCommandEventHandler(gbtBehavDominanceToolbar::OnTopLevel));
101 topSizer->Add(m_topButton, 0, wxALL | wxALIGN_CENTER, 5);
102
103 m_prevButton = new wxBitmapButton(this, -1, wxBitmap(prev_xpm));
104 m_prevButton->SetToolTip(_("Previous round of elimination"));
105 Connect(m_prevButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
106 wxCommandEventHandler(gbtBehavDominanceToolbar::OnPreviousLevel));
107 topSizer->Add(m_prevButton, 0, wxALL | wxALIGN_CENTER, 5);
108
109 m_level = new wxStaticText(this, wxID_STATIC,
110 wxT("All actions shown"),
111 wxDefaultPosition, wxDefaultSize,
112 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
113 topSizer->Add(m_level, 0, wxALL | wxALIGN_CENTER, 5);
114
115 m_nextButton = new wxBitmapButton(this, -1, wxBitmap(next_xpm));
116 m_nextButton->SetToolTip(_("Next round of elimination"));
117 Connect(m_nextButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
118 wxCommandEventHandler(gbtBehavDominanceToolbar::OnNextLevel));
119 topSizer->Add(m_nextButton, 0, wxALL | wxALIGN_CENTER, 5);
120
121 m_allButton = new wxBitmapButton(this, -1, wxBitmap(toend_xpm));
122 m_allButton->SetToolTip(_("Eliminate iteratively"));
123 Connect(m_allButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
124 wxCommandEventHandler(gbtBehavDominanceToolbar::OnLastLevel));
125 topSizer->Add(m_allButton, 0, wxALL | wxALIGN_CENTER, 5);
126
127 wxCheckBox *showReachable = new wxCheckBox(this, -1,
128 wxT("Show only reachable nodes"));
129 showReachable->SetValue(m_doc->GetStyle().RootReachable());
130 Connect(showReachable->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED,
131 wxCommandEventHandler(gbtBehavDominanceToolbar::OnShowReachable));
132 topSizer->Add(showReachable, 0, wxALL | wxALIGN_CENTER, 5);
133
134 SetSizer(topSizer);
135 Layout();
136 }
137
OnStrength(wxCommandEvent & p_event)138 void gbtBehavDominanceToolbar::OnStrength(wxCommandEvent &p_event)
139 {
140 m_doc->SetBehavElimStrength(p_event.GetSelection() == 0);
141 }
142
OnTopLevel(wxCommandEvent &)143 void gbtBehavDominanceToolbar::OnTopLevel(wxCommandEvent &)
144 {
145 m_doc->TopBehavElimLevel();
146 }
147
OnPreviousLevel(wxCommandEvent &)148 void gbtBehavDominanceToolbar::OnPreviousLevel(wxCommandEvent &)
149 {
150 m_doc->PreviousBehavElimLevel();
151 }
152
OnNextLevel(wxCommandEvent &)153 void gbtBehavDominanceToolbar::OnNextLevel(wxCommandEvent &)
154 {
155 m_doc->NextBehavElimLevel();
156 }
157
OnLastLevel(wxCommandEvent &)158 void gbtBehavDominanceToolbar::OnLastLevel(wxCommandEvent &)
159 {
160 while (m_doc->NextBehavElimLevel());
161 }
162
OnShowReachable(wxCommandEvent &)163 void gbtBehavDominanceToolbar::OnShowReachable(wxCommandEvent &)
164 {
165 gbtStyle style = m_doc->GetStyle();
166 style.SetRootReachable(!style.RootReachable());
167 m_doc->SetStyle(style);
168 }
169
OnUpdate(void)170 void gbtBehavDominanceToolbar::OnUpdate(void)
171 {
172 m_topButton->Enable(m_doc->GetBehavElimLevel() > 1);
173 m_prevButton->Enable(m_doc->GetBehavElimLevel() > 1);
174 m_nextButton->Enable(m_doc->CanBehavElim());
175 m_allButton->Enable(m_doc->CanBehavElim());
176 if (m_doc->GetBehavElimLevel() == 1) {
177 m_level->SetLabel(wxT("All actions shown"));
178 }
179 else if (m_doc->GetBehavElimLevel() == 2) {
180 m_level->SetLabel(wxT("Eliminated 1 level"));
181 }
182 else {
183 m_level->SetLabel(wxString::Format(wxT("Eliminated %d levels"),
184 m_doc->GetBehavElimLevel()-1));
185 }
186 GetSizer()->Layout();
187 }
188
189 #include "bitmaps/color.xpm"
190 #include "bitmaps/person.xpm"
191
192 class gbtTreePlayerIcon : public wxStaticBitmap {
193 private:
194 int m_player;
195
196 // Event handlers
197 void OnLeftClick(wxMouseEvent &);
198
199 public:
200 gbtTreePlayerIcon(wxWindow *p_parent, int p_player);
201
202 DECLARE_EVENT_TABLE()
203 };
204
BEGIN_EVENT_TABLE(gbtTreePlayerIcon,wxStaticBitmap)205 BEGIN_EVENT_TABLE(gbtTreePlayerIcon, wxStaticBitmap)
206 EVT_LEFT_DOWN(gbtTreePlayerIcon::OnLeftClick)
207 END_EVENT_TABLE()
208
209 gbtTreePlayerIcon::gbtTreePlayerIcon(wxWindow *p_parent, int p_player)
210 : wxStaticBitmap(p_parent, -1, wxBitmap(person_xpm)), m_player(p_player)
211 { }
212
OnLeftClick(wxMouseEvent &)213 void gbtTreePlayerIcon::OnLeftClick(wxMouseEvent &)
214 {
215 wxBitmap bitmap(person_xpm);
216
217 #if defined( __WXMSW__) or defined(__WXMAC__)
218 wxImage image = bitmap.ConvertToImage();
219 #else
220 wxIcon image;
221 image.CopyFromBitmap(bitmap);
222 #endif // _WXMSW__
223
224 wxTextDataObject textData(wxString::Format(wxT("P%d"), m_player));
225 wxDropSource source(textData, this, image, image, image);
226 source.DoDragDrop(wxDrag_DefaultMove);
227 }
228
229 class gbtTreePlayerPanel : public wxPanel {
230 private:
231 gbtGameDocument *m_doc;
232 int m_player;
233 gbtEditableText *m_playerLabel;
234 wxStaticText *m_payoff, *m_nodeValue, *m_nodeProb;
235 wxStaticText *m_infosetValue, *m_infosetProb, *m_belief;
236
237 /// @name Event handlers
238 //@{
239 /// The set color icon is clicked
240 void OnSetColor(wxCommandEvent &);
241 /// Start the editing of the player label
242 void OnEditPlayerLabel(wxCommandEvent &);
243 /// End the editing of the player label after enter is pressed
244 void OnAcceptPlayerLabel(wxCommandEvent &);
245 /// Process a keypress event
246 void OnChar(wxKeyEvent &);
247 //@}
248
249 public:
250 gbtTreePlayerPanel(wxWindow *, gbtGameDocument *, int p_player);
251
252 void OnUpdate(void);
253 void PostPendingChanges(void);
254
255 DECLARE_EVENT_TABLE()
256 };
257
BEGIN_EVENT_TABLE(gbtTreePlayerPanel,wxPanel)258 BEGIN_EVENT_TABLE(gbtTreePlayerPanel, wxPanel)
259 EVT_CHAR(gbtTreePlayerPanel::OnChar)
260 END_EVENT_TABLE()
261
262 gbtTreePlayerPanel::gbtTreePlayerPanel(wxWindow *p_parent,
263 gbtGameDocument *p_doc,
264 int p_player)
265 : wxPanel(p_parent, -1), m_doc(p_doc), m_player(p_player)
266 {
267 wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
268
269 wxBoxSizer *labelSizer = new wxBoxSizer(wxHORIZONTAL);
270
271 wxStaticBitmap *playerIcon = new gbtTreePlayerIcon(this, m_player);
272 labelSizer->Add(playerIcon, 0, wxALL | wxALIGN_CENTER, 0);
273
274 wxBitmapButton *setColorIcon =
275 new wxBitmapButton(this, -1, wxBitmap(color_xpm),
276 wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
277 setColorIcon->SetToolTip(_("Change the color for this player"));
278
279 labelSizer->Add(setColorIcon, 0, wxALL | wxALIGN_CENTER, 0);
280 Connect(setColorIcon->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
281 wxCommandEventHandler(gbtTreePlayerPanel::OnSetColor));
282
283 m_playerLabel = new gbtEditableText(this, -1, wxT(""),
284 wxDefaultPosition, wxSize(125, -1));
285 m_playerLabel->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD));
286 labelSizer->Add(m_playerLabel, 1, wxLEFT | wxEXPAND, 10);
287 Connect(m_playerLabel->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
288 wxCommandEventHandler(gbtTreePlayerPanel::OnEditPlayerLabel));
289 Connect(m_playerLabel->GetId(), wxEVT_COMMAND_TEXT_ENTER,
290 wxCommandEventHandler(gbtTreePlayerPanel::OnAcceptPlayerLabel));
291
292 topSizer->Add(labelSizer, 0, wxALL, 0);
293
294 m_payoff = new wxStaticText(this, wxID_STATIC, wxT("Payoff:"),
295 wxDefaultPosition, wxDefaultSize,
296 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
297 m_payoff->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL));
298 topSizer->Add(m_payoff, 0, wxALL | wxEXPAND, 0);
299 topSizer->Show(m_payoff, false);
300
301 m_nodeValue = new wxStaticText(this, wxID_STATIC, wxT("Node value:"),
302 wxDefaultPosition, wxDefaultSize,
303 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
304 m_nodeValue->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL));
305 topSizer->Add(m_nodeValue, 0, wxALL | wxEXPAND, 0);
306 topSizer->Show(m_nodeValue, false);
307
308 m_nodeProb = new wxStaticText(this, wxID_STATIC, wxT("Node reached:"),
309 wxDefaultPosition, wxDefaultSize,
310 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
311 m_nodeProb->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL));
312 topSizer->Add(m_nodeProb, 0, wxALL | wxEXPAND, 0);
313 topSizer->Show(m_nodeProb, false);
314
315 m_infosetValue = new wxStaticText(this, wxID_STATIC, wxT("Infoset value:"),
316 wxDefaultPosition, wxDefaultSize,
317 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
318 m_infosetValue->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL));
319 topSizer->Add(m_infosetValue, 0, wxALL | wxEXPAND, 0);
320 topSizer->Show(m_infosetValue, false);
321
322 m_infosetProb = new wxStaticText(this, wxID_STATIC, wxT("Infoset reached:"),
323 wxDefaultPosition, wxDefaultSize,
324 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
325 m_infosetProb->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL));
326 topSizer->Add(m_infosetProb, 0, wxALL | wxEXPAND, 0);
327 topSizer->Show(m_infosetProb, false);
328
329 m_belief = new wxStaticText(this, wxID_STATIC, wxT("Belief:"),
330 wxDefaultPosition, wxDefaultSize,
331 wxALIGN_CENTER | wxST_NO_AUTORESIZE);
332 m_belief->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL));
333 topSizer->Add(m_belief, 0, wxALL | wxEXPAND, 0);
334 topSizer->Show(m_belief, false);
335
336 SetSizer(topSizer);
337 topSizer->SetSizeHints(this);
338 topSizer->Fit(this);
339 Layout();
340 OnUpdate();
341 }
342
OnUpdate(void)343 void gbtTreePlayerPanel::OnUpdate(void)
344 {
345 if (!m_doc->IsTree()) return;
346
347 wxColour color = m_doc->GetStyle().GetPlayerColor(m_player);
348
349 m_playerLabel->SetForegroundColour(color);
350 m_playerLabel->SetValue(wxString(m_doc->GetGame()->GetPlayer(m_player)->GetLabel().c_str(),
351 *wxConvCurrent));
352
353 m_payoff->SetForegroundColour(color);
354 if (m_doc->GetCurrentProfile() > 0) {
355 std::string pay = m_doc->GetProfiles().GetPayoff(m_player);
356 m_payoff->SetLabel(wxT("Payoff: ") +
357 wxString(pay.c_str(), *wxConvCurrent));
358 GetSizer()->Show(m_payoff, true);
359
360 Gambit::GameNode node = m_doc->GetSelectNode();
361
362 if (node) {
363 m_nodeValue->SetForegroundColour(color);
364 std::string value = m_doc->GetProfiles().GetNodeValue(node, m_player);
365 m_nodeValue->SetLabel(wxT("Node value: ") +
366 wxString(value.c_str(), *wxConvCurrent));
367 GetSizer()->Show(m_nodeValue, true);
368
369 if (node->GetInfoset() && node->GetPlayer()->GetNumber() == m_player) {
370 m_nodeProb->SetForegroundColour(color);
371 std::string value = m_doc->GetProfiles().GetRealizProb(node);
372 m_nodeProb->SetLabel(wxT("Node reached: ") +
373 wxString(value.c_str(), *wxConvCurrent));
374 GetSizer()->Show(m_nodeProb, true);
375
376 m_infosetValue->SetForegroundColour(color);
377 value = m_doc->GetProfiles().GetInfosetValue(node);
378 m_infosetValue->SetLabel(wxT("Infoset value: ") +
379 wxString(value.c_str(), *wxConvCurrent));
380 GetSizer()->Show(m_infosetValue, true);
381
382 m_infosetProb->SetForegroundColour(color);
383 value = m_doc->GetProfiles().GetInfosetProb(node);
384 m_infosetProb->SetLabel(wxT("Infoset reached: ") +
385 wxString(value.c_str(), *wxConvCurrent));
386 GetSizer()->Show(m_infosetProb, true);
387
388 m_belief->SetForegroundColour(color);
389 value = m_doc->GetProfiles().GetBeliefProb(node);
390 m_belief->SetLabel(wxT("Belief: ") +
391 wxString(value.c_str(), *wxConvCurrent));
392 GetSizer()->Show(m_belief, true);
393 }
394 else {
395 GetSizer()->Show(m_nodeProb, false);
396 GetSizer()->Show(m_infosetValue, false);
397 GetSizer()->Show(m_infosetProb, false);
398 GetSizer()->Show(m_belief, false);
399 }
400 }
401 else {
402 GetSizer()->Show(m_nodeValue, false);
403 }
404 }
405 else {
406 GetSizer()->Show(m_payoff, false);
407 GetSizer()->Show(m_nodeValue, false);
408 GetSizer()->Show(m_nodeProb, false);
409 GetSizer()->Show(m_infosetValue, false);
410 GetSizer()->Show(m_infosetProb, false);
411 GetSizer()->Show(m_belief, false);
412 }
413
414 GetSizer()->Layout();
415 GetSizer()->SetSizeHints(this);
416 GetSizer()->Fit(this);
417 }
418
OnChar(wxKeyEvent & p_event)419 void gbtTreePlayerPanel::OnChar(wxKeyEvent &p_event)
420 {
421 if (p_event.GetKeyCode() == WXK_ESCAPE) {
422 m_playerLabel->EndEdit(false);
423 }
424 else {
425 p_event.Skip();
426 }
427 }
428
OnSetColor(wxCommandEvent &)429 void gbtTreePlayerPanel::OnSetColor(wxCommandEvent &)
430 {
431 wxColourData data;
432 data.SetColour(m_doc->GetStyle().GetPlayerColor(m_player));
433 wxColourDialog dialog(this, &data);
434 dialog.SetTitle(wxString::Format(_("Choose color for player %d"),
435 m_player));
436
437 if (dialog.ShowModal() == wxID_OK) {
438 wxColour color = dialog.GetColourData().GetColour();
439 gbtStyle style = m_doc->GetStyle();
440 style.SetPlayerColor(m_player, color);
441 m_doc->SetStyle(style);
442 }
443 }
444
OnEditPlayerLabel(wxCommandEvent &)445 void gbtTreePlayerPanel::OnEditPlayerLabel(wxCommandEvent &)
446 {
447 m_doc->PostPendingChanges();
448 m_playerLabel->BeginEdit();
449 }
450
OnAcceptPlayerLabel(wxCommandEvent &)451 void gbtTreePlayerPanel::OnAcceptPlayerLabel(wxCommandEvent &)
452 {
453 m_doc->DoSetPlayerLabel(m_doc->GetGame()->GetPlayer(m_player),
454 m_playerLabel->GetValue());
455 }
456
PostPendingChanges(void)457 void gbtTreePlayerPanel::PostPendingChanges(void)
458 {
459 if (m_playerLabel->IsEditing()) {
460 m_playerLabel->EndEdit(true);
461 m_doc->DoSetPlayerLabel(m_doc->GetGame()->GetPlayer(m_player),
462 m_playerLabel->GetValue());
463 }
464 }
465
466 #include "bitmaps/dice.xpm"
467
468 class gbtTreeChanceIcon : public wxStaticBitmap {
469 private:
470 // Event handlers
471 void OnLeftClick(wxMouseEvent &);
472
473 public:
474 gbtTreeChanceIcon(wxWindow *p_parent);
475
476 DECLARE_EVENT_TABLE()
477 };
478
BEGIN_EVENT_TABLE(gbtTreeChanceIcon,wxStaticBitmap)479 BEGIN_EVENT_TABLE(gbtTreeChanceIcon, wxStaticBitmap)
480 EVT_LEFT_DOWN(gbtTreeChanceIcon::OnLeftClick)
481 END_EVENT_TABLE()
482
483 gbtTreeChanceIcon::gbtTreeChanceIcon(wxWindow *p_parent)
484 : wxStaticBitmap(p_parent, -1, wxBitmap(dice_xpm))
485 { }
486
OnLeftClick(wxMouseEvent &)487 void gbtTreeChanceIcon::OnLeftClick(wxMouseEvent &)
488 {
489 wxBitmap bitmap(dice_xpm);
490
491 #if defined( __WXMSW__) or defined(__WXMAC__)
492 wxImage image = bitmap.ConvertToImage();
493 #else
494 wxIcon image;
495 image.CopyFromBitmap(bitmap);
496 #endif // _WXMSW__
497
498 wxTextDataObject textData(wxT("P0"));
499 wxDropSource source(textData, this, image, image, image);
500 source.DoDragDrop(wxDrag_DefaultMove);
501 }
502
503 class gbtTreeChancePanel : public wxPanel, public gbtGameView {
504 private:
505 wxStaticText *m_playerLabel;
506
507 // Implementation of gbtGameView members
508 void OnUpdate(void);
509
510 /// @name Event handlers
511 //@{
512 /// The set color icon is clicked
513 void OnSetColor(wxCommandEvent &);
514 //@}
515
516 public:
517 gbtTreeChancePanel(wxWindow *, gbtGameDocument *);
518 };
519
gbtTreeChancePanel(wxWindow * p_parent,gbtGameDocument * p_doc)520 gbtTreeChancePanel::gbtTreeChancePanel(wxWindow *p_parent,
521 gbtGameDocument *p_doc)
522 : wxPanel(p_parent, -1), gbtGameView(p_doc)
523 {
524 wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
525
526 wxBoxSizer *labelSizer = new wxBoxSizer(wxHORIZONTAL);
527
528 wxStaticBitmap *playerIcon = new gbtTreeChanceIcon(this);
529 labelSizer->Add(playerIcon, 0, wxALL | wxALIGN_CENTER, 0);
530
531 wxBitmapButton *setColorIcon =
532 new wxBitmapButton(this, -1, wxBitmap(color_xpm),
533 wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
534 setColorIcon->SetToolTip(_("Change the color for this player"));
535
536 labelSizer->Add(setColorIcon, 0, wxALL | wxALIGN_CENTER, 0);
537 Connect(setColorIcon->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
538 wxCommandEventHandler(gbtTreeChancePanel::OnSetColor));
539
540 m_playerLabel = new wxStaticText(this, wxID_STATIC, wxT("Chance"),
541 wxDefaultPosition, wxSize(125, -1),
542 wxALIGN_LEFT);
543 m_playerLabel->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD));
544 labelSizer->Add(m_playerLabel, 1, wxLEFT | wxALIGN_CENTER, 10);
545
546 topSizer->Add(labelSizer, 0, wxALL, 0);
547
548 SetSizer(topSizer);
549 topSizer->SetSizeHints(this);
550 topSizer->Fit(this);
551 Layout();
552 }
553
OnUpdate(void)554 void gbtTreeChancePanel::OnUpdate(void)
555 {
556 if (!m_doc->GetGame()) return;
557
558 m_playerLabel->SetForegroundColour(m_doc->GetStyle().ChanceColor());
559 GetSizer()->Layout();
560 }
561
OnSetColor(wxCommandEvent &)562 void gbtTreeChancePanel::OnSetColor(wxCommandEvent &)
563 {
564 wxColourData data;
565 data.SetColour(m_doc->GetStyle().ChanceColor());
566 wxColourDialog dialog(this, &data);
567 dialog.SetTitle(wxT("Choose color for chance player"));
568
569 if (dialog.ShowModal() == wxID_OK) {
570 wxColour color = dialog.GetColourData().GetColour();
571 gbtStyle style = m_doc->GetStyle();
572 style.SetChanceColor(color);
573 m_doc->SetStyle(style);
574 }
575 }
576
577 //=====================================================================
578 // class gbtTreePlayerToolbar
579 //=====================================================================
580
581 class gbtTreePlayerToolbar : public wxPanel, public gbtGameView {
582 private:
583 gbtTreeChancePanel *m_chancePanel;
584 Gambit::Array<gbtTreePlayerPanel *> m_playerPanels;
585
586 // @name Implementation of gbtGameView members
587 //@{
588 void OnUpdate(void);
589 void PostPendingChanges(void);
590 //@}
591
592 public:
593 gbtTreePlayerToolbar(wxWindow *p_parent, gbtGameDocument *p_doc);
594 };
595
596
gbtTreePlayerToolbar(wxWindow * p_parent,gbtGameDocument * p_doc)597 gbtTreePlayerToolbar::gbtTreePlayerToolbar(wxWindow *p_parent,
598 gbtGameDocument *p_doc)
599 : wxPanel(p_parent, -1, wxDefaultPosition, wxSize(210, -1)),
600 gbtGameView(p_doc)
601 {
602 wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
603
604 m_chancePanel = new gbtTreeChancePanel(this, m_doc);
605 topSizer->Add(m_chancePanel, 0, wxALL | wxEXPAND, 5);
606
607 for (int pl = 1; pl <= m_doc->NumPlayers(); pl++) {
608 m_playerPanels.Append(new gbtTreePlayerPanel(this, m_doc, pl));
609 topSizer->Add(m_playerPanels[pl], 0, wxALL | wxEXPAND, 5);
610 }
611
612 SetSizer(topSizer);
613 Layout();
614 }
615
OnUpdate(void)616 void gbtTreePlayerToolbar::OnUpdate(void)
617 {
618 while (m_playerPanels.Length() < m_doc->NumPlayers()) {
619 gbtTreePlayerPanel *panel = new gbtTreePlayerPanel(this, m_doc,
620 m_playerPanels.Length()+1);
621 m_playerPanels.Append(panel);
622 GetSizer()->Add(panel, 0, wxALL | wxEXPAND, 5);
623 }
624
625 while (m_playerPanels.Length() > m_doc->NumPlayers()) {
626 gbtTreePlayerPanel *panel = m_playerPanels.Remove(m_playerPanels.Length());
627 GetSizer()->Detach(panel);
628 panel->Destroy();
629 }
630
631 for (int pl = 1; pl <= m_playerPanels.Length(); pl++) {
632 m_playerPanels[pl]->OnUpdate();
633 }
634
635 GetSizer()->Layout();
636 }
637
PostPendingChanges(void)638 void gbtTreePlayerToolbar::PostPendingChanges(void)
639 {
640 for (int pl = 1; pl <= m_playerPanels.Length(); pl++) {
641 m_playerPanels[pl]->PostPendingChanges();
642 }
643 }
644
645 //=====================================================================
646 // Implementation of class gbtEfgPanel
647 //=====================================================================
648
BEGIN_EVENT_TABLE(gbtEfgPanel,wxPanel)649 BEGIN_EVENT_TABLE(gbtEfgPanel, wxPanel)
650 EVT_MENU(GBT_MENU_TOOLS_DOMINANCE, gbtEfgPanel::OnToolsDominance)
651 EVT_MENU(GBT_MENU_VIEW_ZOOMIN, gbtEfgPanel::OnViewZoomIn)
652 EVT_MENU(GBT_MENU_VIEW_ZOOMOUT, gbtEfgPanel::OnViewZoomOut)
653 EVT_MENU(GBT_MENU_VIEW_ZOOM100, gbtEfgPanel::OnViewZoom100)
654 EVT_MENU(GBT_MENU_VIEW_ZOOMFIT, gbtEfgPanel::OnViewZoomFit)
655 END_EVENT_TABLE()
656
657 gbtEfgPanel::gbtEfgPanel(wxWindow *p_parent, gbtGameDocument *p_doc)
658 : wxPanel(p_parent, -1), gbtGameView(p_doc)
659 {
660 m_treeWindow = new gbtEfgDisplay(this, m_doc);
661 m_playerToolbar = new gbtTreePlayerToolbar(this, m_doc);
662 m_dominanceToolbar = new gbtBehavDominanceToolbar(this, m_doc);
663
664 wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
665 topSizer->Add(m_dominanceToolbar, 0, wxEXPAND, 0);
666 topSizer->Show(m_dominanceToolbar, false);
667
668 wxBoxSizer *treeSizer = new wxBoxSizer(wxHORIZONTAL);
669 treeSizer->Add(m_playerToolbar, 0, wxEXPAND, 0);
670 treeSizer->Add(m_treeWindow, 1, wxEXPAND, 0);
671
672 topSizer->Add(treeSizer, 1, wxEXPAND, 0);
673 SetSizer(topSizer);
674 Layout();
675 }
676
OnToolsDominance(wxCommandEvent & p_event)677 void gbtEfgPanel::OnToolsDominance(wxCommandEvent &p_event)
678 {
679 GetSizer()->Show(m_dominanceToolbar, p_event.IsChecked(), true);
680 GetSizer()->Layout();
681 }
682
OnViewZoomIn(wxCommandEvent &)683 void gbtEfgPanel::OnViewZoomIn(wxCommandEvent &)
684 {
685 int zoom = m_treeWindow->GetZoom();
686 if (zoom < 150) zoom += 10;
687 m_treeWindow->SetZoom(zoom);
688 }
689
OnViewZoomOut(wxCommandEvent &)690 void gbtEfgPanel::OnViewZoomOut(wxCommandEvent &)
691 {
692 int zoom = m_treeWindow->GetZoom();
693 if (zoom > 10) zoom -= 10;
694 m_treeWindow->SetZoom(zoom);
695 }
696
OnViewZoom100(wxCommandEvent &)697 void gbtEfgPanel::OnViewZoom100(wxCommandEvent &)
698 {
699 m_treeWindow->SetZoom(100);
700 }
701
OnViewZoomFit(wxCommandEvent &)702 void gbtEfgPanel::OnViewZoomFit(wxCommandEvent &)
703 {
704 m_treeWindow->FitZoom();
705 }
706
707 class gbtEfgPrintout : public wxPrintout {
708 private:
709 gbtEfgPanel *m_efgPanel;
710
711 public:
gbtEfgPrintout(gbtEfgPanel * p_efgPanel,const wxString & p_label)712 gbtEfgPrintout(gbtEfgPanel *p_efgPanel, const wxString &p_label)
713 : wxPrintout(p_label), m_efgPanel(p_efgPanel) { }
~gbtEfgPrintout()714 virtual ~gbtEfgPrintout() { }
715
OnPrintPage(int)716 bool OnPrintPage(int)
717 { m_efgPanel->RenderGame(*GetDC(), 50, 50); return true; }
HasPage(int page)718 bool HasPage(int page) { return (page <= 1); }
GetPageInfo(int * minPage,int * maxPage,int * selPageFrom,int * selPageTo)719 void GetPageInfo(int *minPage, int *maxPage,
720 int *selPageFrom, int *selPageTo)
721 { *minPage = 1; *maxPage = 1; *selPageFrom = 1; *selPageTo = 1; }
722 };
723
GetPrintout(void)724 wxPrintout *gbtEfgPanel::GetPrintout(void)
725 {
726 return new gbtEfgPrintout(this,
727 wxString(m_doc->GetGame()->GetTitle().c_str(),
728 *wxConvCurrent));
729 }
730
GetBitmap(wxBitmap & p_bitmap,int p_marginX,int p_marginY)731 bool gbtEfgPanel::GetBitmap(wxBitmap &p_bitmap, int p_marginX, int p_marginY)
732 {
733 if (m_treeWindow->GetLayout().MaxX() > 65000 ||
734 m_treeWindow->GetLayout().MaxY() > 65000) {
735 // This is just too huge to export to graphics
736 return false;
737 }
738
739 wxMemoryDC dc;
740 p_bitmap = wxBitmap(m_treeWindow->GetLayout().MaxX() + 2 * p_marginX,
741 m_treeWindow->GetLayout().MaxY() + 2 * p_marginY);
742 dc.SelectObject(p_bitmap);
743 RenderGame(dc, p_marginX, p_marginY);
744 return true;
745 }
746
GetSVG(const wxString & p_filename,int p_marginX,int p_marginY)747 void gbtEfgPanel::GetSVG(const wxString &p_filename,
748 int p_marginX, int p_marginY)
749 {
750 // The size of the image to be drawn
751 int maxX = m_treeWindow->GetLayout().MaxX();
752 int maxY = m_treeWindow->GetLayout().MaxY();
753
754 wxSVGFileDC dc(p_filename, maxX + 2*p_marginX, maxY + 2*p_marginY);
755 // For some reason, this needs to be initialized
756 dc.SetLogicalScale(1.0, 1.0);
757 RenderGame(dc, p_marginX, p_marginY);
758 }
759
RenderGame(wxDC & p_dc,int p_marginX,int p_marginY)760 void gbtEfgPanel::RenderGame(wxDC &p_dc, int p_marginX, int p_marginY)
761 {
762 // The size of the image to be drawn
763 int maxX = m_treeWindow->GetLayout().MaxX();
764 int maxY = m_treeWindow->GetLayout().MaxY();
765
766 // Get the size of the DC in pixels
767 wxCoord w, h;
768 p_dc.GetSize(&w, &h);
769
770 // Calculate a scaling factor
771 double scaleX = (double) w / (double) (maxX + 2*p_marginX);
772 double scaleY = (double) h / (double) (maxY + 2*p_marginY);
773 double scale = (scaleX < scaleY) ? scaleX : scaleY;
774 // Never zoom in
775 if (scale > 1.0) scale = 1.0;
776 p_dc.SetUserScale(scale, scale);
777
778 // Calculate the position on the DC to center the tree
779 double posX = (double) ((w - (maxX * scale)) / 2.0);
780 double posY = (double) ((h - (maxY * scale)) / 2.0);
781 p_dc.SetDeviceOrigin((int) posX, (int) posY);
782
783 printf("Drawing with scale %f\n", scale);
784
785 // Draw!
786 m_treeWindow->OnDraw(p_dc, scale);
787 }
788