// // $Source: /cvsroot/gambit/gambit/sources/gui/efgpanel.cc,v $ // $Date: 2006/11/11 17:30:24 $ // $Revision: 1.16 $ // // DESCRIPTION: // Main viewing panel for extensive forms // // This file is part of Gambit // Copyright (c) 2005, The Gambit Project // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include #ifndef WX_PRECOMP #include #endif // WX_PRECOMP #include // for drag-and-drop features #include // for creating drag-and-drop cursor #include // for printing support #include // for picking player colors #include "dcsvg.h" // for SVG output #include "efgpanel.h" #include "efgdisplay.h" // FIXME: communicate with tree window via events. #include "menuconst.h" #include "edittext.h" //===================================================================== // class gbtBehavDominanceToolbar //===================================================================== //! //! This panel serves as a toolbar for interactively viewing //! dominance information on extensive forms. //! class gbtBehavDominanceToolbar : public wxPanel, public gbtGameView { private: wxButton *m_topButton, *m_prevButton, *m_nextButton, *m_allButton; wxStaticText *m_level; // Overriding gbtGameView members void OnUpdate(void); // Event handlers void OnStrength(wxCommandEvent &); void OnTopLevel(wxCommandEvent &); void OnPreviousLevel(wxCommandEvent &); void OnNextLevel(wxCommandEvent &); void OnLastLevel(wxCommandEvent &); void OnShowReachable(wxCommandEvent &); public: gbtBehavDominanceToolbar(wxWindow *p_parent, gbtGameDocument *p_doc); virtual ~gbtBehavDominanceToolbar() { } }; #include "bitmaps/next.xpm" #include "bitmaps/prev.xpm" #include "bitmaps/tobegin.xpm" #include "bitmaps/toend.xpm" gbtBehavDominanceToolbar::gbtBehavDominanceToolbar(wxWindow *p_parent, gbtGameDocument *p_doc) : wxPanel(p_parent, -1), gbtGameView(p_doc) { wxBoxSizer *topSizer = new wxBoxSizer(wxHORIZONTAL); topSizer->Add(new wxStaticText(this, wxID_STATIC, wxT("Hide actions which are ")), 0, wxALL | wxALIGN_CENTER, 5); wxString domChoices[] = { wxT("strictly"), wxT("strictly or weakly") }; wxChoice *choice = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 2, domChoices); choice->SetSelection(0); Connect(choice->GetId(), wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(gbtBehavDominanceToolbar::OnStrength)); topSizer->Add(choice, 0, wxALL | wxALIGN_CENTER, 5); topSizer->Add(new wxStaticText(this, wxID_STATIC, wxT("dominated:")), 0, wxALL | wxALIGN_CENTER, 5); m_topButton = new wxBitmapButton(this, -1, wxBitmap(tobegin_xpm)); m_topButton->SetToolTip(_("Show all strategies")); Connect(m_topButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtBehavDominanceToolbar::OnTopLevel)); topSizer->Add(m_topButton, 0, wxALL | wxALIGN_CENTER, 5); m_prevButton = new wxBitmapButton(this, -1, wxBitmap(prev_xpm)); m_prevButton->SetToolTip(_("Previous round of elimination")); Connect(m_prevButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtBehavDominanceToolbar::OnPreviousLevel)); topSizer->Add(m_prevButton, 0, wxALL | wxALIGN_CENTER, 5); m_level = new wxStaticText(this, wxID_STATIC, wxT("All actions shown"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); topSizer->Add(m_level, 0, wxALL | wxALIGN_CENTER, 5); m_nextButton = new wxBitmapButton(this, -1, wxBitmap(next_xpm)); m_nextButton->SetToolTip(_("Next round of elimination")); Connect(m_nextButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtBehavDominanceToolbar::OnNextLevel)); topSizer->Add(m_nextButton, 0, wxALL | wxALIGN_CENTER, 5); m_allButton = new wxBitmapButton(this, -1, wxBitmap(toend_xpm)); m_allButton->SetToolTip(_("Eliminate iteratively")); Connect(m_allButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtBehavDominanceToolbar::OnLastLevel)); topSizer->Add(m_allButton, 0, wxALL | wxALIGN_CENTER, 5); wxCheckBox *showReachable = new wxCheckBox(this, -1, wxT("Show only reachable nodes")); showReachable->SetValue(m_doc->GetStyle().RootReachable()); Connect(showReachable->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(gbtBehavDominanceToolbar::OnShowReachable)); topSizer->Add(showReachable, 0, wxALL | wxALIGN_CENTER, 5); SetSizer(topSizer); Layout(); } void gbtBehavDominanceToolbar::OnStrength(wxCommandEvent &p_event) { m_doc->SetBehavElimStrength(p_event.GetSelection() == 0); } void gbtBehavDominanceToolbar::OnTopLevel(wxCommandEvent &) { m_doc->TopBehavElimLevel(); } void gbtBehavDominanceToolbar::OnPreviousLevel(wxCommandEvent &) { m_doc->PreviousBehavElimLevel(); } void gbtBehavDominanceToolbar::OnNextLevel(wxCommandEvent &) { m_doc->NextBehavElimLevel(); } void gbtBehavDominanceToolbar::OnLastLevel(wxCommandEvent &) { while (m_doc->NextBehavElimLevel()); } void gbtBehavDominanceToolbar::OnShowReachable(wxCommandEvent &) { m_doc->GetStyle().SetRootReachable(!m_doc->GetStyle().RootReachable()); m_doc->UpdateViews(GBT_DOC_MODIFIED_NONE); } void gbtBehavDominanceToolbar::OnUpdate(void) { m_topButton->Enable(m_doc->GetBehavElimLevel() > 1); m_prevButton->Enable(m_doc->GetBehavElimLevel() > 1); m_nextButton->Enable(m_doc->CanBehavElim()); m_allButton->Enable(m_doc->CanBehavElim()); if (m_doc->GetBehavElimLevel() == 1) { m_level->SetLabel(wxT("All actions shown")); } else if (m_doc->GetBehavElimLevel() == 2) { m_level->SetLabel(wxT("Eliminated 1 level")); } else { m_level->SetLabel(wxString::Format(wxT("Eliminated %d levels"), m_doc->GetBehavElimLevel()-1)); } GetSizer()->Layout(); } #include "bitmaps/color.xpm" #include "bitmaps/person.xpm" class gbtTreePlayerIcon : public wxStaticBitmap { private: int m_player; // Event handlers void OnLeftClick(wxMouseEvent &); public: gbtTreePlayerIcon(wxWindow *p_parent, int p_player); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(gbtTreePlayerIcon, wxStaticBitmap) EVT_LEFT_DOWN(gbtTreePlayerIcon::OnLeftClick) END_EVENT_TABLE() gbtTreePlayerIcon::gbtTreePlayerIcon(wxWindow *p_parent, int p_player) : wxStaticBitmap(p_parent, -1, wxBitmap(person_xpm)), m_player(p_player) { } void gbtTreePlayerIcon::OnLeftClick(wxMouseEvent &) { wxBitmap bitmap(person_xpm); #if defined( __WXMSW__) or defined(__WXMAC__) wxImage image = bitmap.ConvertToImage(); #else wxIcon image; image.CopyFromBitmap(bitmap); #endif // _WXMSW__ wxTextDataObject textData(wxString::Format(wxT("P%d"), m_player)); wxDropSource source(textData, this, image, image, image); source.DoDragDrop(wxDrag_DefaultMove); } class gbtTreePlayerPanel : public wxPanel { private: gbtGameDocument *m_doc; int m_player; gbtEditableText *m_playerLabel; wxStaticText *m_payoff, *m_nodeValue, *m_nodeProb; wxStaticText *m_infosetValue, *m_infosetProb, *m_belief; /// @name Event handlers //@{ /// The set color icon is clicked void OnSetColor(wxCommandEvent &); /// Start the editing of the player label void OnEditPlayerLabel(wxCommandEvent &); /// End the editing of the player label after enter is pressed void OnAcceptPlayerLabel(wxCommandEvent &); /// Process a keypress event void OnChar(wxKeyEvent &); //@} public: gbtTreePlayerPanel(wxWindow *, gbtGameDocument *, int p_player); void OnUpdate(void); void PostPendingChanges(void); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(gbtTreePlayerPanel, wxPanel) EVT_CHAR(gbtTreePlayerPanel::OnChar) END_EVENT_TABLE() gbtTreePlayerPanel::gbtTreePlayerPanel(wxWindow *p_parent, gbtGameDocument *p_doc, int p_player) : wxPanel(p_parent, -1), m_doc(p_doc), m_player(p_player) { wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer *labelSizer = new wxBoxSizer(wxHORIZONTAL); wxStaticBitmap *playerIcon = new gbtTreePlayerIcon(this, m_player); labelSizer->Add(playerIcon, 0, wxALL | wxALIGN_CENTER, 0); wxBitmapButton *setColorIcon = new wxBitmapButton(this, -1, wxBitmap(color_xpm), wxDefaultPosition, wxDefaultSize, wxNO_BORDER); setColorIcon->SetToolTip(_("Change the color for this player")); labelSizer->Add(setColorIcon, 0, wxALL | wxALIGN_CENTER, 0); Connect(setColorIcon->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtTreePlayerPanel::OnSetColor)); m_playerLabel = new gbtEditableText(this, -1, wxT(""), wxDefaultPosition, wxSize(125, -1)); m_playerLabel->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD)); labelSizer->Add(m_playerLabel, 1, wxLEFT | wxEXPAND, 10); Connect(m_playerLabel->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtTreePlayerPanel::OnEditPlayerLabel)); Connect(m_playerLabel->GetId(), wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(gbtTreePlayerPanel::OnAcceptPlayerLabel)); topSizer->Add(labelSizer, 0, wxALL, 0); m_payoff = new wxStaticText(this, wxID_STATIC, wxT("Payoff:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); m_payoff->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)); topSizer->Add(m_payoff, 0, wxALL | wxEXPAND, 0); topSizer->Show(m_payoff, false); m_nodeValue = new wxStaticText(this, wxID_STATIC, wxT("Node value:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); m_nodeValue->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)); topSizer->Add(m_nodeValue, 0, wxALL | wxEXPAND, 0); topSizer->Show(m_nodeValue, false); m_nodeProb = new wxStaticText(this, wxID_STATIC, wxT("Node reached:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); m_nodeProb->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)); topSizer->Add(m_nodeProb, 0, wxALL | wxEXPAND, 0); topSizer->Show(m_nodeProb, false); m_infosetValue = new wxStaticText(this, wxID_STATIC, wxT("Infoset value:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); m_infosetValue->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)); topSizer->Add(m_infosetValue, 0, wxALL | wxEXPAND, 0); topSizer->Show(m_infosetValue, false); m_infosetProb = new wxStaticText(this, wxID_STATIC, wxT("Infoset reached:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); m_infosetProb->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)); topSizer->Add(m_infosetProb, 0, wxALL | wxEXPAND, 0); topSizer->Show(m_infosetProb, false); m_belief = new wxStaticText(this, wxID_STATIC, wxT("Belief:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER | wxST_NO_AUTORESIZE); m_belief->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)); topSizer->Add(m_belief, 0, wxALL | wxEXPAND, 0); topSizer->Show(m_belief, false); SetSizer(topSizer); topSizer->SetSizeHints(this); topSizer->Fit(this); Layout(); } void gbtTreePlayerPanel::OnUpdate(void) { if (!m_doc->IsTree()) return; wxColour color = m_doc->GetStyle().GetPlayerColor(m_player); m_playerLabel->SetForegroundColour(color); m_playerLabel->SetValue(wxString(m_doc->GetGame()->GetPlayer(m_player)->GetLabel().c_str(), *wxConvCurrent)); m_payoff->SetForegroundColour(color); if (m_doc->GetCurrentProfile() > 0) { std::string pay = m_doc->GetProfiles().GetPayoff(m_player); m_payoff->SetLabel(wxT("Payoff: ") + wxString(pay.c_str(), *wxConvCurrent)); GetSizer()->Show(m_payoff, true); Gambit::GameNode node = m_doc->GetSelectNode(); if (node) { m_nodeValue->SetForegroundColour(color); std::string value = m_doc->GetProfiles().GetNodeValue(node, m_player); m_nodeValue->SetLabel(wxT("Node value: ") + wxString(value.c_str(), *wxConvCurrent)); GetSizer()->Show(m_nodeValue, true); if (node->GetInfoset() && node->GetPlayer()->GetNumber() == m_player) { m_nodeProb->SetForegroundColour(color); std::string value = m_doc->GetProfiles().GetRealizProb(node); m_nodeProb->SetLabel(wxT("Node reached: ") + wxString(value.c_str(), *wxConvCurrent)); GetSizer()->Show(m_nodeProb, true); m_infosetValue->SetForegroundColour(color); value = m_doc->GetProfiles().GetInfosetValue(node); m_infosetValue->SetLabel(wxT("Infoset value: ") + wxString(value.c_str(), *wxConvCurrent)); GetSizer()->Show(m_infosetValue, true); m_infosetProb->SetForegroundColour(color); value = m_doc->GetProfiles().GetInfosetProb(node); m_infosetProb->SetLabel(wxT("Infoset reached: ") + wxString(value.c_str(), *wxConvCurrent)); GetSizer()->Show(m_infosetProb, true); m_belief->SetForegroundColour(color); value = m_doc->GetProfiles().GetBeliefProb(node); m_belief->SetLabel(wxT("Belief: ") + wxString(value.c_str(), *wxConvCurrent)); GetSizer()->Show(m_belief, true); } else { GetSizer()->Show(m_nodeProb, false); GetSizer()->Show(m_infosetValue, false); GetSizer()->Show(m_infosetProb, false); GetSizer()->Show(m_belief, false); } } else { GetSizer()->Show(m_nodeValue, false); } } else { GetSizer()->Show(m_payoff, false); GetSizer()->Show(m_nodeValue, false); GetSizer()->Show(m_nodeProb, false); GetSizer()->Show(m_infosetValue, false); GetSizer()->Show(m_infosetProb, false); GetSizer()->Show(m_belief, false); } GetSizer()->Layout(); GetSizer()->SetSizeHints(this); GetSizer()->Fit(this); } void gbtTreePlayerPanel::OnChar(wxKeyEvent &p_event) { if (p_event.GetKeyCode() == WXK_ESCAPE) { m_playerLabel->EndEdit(false); } else { p_event.Skip(); } } void gbtTreePlayerPanel::OnSetColor(wxCommandEvent &) { wxColourData data; data.SetColour(m_doc->GetStyle().GetPlayerColor(m_player)); wxColourDialog dialog(this, &data); dialog.SetTitle(wxString::Format(_("Choose color for player %d"), m_player)); if (dialog.ShowModal() == wxID_OK) { wxColour color = dialog.GetColourData().GetColour(); m_doc->GetStyle().SetPlayerColor(m_player, color); m_doc->UpdateViews(GBT_DOC_MODIFIED_VIEWS); } } void gbtTreePlayerPanel::OnEditPlayerLabel(wxCommandEvent &) { m_doc->PostPendingChanges(); m_playerLabel->BeginEdit(); } void gbtTreePlayerPanel::OnAcceptPlayerLabel(wxCommandEvent &) { m_doc->GetGame()->GetPlayer(m_player)->SetLabel((const char *) m_playerLabel->GetValue().mb_str()); m_doc->UpdateViews(GBT_DOC_MODIFIED_LABELS); } void gbtTreePlayerPanel::PostPendingChanges(void) { if (m_playerLabel->IsEditing()) { m_playerLabel->EndEdit(true); m_doc->GetGame()->GetPlayer(m_player)->SetLabel((const char *) m_playerLabel->GetValue().mb_str()); m_doc->UpdateViews(GBT_DOC_MODIFIED_LABELS); } } #include "bitmaps/dice.xpm" class gbtTreeChanceIcon : public wxStaticBitmap { private: // Event handlers void OnLeftClick(wxMouseEvent &); public: gbtTreeChanceIcon(wxWindow *p_parent); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(gbtTreeChanceIcon, wxStaticBitmap) EVT_LEFT_DOWN(gbtTreeChanceIcon::OnLeftClick) END_EVENT_TABLE() gbtTreeChanceIcon::gbtTreeChanceIcon(wxWindow *p_parent) : wxStaticBitmap(p_parent, -1, wxBitmap(dice_xpm)) { } void gbtTreeChanceIcon::OnLeftClick(wxMouseEvent &) { wxBitmap bitmap(dice_xpm); #if defined( __WXMSW__) or defined(__WXMAC__) wxImage image = bitmap.ConvertToImage(); #else wxIcon image; image.CopyFromBitmap(bitmap); #endif // _WXMSW__ wxTextDataObject textData(wxT("P0")); wxDropSource source(textData, this, image, image, image); source.DoDragDrop(wxDrag_DefaultMove); } class gbtTreeChancePanel : public wxPanel, public gbtGameView { private: wxStaticText *m_playerLabel; // Implementation of gbtGameView members void OnUpdate(void); /// @name Event handlers //@{ /// The set color icon is clicked void OnSetColor(wxCommandEvent &); //@} public: gbtTreeChancePanel(wxWindow *, gbtGameDocument *); }; gbtTreeChancePanel::gbtTreeChancePanel(wxWindow *p_parent, gbtGameDocument *p_doc) : wxPanel(p_parent, -1), gbtGameView(p_doc) { wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer *labelSizer = new wxBoxSizer(wxHORIZONTAL); wxStaticBitmap *playerIcon = new gbtTreeChanceIcon(this); labelSizer->Add(playerIcon, 0, wxALL | wxALIGN_CENTER, 0); wxBitmapButton *setColorIcon = new wxBitmapButton(this, -1, wxBitmap(color_xpm), wxDefaultPosition, wxDefaultSize, wxNO_BORDER); setColorIcon->SetToolTip(_("Change the color for this player")); labelSizer->Add(setColorIcon, 0, wxALL | wxALIGN_CENTER, 0); Connect(setColorIcon->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(gbtTreeChancePanel::OnSetColor)); m_playerLabel = new wxStaticText(this, wxID_STATIC, wxT("Chance"), wxDefaultPosition, wxSize(125, -1), wxALIGN_LEFT); m_playerLabel->SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD)); labelSizer->Add(m_playerLabel, 1, wxLEFT | wxALIGN_CENTER, 10); topSizer->Add(labelSizer, 0, wxALL, 0); SetSizer(topSizer); topSizer->SetSizeHints(this); topSizer->Fit(this); Layout(); } void gbtTreeChancePanel::OnUpdate(void) { if (!m_doc->GetGame()) return; m_playerLabel->SetForegroundColour(m_doc->GetStyle().ChanceColor()); GetSizer()->Layout(); } void gbtTreeChancePanel::OnSetColor(wxCommandEvent &) { wxColourData data; data.SetColour(m_doc->GetStyle().ChanceColor()); wxColourDialog dialog(this, &data); dialog.SetTitle(wxT("Choose color for chance player")); if (dialog.ShowModal() == wxID_OK) { wxColour color = dialog.GetColourData().GetColour(); m_doc->GetStyle().SetChanceColor(color); m_doc->UpdateViews(GBT_DOC_MODIFIED_VIEWS); } } //===================================================================== // class gbtTreePlayerToolbar //===================================================================== class gbtTreePlayerToolbar : public wxPanel, public gbtGameView { private: gbtTreeChancePanel *m_chancePanel; Gambit::Array m_playerPanels; // @name Implementation of gbtGameView members //@{ void OnUpdate(void); void PostPendingChanges(void); //@} public: gbtTreePlayerToolbar(wxWindow *p_parent, gbtGameDocument *p_doc); }; gbtTreePlayerToolbar::gbtTreePlayerToolbar(wxWindow *p_parent, gbtGameDocument *p_doc) : wxPanel(p_parent, -1, wxDefaultPosition, wxSize(110, -1)), gbtGameView(p_doc) { wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); m_chancePanel = new gbtTreeChancePanel(this, m_doc); topSizer->Add(m_chancePanel, 0, wxALL | wxEXPAND, 5); for (int pl = 1; pl <= m_doc->NumPlayers(); pl++) { m_playerPanels.Append(new gbtTreePlayerPanel(this, m_doc, pl)); topSizer->Add(m_playerPanels[pl], 0, wxALL | wxEXPAND, 5); } SetSizer(topSizer); Layout(); } void gbtTreePlayerToolbar::OnUpdate(void) { while (m_playerPanels.Length() < m_doc->NumPlayers()) { gbtTreePlayerPanel *panel = new gbtTreePlayerPanel(this, m_doc, m_playerPanels.Length()+1); m_playerPanels.Append(panel); GetSizer()->Add(panel, 0, wxALL | wxEXPAND, 5); } while (m_playerPanels.Length() > m_doc->NumPlayers()) { gbtTreePlayerPanel *panel = m_playerPanels.Remove(m_playerPanels.Length()); GetSizer()->Remove(panel); panel->Destroy(); } for (int pl = 1; pl <= m_playerPanels.Length(); pl++) { m_playerPanels[pl]->OnUpdate(); } GetSizer()->Layout(); } void gbtTreePlayerToolbar::PostPendingChanges(void) { for (int pl = 1; pl <= m_playerPanels.Length(); pl++) { m_playerPanels[pl]->PostPendingChanges(); } } //===================================================================== // Implementation of class gbtEfgPanel //===================================================================== BEGIN_EVENT_TABLE(gbtEfgPanel, wxPanel) EVT_MENU(GBT_MENU_TOOLS_DOMINANCE, gbtEfgPanel::OnToolsDominance) EVT_MENU(GBT_MENU_VIEW_ZOOMIN, gbtEfgPanel::OnViewZoomIn) EVT_MENU(GBT_MENU_VIEW_ZOOMOUT, gbtEfgPanel::OnViewZoomOut) EVT_MENU(GBT_MENU_VIEW_ZOOM100, gbtEfgPanel::OnViewZoom100) EVT_MENU(GBT_MENU_VIEW_ZOOMFIT, gbtEfgPanel::OnViewZoomFit) END_EVENT_TABLE() gbtEfgPanel::gbtEfgPanel(wxWindow *p_parent, gbtGameDocument *p_doc) : wxPanel(p_parent, -1), gbtGameView(p_doc) { m_treeWindow = new gbtEfgDisplay(this, m_doc); m_playerToolbar = new gbtTreePlayerToolbar(this, m_doc); m_dominanceToolbar = new gbtBehavDominanceToolbar(this, m_doc); wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); topSizer->Add(m_dominanceToolbar, 0, wxEXPAND, 0); topSizer->Show(m_dominanceToolbar, false); wxBoxSizer *treeSizer = new wxBoxSizer(wxHORIZONTAL); treeSizer->Add(m_playerToolbar, 0, wxEXPAND, 0); treeSizer->Add(m_treeWindow, 1, wxEXPAND, 0); topSizer->Add(treeSizer, 1, wxEXPAND, 0); SetSizer(topSizer); Layout(); } void gbtEfgPanel::OnToolsDominance(wxCommandEvent &p_event) { GetSizer()->Show(m_dominanceToolbar, p_event.IsChecked(), true); GetSizer()->Layout(); } void gbtEfgPanel::OnViewZoomIn(wxCommandEvent &) { int zoom = m_treeWindow->GetZoom(); if (zoom < 150) zoom += 10; m_treeWindow->SetZoom(zoom); } void gbtEfgPanel::OnViewZoomOut(wxCommandEvent &) { int zoom = m_treeWindow->GetZoom(); if (zoom > 10) zoom -= 10; m_treeWindow->SetZoom(zoom); } void gbtEfgPanel::OnViewZoom100(wxCommandEvent &) { m_treeWindow->SetZoom(100); } void gbtEfgPanel::OnViewZoomFit(wxCommandEvent &) { m_treeWindow->FitZoom(); } class gbtEfgPrintout : public wxPrintout { private: gbtEfgPanel *m_efgPanel; public: gbtEfgPrintout(gbtEfgPanel *p_efgPanel, const wxString &p_label) : wxPrintout(p_label), m_efgPanel(p_efgPanel) { } virtual ~gbtEfgPrintout() { } bool OnPrintPage(int) { m_efgPanel->RenderGame(*GetDC(), 50, 50); return true; } bool HasPage(int page) { return (page <= 1); } void GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) { *minPage = 1; *maxPage = 1; *selPageFrom = 1; *selPageTo = 1; } }; wxPrintout *gbtEfgPanel::GetPrintout(void) { return new gbtEfgPrintout(this, wxString(m_doc->GetGame()->GetTitle().c_str(), *wxConvCurrent)); } bool gbtEfgPanel::GetBitmap(wxBitmap &p_bitmap, int p_marginX, int p_marginY) { if (m_treeWindow->GetLayout().MaxX() > 65000 || m_treeWindow->GetLayout().MaxY() > 65000) { // This is just too huge to export to graphics return false; } wxMemoryDC dc; p_bitmap = wxBitmap(m_treeWindow->GetLayout().MaxX() + 2 * p_marginX, m_treeWindow->GetLayout().MaxY() + 2 * p_marginY); dc.SelectObject(p_bitmap); RenderGame(dc, p_marginX, p_marginY); return true; } void gbtEfgPanel::GetSVG(const wxString &p_filename, int p_marginX, int p_marginY) { // The size of the image to be drawn int maxX = m_treeWindow->GetLayout().MaxX(); int maxY = m_treeWindow->GetLayout().MaxY(); wxSVGFileDC dc(p_filename, maxX + 2*p_marginX, maxY + 2*p_marginY); // For some reason, this needs to be initialized dc.SetLogicalScale(1.0, 1.0); RenderGame(dc, p_marginX, p_marginY); } void gbtEfgPanel::RenderGame(wxDC &p_dc, int p_marginX, int p_marginY) { // The size of the image to be drawn int maxX = m_treeWindow->GetLayout().MaxX(); int maxY = m_treeWindow->GetLayout().MaxY(); // Get the size of the DC in pixels wxCoord w, h; p_dc.GetSize(&w, &h); // Calculate a scaling factor double scaleX = (double) w / (double) (maxX + 2*p_marginX); double scaleY = (double) h / (double) (maxY + 2*p_marginY); double scale = (scaleX < scaleY) ? scaleX : scaleY; // Never zoom in if (scale > 1.0) scale = 1.0; p_dc.SetUserScale(scale, scale); // Calculate the position on the DC to center the tree double posX = (double) ((w - (maxX * scale)) / 2.0); double posY = (double) ((h - (maxY * scale)) / 2.0); p_dc.SetDeviceOrigin((int) posX, (int) posY); printf("Drawing with scale %f\n", scale); // Draw! m_treeWindow->OnDraw(p_dc, scale); }