From 29b07a3821efad89112a5a250fee09f2577658fe Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Garcia Date: Fri, 3 Mar 2000 18:21:48 +0000 Subject: [PATCH] Life version 2.1 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6415 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- demos/life/dialogs.cpp | 18 ++- demos/life/dialogs.h | 3 +- demos/life/game.cpp | 144 +++++++++++++++--- demos/life/game.h | 21 ++- demos/life/life.cpp | 335 +++++++++++++++++++++++++++++++---------- demos/life/life.h | 57 ++++--- demos/life/samples.inc | 4 +- 7 files changed, 441 insertions(+), 141 deletions(-) diff --git a/demos/life/dialogs.cpp b/demos/life/dialogs.cpp index fedac9e0b9..0d8989793e 100644 --- a/demos/life/dialogs.cpp +++ b/demos/life/dialogs.cpp @@ -29,12 +29,13 @@ #endif #include "wx/statline.h" -#include "wx/spinctrl.h" +#include "wx/minifram.h" #include "dialogs.h" #include "life.h" #include "game.h" + // -------------------------------------------------------------------------- // resources // -------------------------------------------------------------------------- @@ -108,17 +109,17 @@ LifeSamplesDialog::LifeSamplesDialog(wxWindow *parent) // layout components wxStaticBoxSizer *sizer1 = new wxStaticBoxSizer( statbox, wxVERTICAL ); - sizer1->Add( m_canvas, 2, wxGROW | wxCENTRE | wxALL, 5); - sizer1->Add( m_text, 1, wxGROW | wxCENTRE | wxALL, 5 ); + sizer1->Add( m_canvas, 2, wxGROW | wxALL, 5); + sizer1->Add( m_text, 1, wxGROW | wxALL, 5 ); wxBoxSizer *sizer2 = new wxBoxSizer( wxHORIZONTAL ); - sizer2->Add( m_list, 0, wxGROW | wxCENTRE | wxALL, 5 ); - sizer2->Add( sizer1, 1, wxGROW | wxCENTRE | wxALL, 5 ); + sizer2->Add( m_list, 0, wxGROW | wxALL, 5 ); + sizer2->Add( sizer1, 1, wxGROW | wxALL, 5 ); wxBoxSizer *sizer3 = new wxBoxSizer( wxVERTICAL ); sizer3->Add( CreateTextSizer(_("Select one configuration")), 0, wxALL, 10 ); sizer3->Add( new wxStaticLine(this, -1), 0, wxGROW | wxLEFT | wxRIGHT, 10 ); - sizer3->Add( sizer2, 1, wxGROW | wxCENTRE | wxALL, 5 ); + sizer3->Add( sizer2, 1, wxGROW | wxALL, 5 ); sizer3->Add( new wxStaticLine(this, -1), 0, wxGROW | wxLEFT | wxRIGHT, 10 ); sizer3->Add( CreateButtonSizer(wxOK | wxCANCEL), 0, wxCENTRE | wxALL, 10 ); @@ -181,7 +182,7 @@ LifeAboutDialog::LifeAboutDialog(wxWindow *parent) wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL ); sizer->Add( sbmp, 0, wxCENTRE | wxALL, 10 ); sizer->Add( new wxStaticLine(this, -1), 0, wxGROW | wxLEFT | wxRIGHT, 5 ); - sizer->Add( CreateTextSizer(_("Life! version 2.0 for wxWindows\n\n" + sizer->Add( CreateTextSizer(_("Life! version 2.1 for wxWindows\n\n" "(c) 2000 Guillermo Rodriguez Garcia\n\n" "\n\n" "Portions of the code are based in XLife;\n" @@ -197,3 +198,6 @@ LifeAboutDialog::LifeAboutDialog(wxWindow *parent) sizer->Fit(this); Centre(wxBOTH | wxCENTRE_ON_SCREEN); } + + + diff --git a/demos/life/dialogs.h b/demos/life/dialogs.h index 95c266eb83..b2187cb0c3 100644 --- a/demos/life/dialogs.h +++ b/demos/life/dialogs.h @@ -28,8 +28,6 @@ #include "wx/wx.h" #endif -#include "wx/spinctrl.h" - #include "life.h" #include "game.h" @@ -73,4 +71,5 @@ public: LifeAboutDialog(wxWindow *parent); }; + #endif // _LIFE_DIALOGS_H_ diff --git a/demos/life/game.cpp b/demos/life/game.cpp index 4946b676f2..f5c2e09f3b 100644 --- a/demos/life/game.cpp +++ b/demos/life/game.cpp @@ -38,8 +38,10 @@ #include // for memset -#define ARRAYSIZE 1024 // size of the static array for BeginFind & co. + +#define ARRAYSIZE 1024 // static array for BeginFind & co. #define ALLOCBOXES 16 // number of cellboxes to alloc at once +#define MAXDEAD 8 // tics before removing cellbox from list // ========================================================================== @@ -48,8 +50,9 @@ #define HASH(x, y) (((x >> 3) & 0x7f) << 7) + ((y >> 3) & 0x7f) -#define HASHSIZE 32768 -#define MAXDEAD 8 +#define HASHSIZE 32768 // hash table size (do not change!) +#define CELLBOX 8 // cells in a cellbox (do not change!) + class CellBox { @@ -329,43 +332,142 @@ void Life::KillBox(CellBox *c) } // -------------------------------------------------------------------------- -// FindMore & co. +// Navigation // -------------------------------------------------------------------------- -// Post eight cells to the cell arrays (changed cells only) -void Life::DoLine(wxInt32 i, wxInt32 j, wxUint32 live, wxUint32 old) +Cell Life::FindCenter() { - wxUint32 diff = (live ^ old) & 0x000000ff; + double i, j; + int n; + i = 0.0; + j = 0.0; + n = 0; - if (!diff) return; + CellBox *c; + for (c = m_head; c; c = c->m_next) + if (!c->m_dead) + { + i += c->m_x; + j += c->m_y; + n++; + } - for (wxInt32 k = 8; k; k--, i++) + if (n > 0) { - if (diff & 0x01) + i = (i / n) + CELLBOX / 2; + j = (j / n) + CELLBOX / 2; + } + + Cell cell; + cell.i = (wxInt32) i; + cell.j = (wxInt32) j; + return cell; +} + +Cell Life::FindNorth() +{ + wxInt32 i = 0, j = 0; + bool first = TRUE; + + CellBox *c; + for (c = m_head; c; c = c->m_next) + if (!c->m_dead && ((first) || (c->m_y < j))) { - m_cells[m_ncells].i = i; - m_cells[m_ncells].j = j; - m_ncells++; + i = c->m_x; + j = c->m_y; + first = FALSE; } - diff >>= 1; - live >>= 1; - } + + Cell cell; + cell.i = first? 0 : i + CELLBOX / 2; + cell.j = first? 0 : j + CELLBOX / 2; + return cell; } -// Post eight cells to the cell arrays (alive cells only) -void Life::DoLine(wxInt32 i, wxInt32 j, wxUint32 live) +Cell Life::FindSouth() { - if (! (live & 0x000000ff)) return; + wxInt32 i = 0, j = 0; + bool first = TRUE; + + CellBox *c; + for (c = m_head; c; c = c->m_next) + if (!c->m_dead && ((first) || (c->m_y > j))) + { + i = c->m_x; + j = c->m_y; + first = FALSE; + } + + Cell cell; + cell.i = first? 0 : i + CELLBOX / 2; + cell.j = first? 0 : j + CELLBOX / 2; + return cell; +} + +Cell Life::FindWest() +{ + wxInt32 i = 0, j = 0; + bool first = TRUE; + + CellBox *c; + for (c = m_head; c; c = c->m_next) + if (!c->m_dead && ((first) || (c->m_x < i))) + { + i = c->m_x; + j = c->m_y; + first = FALSE; + } + + Cell cell; + cell.i = first? 0 : i + CELLBOX / 2; + cell.j = first? 0 : j + CELLBOX / 2; + return cell; +} + +Cell Life::FindEast() +{ + wxInt32 i = 0, j = 0; + bool first = TRUE; + + CellBox *c; + for (c = m_head; c; c = c->m_next) + if (!c->m_dead && ((first) || (c->m_x > i))) + { + i = c->m_x; + j = c->m_y; + first = FALSE; + } + + Cell cell; + cell.i = first? 0 : i + CELLBOX / 2; + cell.j = first? 0 : j + CELLBOX / 2; + return cell; +} + +// -------------------------------------------------------------------------- +// FindMore & co. +// -------------------------------------------------------------------------- + +// DoLine: +// Post eight cells to the cell arrays - leave out the fourth +// argument (or pass 0, the default value) to post alive cells +// only, else it will post cells which have changed. +// +void Life::DoLine(wxInt32 i, wxInt32 j, wxUint32 live, wxUint32 old) +{ + wxUint32 diff = (live ^ old) & 0xff; + + if (!diff) return; for (wxInt32 k = 8; k; k--, i++) { - if (live & 0x01) + if (diff & 0x01) { m_cells[m_ncells].i = i; m_cells[m_ncells].j = j; m_ncells++; } - live >>= 1; + diff >>= 1; } } diff --git a/demos/life/game.h b/demos/life/game.h index 9238e6d0ab..12bb4ff3dd 100644 --- a/demos/life/game.h +++ b/demos/life/game.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: game.h -// Purpose: Life! game logic, version 2 +// Purpose: Life! game logic // Author: Guillermo Rodriguez Garcia, // Modified by: // Created: Jan/2000 @@ -35,6 +35,7 @@ // A Cell is just a struct which contains a pair of (i, j) coords. // These structs are not used internally anywhere; they are just // used to pass cell coordinates around. + struct Cell { wxInt32 i; @@ -85,14 +86,21 @@ public: // accessors inline wxUint32 GetNumCells() const { return m_numcells; }; - bool IsAlive (wxInt32 x, wxInt32 y); - void SetCell (wxInt32 x, wxInt32 y, bool alive = TRUE); - void SetShape(const LifeShape &shape); + bool IsAlive (wxInt32 x, wxInt32 y); + void SetCell (wxInt32 x, wxInt32 y, bool alive = TRUE); + void SetShape (const LifeShape &shape); // game control void Clear(); bool NextTic(); + // navigation + Cell FindNorth(); + Cell FindSouth(); + Cell FindWest(); + Cell FindEast(); + Cell FindCenter(); + // The following functions find cells within a given viewport; either // all alive cells, or only those cells which have changed since last // generation. You first call BeginFind() to specify the viewport, @@ -122,9 +130,8 @@ private: CellBox *LinkBox(wxInt32 x, wxInt32 y, bool create = TRUE); void KillBox(CellBox *c); - // helpers for FindMore & co. - void DoLine(wxInt32 i, wxInt32 j, wxUint32 alive, wxUint32 old); - void DoLine(wxInt32 i, wxInt32 j, wxUint32 alive); + // helper for BeginFind & FindMore + void DoLine(wxInt32 i, wxInt32 j, wxUint32 alive, wxUint32 old = 0); CellBox *m_head; // list of alive boxes diff --git a/demos/life/life.cpp b/demos/life/life.cpp index d8b6bb9150..91dc7f236b 100644 --- a/demos/life/life.cpp +++ b/demos/life/life.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: life.cpp -// Purpose: The game of life, created by J. H. Conway +// Purpose: The game of Life, created by J. H. Conway // Author: Guillermo Rodriguez Garcia, // Modified by: // Created: Jan/2000 @@ -21,11 +21,11 @@ #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/wx.h" + #include "wx/wx.h" #endif #include "wx/statline.h" @@ -39,7 +39,7 @@ // -------------------------------------------------------------------------- #if defined(__WXGTK__) || defined(__WXMOTIF__) - // the application icon + // application icon #include "mondrian.xpm" // bitmap buttons for the toolbar @@ -48,6 +48,13 @@ #include "bitmaps/stop.xpm" #include "bitmaps/zoomin.xpm" #include "bitmaps/zoomout.xpm" + + // navigator + #include "bitmaps/north.xpm" + #include "bitmaps/south.xpm" + #include "bitmaps/east.xpm" + #include "bitmaps/west.xpm" + #include "bitmaps/center.xpm" #endif // -------------------------------------------------------------------------- @@ -57,12 +64,14 @@ // IDs for the controls and the menu commands enum { + // timer + ID_TIMER = 1001, + // menu items and toolbar buttons - ID_RESET = 1001, + ID_RESET, ID_SAMPLES, ID_ABOUT, ID_EXIT, - ID_CENTER, ID_START, ID_STEP, ID_STOP, @@ -71,7 +80,16 @@ enum ID_TOPSPEED, // speed selection slider - ID_SLIDER + ID_SLIDER, + + // navigation + ID_SHOWNAV, + ID_ORIGIN, + ID_CENTER, + ID_NORTH, + ID_SOUTH, + ID_EAST, + ID_WEST, }; // -------------------------------------------------------------------------- @@ -84,17 +102,28 @@ BEGIN_EVENT_TABLE(LifeFrame, wxFrame) EVT_MENU (ID_RESET, LifeFrame::OnMenu) EVT_MENU (ID_ABOUT, LifeFrame::OnMenu) EVT_MENU (ID_EXIT, LifeFrame::OnMenu) - EVT_MENU (ID_CENTER, LifeFrame::OnMenu) EVT_MENU (ID_START, LifeFrame::OnMenu) EVT_MENU (ID_STEP, LifeFrame::OnMenu) EVT_MENU (ID_STOP, LifeFrame::OnMenu) - EVT_MENU (ID_ZOOMIN, LifeFrame::OnMenu) - EVT_MENU (ID_ZOOMOUT, LifeFrame::OnMenu) EVT_MENU (ID_TOPSPEED, LifeFrame::OnMenu) + EVT_MENU (ID_SHOWNAV, LifeFrame::OnMenu) + EVT_MENU (ID_ORIGIN, LifeFrame::OnNavigate) + EVT_BUTTON (ID_CENTER, LifeFrame::OnNavigate) + EVT_BUTTON (ID_NORTH, LifeFrame::OnNavigate) + EVT_BUTTON (ID_SOUTH, LifeFrame::OnNavigate) + EVT_BUTTON (ID_EAST, LifeFrame::OnNavigate) + EVT_BUTTON (ID_WEST, LifeFrame::OnNavigate) + EVT_MENU (ID_ZOOMIN, LifeFrame::OnZoom) + EVT_MENU (ID_ZOOMOUT, LifeFrame::OnZoom) EVT_COMMAND_SCROLL (ID_SLIDER, LifeFrame::OnSlider) + EVT_TIMER (ID_TIMER, LifeFrame::OnTimer) EVT_CLOSE ( LifeFrame::OnClose) END_EVENT_TABLE() +BEGIN_EVENT_TABLE(LifeNavigator, wxMiniFrame) + EVT_CLOSE ( LifeNavigator::OnClose) +END_EVENT_TABLE() + BEGIN_EVENT_TABLE(LifeCanvas, wxWindow) EVT_PAINT ( LifeCanvas::OnPaint) EVT_SCROLLWIN ( LifeCanvas::OnScroll) @@ -116,7 +145,6 @@ IMPLEMENT_APP(LifeApp) #define ADD_TOOL(id, bmp, tooltip, help) \ toolBar->AddTool(id, bmp, wxNullBitmap, FALSE, -1, -1, (wxObject *)0, tooltip, help) -#define GET_FRAME() ((LifeFrame *) wxGetApp().GetTopWindow()) // -------------------------------------------------------------------------- // LifeApp @@ -141,13 +169,14 @@ bool LifeApp::OnInit() // -------------------------------------------------------------------------- // frame constructor -LifeFrame::LifeFrame() : wxFrame((wxFrame *)0, -1, _("Life!"), wxPoint(50, 50)) +LifeFrame::LifeFrame() : wxFrame((wxFrame *)0, -1, _("Life!"), wxPoint(200, 200)) { // frame icon SetIcon(wxICON(mondrian)); // menu bar wxMenu *menuFile = new wxMenu("", wxMENU_TEAROFF); + wxMenu *menuView = new wxMenu("", wxMENU_TEAROFF); wxMenu *menuGame = new wxMenu("", wxMENU_TEAROFF); menuFile->Append(ID_RESET, _("Reset"), _("Start a new game")); @@ -157,19 +186,29 @@ LifeFrame::LifeFrame() : wxFrame((wxFrame *)0, -1, _("Life!"), wxPoint(50, 50)) menuFile->AppendSeparator(); menuFile->Append(ID_EXIT, _("E&xit\tAlt-X"), _("Quit this program")); - menuGame->Append(ID_CENTER, _("Re¢er\tCtrl-C"), _("Go to (0, 0)")); + menuView->Append(ID_SHOWNAV, _("Navigation toolbox"), _("Show or hide toolbox"), TRUE); + menuView->Check (ID_SHOWNAV, TRUE); + menuView->AppendSeparator(); + menuView->Append(ID_ORIGIN, _("Absolute origin"), _("Go to (0, 0)")); + menuView->Append(ID_CENTER, _("Center of mass"), _("Find center of mass")); + menuView->Append(ID_NORTH, _("North"), _("Find northernmost cell")); + menuView->Append(ID_SOUTH, _("South"), _("Find southernmost cell")); + menuView->Append(ID_EAST, _("East"), _("Find easternmost cell")); + menuView->Append(ID_WEST, _("West"), _("Find westernmost cell")); + menuView->AppendSeparator(); + menuView->Append(ID_ZOOMIN, _("Zoom &in\tCtrl-I")); + menuView->Append(ID_ZOOMOUT, _("Zoom &out\tCtrl-O")); + menuGame->Append(ID_START, _("&Start\tCtrl-S"), _("Start")); menuGame->Append(ID_STEP, _("&Next\tCtrl-N"), _("Single step")); menuGame->Append(ID_STOP, _("S&top\tCtrl-T"), _("Stop")); menuGame->Enable(ID_STOP, FALSE); menuGame->AppendSeparator(); menuGame->Append(ID_TOPSPEED, _("Top speed!"), _("Go as fast as possible")); - menuGame->AppendSeparator(); - menuGame->Append(ID_ZOOMIN, _("Zoom &in\tCtrl-I")); - menuGame->Append(ID_ZOOMOUT, _("Zoom &out\tCtrl-O")); wxMenuBar *menuBar = new wxMenuBar(); menuBar->Append(menuFile, _("&File")); + menuBar->Append(menuView, _("&View")); menuBar->Append(menuGame, _("&Game")); SetMenuBar(menuBar); @@ -198,36 +237,69 @@ LifeFrame::LifeFrame() : wxFrame((wxFrame *)0, -1, _("Life!"), wxPoint(50, 50)) CreateStatusBar(2); SetStatusText(_("Welcome to Life!")); - // game and canvas - wxPanel *panel = new wxPanel(this, -1); - m_life = new Life(); - m_canvas = new LifeCanvas(panel, m_life); - m_timer = new LifeTimer(); - m_running = FALSE; - m_topspeed = FALSE; - m_interval = 500; - m_tics = 0; - m_text = new wxStaticText(panel, -1, ""); - UpdateInfoText(); + // game and timer + m_life = new Life(); + m_timer = new wxTimer(this, ID_TIMER); + m_running = FALSE; + m_topspeed = FALSE; + m_interval = 500; + m_tics = 0; - // speed selection slider - wxSlider *slider = new wxSlider(panel, ID_SLIDER, + // We use two different panels to reduce flicker in wxGTK, because + // some widgets (like wxStaticText) don't have their own X11 window, + // and thus updating the text would result in a refresh of the canvas + // if they belong to the same parent. + + wxPanel *panel1 = new wxPanel(this, -1); + wxPanel *panel2 = new wxPanel(this, -1); + + // canvas + m_canvas = new LifeCanvas(panel1, m_life); + + // info panel + m_text = new wxStaticText(panel2, -1, + wxEmptyString, + wxDefaultPosition, + wxDefaultSize, + wxALIGN_CENTER | wxST_NO_AUTORESIZE); + + wxSlider *slider = new wxSlider(panel2, ID_SLIDER, 5, 1, 10, wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL | wxSL_AUTOTICKS); + UpdateInfoText(); + // component layout - wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL); - sizer->Add(new wxStaticLine(panel, -1), 0, wxGROW | wxCENTRE); - sizer->Add(m_canvas, 1, wxGROW | wxCENTRE | wxALL, 2); - sizer->Add(new wxStaticLine(panel, -1), 0, wxGROW | wxCENTRE); - sizer->Add(m_text, 0, wxCENTRE | wxTOP, 4); - sizer->Add(slider, 0, wxCENTRE | wxALL, 4); - panel->SetSizer(sizer); - panel->SetAutoLayout(TRUE); - sizer->Fit(this); - sizer->SetSizeHints(this); + wxBoxSizer *sizer1 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *sizer2 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *sizer3 = new wxBoxSizer(wxVERTICAL); + + sizer1->Add( new wxStaticLine(panel1, -1), 0, wxGROW ); + sizer1->Add( m_canvas, 1, wxGROW | wxALL, 2 ); + sizer1->Add( new wxStaticLine(panel1, -1), 0, wxGROW ); + panel1->SetSizer( sizer1 ); + panel1->SetAutoLayout( TRUE ); + sizer1->Fit( panel1 ); + + sizer2->Add( m_text, 0, wxGROW | wxTOP, 4 ); + sizer2->Add( slider, 0, wxCENTRE | wxALL, 4 ); + panel2->SetSizer( sizer2 ); + panel2->SetAutoLayout( TRUE ); + sizer2->Fit( panel2 ); + + sizer3->Add( panel1, 1, wxGROW ); + sizer3->Add( panel2, 0, wxGROW ); + SetSizer( sizer3 ); + SetAutoLayout( TRUE ); + sizer3->Fit( this ); + + // set minimum frame size + sizer3->SetSizeHints( this ); + + // navigator frame + m_navigator = new LifeNavigator(this); } LifeFrame::~LifeFrame() @@ -239,7 +311,7 @@ void LifeFrame::UpdateInfoText() { wxString msg; - msg.Printf(_(" Generation: %u (T: %u ms), Population: %u "), + msg.Printf(_(" Generation: %u (T: %u ms), Population: %u "), m_tics, m_topspeed? 0 : m_interval, m_life->GetNumCells()); @@ -254,9 +326,9 @@ void LifeFrame::UpdateUI() // start / stop GetToolBar()->EnableTool(ID_START, !m_running); GetToolBar()->EnableTool(ID_STOP, m_running); - GetMenuBar()->GetMenu(1)->Enable(ID_START, !m_running); - GetMenuBar()->GetMenu(1)->Enable(ID_STEP, !m_running); - GetMenuBar()->GetMenu(1)->Enable(ID_STOP, m_running); + GetMenuBar()->GetMenu(2)->Enable(ID_START, !m_running); + GetMenuBar()->GetMenu(2)->Enable(ID_STEP, !m_running); + GetMenuBar()->GetMenu(2)->Enable(ID_STOP, m_running); // zooming int cellsize = m_canvas->GetCellSize(); @@ -271,28 +343,13 @@ void LifeFrame::OnMenu(wxCommandEvent& event) { switch (event.GetId()) { - case ID_CENTER : m_canvas->Recenter(0, 0); break; case ID_START : OnStart(); break; - case ID_STEP : OnTimer(); break; + case ID_STEP : OnStep(); break; case ID_STOP : OnStop(); break; - case ID_ZOOMIN : + case ID_SHOWNAV : { - int cellsize = m_canvas->GetCellSize(); - if (cellsize < 32) - { - m_canvas->SetCellSize(cellsize * 2); - UpdateUI(); - } - break; - } - case ID_ZOOMOUT : - { - int cellsize = m_canvas->GetCellSize(); - if (cellsize > 1) - { - m_canvas->SetCellSize(cellsize / 2); - UpdateUI(); - } + bool checked = GetMenuBar()->GetMenu(1)->IsChecked(ID_SHOWNAV); + m_navigator->Show(checked); break; } case ID_TOPSPEED: @@ -302,7 +359,7 @@ void LifeFrame::OnMenu(wxCommandEvent& event) UpdateUI(); while (m_running && m_topspeed) { - OnTimer(); + OnStep(); wxYield(); } break; @@ -350,7 +407,6 @@ void LifeFrame::OnSamples(wxCommandEvent& WXUNUSED(event)) // dialog box LifeSamplesDialog dialog(this); - // new game? if (dialog.ShowModal() == wxID_OK) { const LifeShape shape = dialog.GetShape(); @@ -366,6 +422,57 @@ void LifeFrame::OnSamples(wxCommandEvent& WXUNUSED(event)) } } +void LifeFrame::OnZoom(wxCommandEvent& event) +{ + int cellsize = m_canvas->GetCellSize(); + + if ((event.GetId() == ID_ZOOMIN) && cellsize < 32) + { + m_canvas->SetCellSize(cellsize * 2); + UpdateUI(); + } + else if ((event.GetId() == ID_ZOOMOUT) && cellsize > 1) + { + m_canvas->SetCellSize(cellsize / 2); + UpdateUI(); + } +} + +void LifeFrame::OnNavigate(wxCommandEvent& event) +{ + Cell c; + + switch (event.GetId()) + { + case ID_NORTH: c = m_life->FindNorth(); break; + case ID_SOUTH: c = m_life->FindSouth(); break; + case ID_WEST: c = m_life->FindWest(); break; + case ID_EAST: c = m_life->FindEast(); break; + case ID_CENTER: c = m_life->FindCenter(); break; + case ID_ORIGIN: c.i = c.j = 0; break; + } + + m_canvas->Recenter(c.i, c.j); +} + +void LifeFrame::OnSlider(wxScrollEvent& event) +{ + m_interval = event.GetPosition() * 100; + + if (m_running) + { + OnStop(); + OnStart(); + } + + UpdateInfoText(); +} + +void LifeFrame::OnTimer(wxTimerEvent& WXUNUSED(event)) +{ + OnStep(); +} + void LifeFrame::OnStart() { if (!m_running) @@ -387,7 +494,7 @@ void LifeFrame::OnStop() } } -void LifeFrame::OnTimer() +void LifeFrame::OnStep() { if (m_life->NextTic()) m_tics++; @@ -398,27 +505,87 @@ void LifeFrame::OnTimer() UpdateInfoText(); } -void LifeFrame::OnSlider(wxScrollEvent& event) -{ - m_interval = event.GetPosition() * 100; - - if (m_running) - { - OnStop(); - OnStart(); - } - - UpdateInfoText(); -} // -------------------------------------------------------------------------- -// LifeTimer +// LifeNavigator miniframe // -------------------------------------------------------------------------- -void LifeTimer::Notify() +LifeNavigator::LifeNavigator(wxWindow *parent) + : wxMiniFrame(parent, -1, + _("Navigation"), + wxDefaultPosition, + wxDefaultSize, + wxCAPTION | wxSIMPLE_BORDER) { - GET_FRAME()->OnTimer(); -}; + wxPanel *panel = new wxPanel(this, -1); + wxBoxSizer *sizer1 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *sizer2 = new wxBoxSizer(wxHORIZONTAL); + + // create bitmaps and masks for the buttons + wxBitmap + bmpn = wxBITMAP(north), + bmpw = wxBITMAP(west), + bmpc = wxBITMAP(center), + bmpe = wxBITMAP(east), + bmps = wxBITMAP(south); + +#ifdef __WXMSW__ + bmpn.SetMask(new wxMask(bmpn, *wxLIGHT_GREY)); + bmpw.SetMask(new wxMask(bmpw, *wxLIGHT_GREY)); + bmpc.SetMask(new wxMask(bmpc, *wxLIGHT_GREY)); + bmpe.SetMask(new wxMask(bmpe, *wxLIGHT_GREY)); + bmps.SetMask(new wxMask(bmps, *wxLIGHT_GREY)); +#endif + + // create the buttons and attach tooltips to them + wxBitmapButton + *bn = new wxBitmapButton(panel, ID_NORTH, bmpn), + *bw = new wxBitmapButton(panel, ID_WEST , bmpw), + *bc = new wxBitmapButton(panel, ID_CENTER, bmpc), + *be = new wxBitmapButton(panel, ID_EAST , bmpe), + *bs = new wxBitmapButton(panel, ID_SOUTH, bmps); + + bn->SetToolTip(_("Find northernmost cell")); + bw->SetToolTip(_("Find westernmost cell")); + bc->SetToolTip(_("Find center of mass")); + be->SetToolTip(_("Find easternmost cell")); + bs->SetToolTip(_("Find southernmost cell")); + + // add buttons to sizers + sizer2->Add( bw, 0, wxCENTRE | wxWEST, 4 ); + sizer2->Add( bc, 0, wxCENTRE); + sizer2->Add( be, 0, wxCENTRE | wxEAST, 4 ); + sizer1->Add( bn, 0, wxCENTRE | wxNORTH, 4 ); + sizer1->Add( sizer2 ); + sizer1->Add( bs, 0, wxCENTRE | wxSOUTH, 4 ); + + // set the miniframe size + panel->SetSizer(sizer1); + panel->SetAutoLayout(TRUE); + sizer1->Fit(this); + sizer1->SetSizeHints(this); + + // move it to a sensible position + wxRect parentRect = parent->GetRect(); + wxSize childSize = GetSize(); + int x = parentRect.GetX() + + parentRect.GetWidth(); + int y = parentRect.GetY() + + (parentRect.GetHeight() - childSize.GetHeight()) / 4; + Move(x, y); + + // done + Show(TRUE); +} + +void LifeNavigator::OnClose(wxCloseEvent& event) +{ + if (event.CanVeto()) + event.Veto(); + else + Destroy(); +} + // -------------------------------------------------------------------------- // LifeCanvas @@ -642,7 +809,7 @@ void LifeCanvas::OnMouse(wxMouseEvent& event) // set statusbar text wxString msg; msg.Printf(_("Cell: (%d, %d)"), i, j); - GET_FRAME()->SetStatusText(msg, 1); + ((LifeFrame *) wxGetApp().GetTopWindow())->SetStatusText(msg, 1); // button pressed? if (!event.LeftIsDown()) @@ -730,7 +897,7 @@ void LifeCanvas::OnMouse(wxMouseEvent& event) dc.EndDrawing(); } - GET_FRAME()->UpdateInfoText(); + ((LifeFrame *) wxGetApp().GetTopWindow())->UpdateInfoText(); } void LifeCanvas::OnSize(wxSizeEvent& event) @@ -841,3 +1008,5 @@ void LifeCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // do nothing. I just don't want the background to be erased, you know. } + + diff --git a/demos/life/life.h b/demos/life/life.h index 74bc31138f..0fa61a695c 100644 --- a/demos/life/life.h +++ b/demos/life/life.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: life.h -// Purpose: The game of life, created by J. H. Conway +// Purpose: The game of Life, created by J. H. Conway // Author: Guillermo Rodriguez Garcia, // Modified by: // Created: Jan/2000 @@ -28,15 +28,18 @@ #include "wx/wx.h" #endif +#include "wx/minifram.h" + #include "game.h" + // -------------------------------------------------------------------------- // LifeCanvas // -------------------------------------------------------------------------- -/* Note that in LifeCanvas, all cell coordinates are - * named i, j, while screen coordinates are named x, y. - */ +// Note that in LifeCanvas, all cell coordinates are +// named i, j, while screen coordinates are named x, y. + class LifeCanvas : public wxWindow { public: @@ -94,17 +97,26 @@ private: wxInt32 m_mi, m_mj; // last mouse position }; + // -------------------------------------------------------------------------- -// LifeTimer +// LifeNavigator // -------------------------------------------------------------------------- -// Life timer -class LifeTimer : public wxTimer +class LifeNavigator : public wxMiniFrame { public: - void Notify(); + // ctor + LifeNavigator(wxWindow *parent); + +private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() + + // event handlers + void OnClose(wxCloseEvent& event); }; + // -------------------------------------------------------------------------- // LifeFrame // -------------------------------------------------------------------------- @@ -119,30 +131,37 @@ public: // member functions void UpdateInfoText(); void UpdateUI(); - void OnTimer(); private: // any class wishing to process wxWindows events must use this macro DECLARE_EVENT_TABLE() // event handlers - void OnMenu(wxCommandEvent& event); void OnSamples(wxCommandEvent& event); + void OnMenu(wxCommandEvent& event); + void OnNavigate(wxCommandEvent& event); + void OnZoom(wxCommandEvent& event); void OnSlider(wxScrollEvent& event); + void OnTimer(wxTimerEvent& event); void OnClose(wxCloseEvent& event); + + // event handler helpers void OnStart(); void OnStop(); - - Life *m_life; - LifeTimer *m_timer; - LifeCanvas *m_canvas; - wxStaticText *m_text; - bool m_running; - bool m_topspeed; - long m_interval; - long m_tics; + void OnStep(); + + Life *m_life; + LifeCanvas *m_canvas; + LifeNavigator *m_navigator; + wxStaticText *m_text; + wxTimer *m_timer; + bool m_running; + bool m_topspeed; + long m_interval; + long m_tics; }; + // -------------------------------------------------------------------------- // LifeApp // -------------------------------------------------------------------------- diff --git a/demos/life/samples.inc b/demos/life/samples.inc index 22fe76d5e2..b8e7f59761 100644 --- a/demos/life/samples.inc +++ b/demos/life/samples.inc @@ -156,8 +156,8 @@ const LifeShape g_shapes[] = "November 1970. Many new guns have since been found."), 36, 9, ".........................*.........." - "......................****....*....." - ".............*.......****.....*....." + "......................****.........." + ".............*.......****..........." "............*.*......*..*.........**" "...........*...**....****.........**" "**.........*...**.....****.........." -- 2.45.2