Easy corner for new wxBombers (as requested in patch #1178276).
[wxWidgets.git] / demos / bombs / bombs.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: bombs.cpp
3 // Purpose: Bombs game
4 // Author: P. Foggia 1996
5 // Modified by: Wlodzimierz Skiba (ABX) 2003
6 // Created: 1996
7 // RCS-ID: $Id$
8 // Copyright: (c) 1996 P. Foggia
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 # pragma implementation
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 # pragma hdrstop
20 #endif
21
22 #ifndef WX_PRECOMP
23 # include "wx/wx.h"
24 #endif //precompiled headers
25
26 #include "wx/stockitem.h"
27
28 #include "bombs.h"
29
30 #include <stdlib.h>
31
32 #ifndef __WXWINCE__
33 # include <time.h>
34 #endif
35
36 #if defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) \
37 || defined(__WXMAC__) || defined(__WXMGL__)
38 # include "bombs.xpm"
39 #endif
40
41 IMPLEMENT_APP(BombsApp)
42
43 #ifdef __WXWINCE__
44 STDAPI_(__int64) CeGetRandomSeed();
45 #endif
46
47 // Called to initialize the program
48 bool BombsApp::OnInit()
49 {
50 #ifdef __WXWINCE__
51 srand((unsigned) CeGetRandomSeed());
52 #else
53 srand((unsigned) time(NULL));
54 #endif
55
56 m_frame = new BombsFrame(&m_game);
57
58 m_frame->NewGame(bombsID_EASY, false);
59
60 return true;
61 }
62
63 BEGIN_EVENT_TABLE(BombsFrame, wxFrame)
64 EVT_MENU(bombsID_EASY, BombsFrame::OnNewEasyGame)
65 EVT_MENU(bombsID_MEDIUM, BombsFrame::OnNewMediumGame)
66 EVT_MENU(bombsID_HARD, BombsFrame::OnNewHardGame)
67 EVT_MENU(bombsID_EASYCORNER, BombsFrame::OnEasyCorner)
68 EVT_MENU(wxID_EXIT, BombsFrame::OnExit)
69 EVT_MENU(wxID_ABOUT, BombsFrame::OnAbout)
70 END_EVENT_TABLE()
71
72 BombsFrame::BombsFrame(BombsGame *game)
73 : wxFrame(NULL, wxID_ANY, wxT("wxBombs"), wxDefaultPosition,
74 wxSize(300, 300), wxDEFAULT_DIALOG_STYLE|wxMINIMIZE_BOX)
75 {
76 m_game = game;
77 m_easyCorner = false;
78 m_lastLevel = bombsID_EASY;
79
80 SetIcon(wxICON(bombs));
81
82 #if wxUSE_STATUSBAR
83 CreateStatusBar();
84 #endif
85
86 // Create a menu bar for the frame
87 wxMenuBar *menuBar = new wxMenuBar;
88 wxMenu *menuFile = new wxMenu;
89 wxMenu *menuLevel = new wxMenu;
90 menuLevel->AppendRadioItem(bombsID_EASY, wxT("&Easy (10x10)\tCtrl-1"));
91 menuLevel->AppendRadioItem(bombsID_MEDIUM, wxT("&Medium (15x15)\tCtrl-2"));
92 menuLevel->AppendRadioItem(bombsID_HARD, wxT("&Hard (25x20)\tCtrl-3"));
93
94 menuFile->Append(bombsID_NEWGAME, wxT("&New Game"),
95 menuLevel, wxT("Starts a new game"));
96 menuFile->AppendCheckItem(bombsID_EASYCORNER, wxT("&Easy corner"));
97
98 menuFile->AppendSeparator();
99 menuFile->Append(wxID_EXIT, wxGetStockLabel(wxID_EXIT), wxT("Quits the application"));
100
101 menuBar->Append(menuFile, wxT("&File"));
102
103
104 wxMenu *menuHelp = new wxMenu;
105 menuHelp->Append(wxID_ABOUT, wxT("&About"),
106 wxT("Displays the program information") );
107
108 menuBar->Append(menuHelp, wxT("&Help"));
109
110 SetMenuBar(menuBar);
111
112 // Create child subwindows.
113 m_canvas = new BombsCanvas(this, m_game);
114
115 // Ensure the subwindows get resized o.k.
116 // OnSize(width, height);
117
118 // Centre frame on the screen.
119 Centre(wxBOTH);
120
121 // Show the frame.
122 Show();
123 }
124
125 void BombsFrame::OnExit(wxCommandEvent& WXUNUSED(event))
126 {
127 Close();
128 }
129
130 void BombsFrame::NewGame(int level, bool query)
131 {
132 if(query)
133 {
134 int ok = wxMessageBox(
135 wxT("Start new game regardless previous board?"),
136 wxT("Confirm"),
137 wxYES_NO | wxICON_QUESTION,
138 this
139 );
140 if(ok!=wxYES)return;
141 }
142
143 int numHorzCells = 20, numVertCells = 20;
144 m_lastLevel = level;
145
146 switch(level)
147 {
148 case bombsID_EASY:
149 numHorzCells = numVertCells = 10;
150 break;
151
152 case bombsID_MEDIUM:
153 numHorzCells = numVertCells = 15;
154 break;
155
156 case bombsID_HARD:
157 numHorzCells = 25; numVertCells = 20;
158 break;
159
160 default :
161 wxFAIL_MSG(wxT("Invalid level"));
162 break;
163 }
164
165 m_game->Init(numHorzCells, numVertCells, m_easyCorner);
166
167 GetMenuBar()->Check(level, true);
168
169 m_canvas->UpdateGridSize();
170 SetClientSize(m_canvas->GetGridSizeInPixels());
171 }
172
173 void BombsFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
174 {
175 wxMessageBox(
176 wxT("wxBombs (c) 1996 by P. Foggia\n<foggia@amalfi.dis.unina.it>"),
177 wxT("About wxBombs") );
178 }
179
180 void BombsFrame::OnNewEasyGame(wxCommandEvent& WXUNUSED(event))
181 {
182 NewGame(bombsID_EASY, true);
183 }
184
185 void BombsFrame::OnNewMediumGame(wxCommandEvent& WXUNUSED(event))
186 {
187 NewGame(bombsID_MEDIUM, true);
188 }
189
190 void BombsFrame::OnNewHardGame(wxCommandEvent& WXUNUSED(event))
191 {
192 NewGame(bombsID_HARD, true);
193 }
194
195 void BombsFrame::OnEasyCorner(wxCommandEvent& WXUNUSED(event))
196 {
197 wxString msg;
198 if(m_easyCorner)
199 msg = wxT("enable");
200 else
201 msg = wxT("disable");
202
203 msg = wxT("Do you really want to ") + msg + wxT(" having\ntop left corner always empty for easier start?");
204
205 int ok = wxMessageBox(
206 msg,
207 wxT("Confirm"),
208 wxYES_NO | wxICON_QUESTION,
209 this
210 );
211
212 if(ok!=wxYES)return;
213
214 m_easyCorner = !m_easyCorner;
215
216 NewGame(m_lastLevel, true);
217 }
218
219 BEGIN_EVENT_TABLE(BombsCanvas, wxPanel)
220 EVT_PAINT(BombsCanvas::OnPaint)
221 EVT_MOUSE_EVENTS(BombsCanvas::OnMouseEvent)
222 EVT_CHAR(BombsCanvas::OnChar)
223 END_EVENT_TABLE()
224
225 BombsCanvas::BombsCanvas(wxFrame *parent, BombsGame *game)
226 : wxPanel(parent, wxID_ANY)
227 {
228 m_game = game;
229 int sx, sy;
230 wxClientDC dc(this);
231 wxFont font= BOMBS_FONT;
232 dc.SetFont(font);
233
234 long chw, chh;
235 wxString buf = wxT("M");
236
237 dc.GetTextExtent(buf, &chw, &chh);
238 dc.SetFont(wxNullFont);
239
240 dc.SetMapMode(wxMM_METRIC);
241
242 int xcm = dc.LogicalToDeviceX(10);
243 int ycm = dc.LogicalToDeviceY(10);
244 // To have a square cell, there must be :
245 // sx*ycm == sy*xcm
246 if (chw*ycm < chh*xcm)
247 {
248 sy = chh;
249 sx = chh*xcm/ycm;
250 }
251 else
252 {
253 sx = chw;
254 sy = chw*ycm/xcm;
255 }
256
257 m_cellWidth = (sx+3+X_UNIT)/X_UNIT;
258 m_cellHeight = (sy+3+Y_UNIT)/Y_UNIT;
259 dc.SetMapMode(wxMM_TEXT);
260 m_bmp = NULL;
261 }
262
263 BombsCanvas::~BombsCanvas()
264 {
265 if (m_bmp)
266 {
267 delete m_bmp;
268 m_bmp = NULL;
269 }
270 }
271
272 // Called when canvas needs to be repainted.
273 void BombsCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
274 {
275 wxPaintDC dc(this);
276
277 const int numHorzCells = m_game->GetWidth();
278 const int numVertCells = m_game->GetHeight();
279 // Insert your drawing code here.
280 if (!m_bmp)
281 {
282 wxSize size = dc.GetSize();
283 m_bmp = new wxBitmap(size.GetWidth(), size.GetHeight());
284 if (m_bmp)
285 {
286 wxMemoryDC memDC;
287 memDC.SelectObject(*m_bmp);
288 DrawField(&memDC, 0, 0, numHorzCells-1, numVertCells-1);
289 memDC.SelectObject(wxNullBitmap);
290 }
291 }
292
293 if (m_bmp)
294 {
295 wxMemoryDC memDC;
296 memDC.SelectObject(*m_bmp);
297 wxSize size = dc.GetSize();
298 dc.Blit(0, 0, size.GetWidth(), size.GetHeight(),
299 &memDC, 0, 0, wxCOPY);
300 memDC.SelectObject(wxNullBitmap);
301 }
302 else
303 {
304 DrawField(&dc, 0, 0, numHorzCells-1, numVertCells-1);
305 }
306 }
307
308 void BombsCanvas::UpdateGridSize()
309 {
310
311 if (m_bmp)
312 {
313 delete m_bmp;
314 m_bmp = NULL;
315 }
316 SetSize(GetGridSizeInPixels());
317 Refresh();
318 }
319
320 wxSize BombsCanvas::GetGridSizeInPixels() const
321 {
322 return wxSize(m_cellWidth*X_UNIT*m_game->GetWidth(),
323 m_cellHeight*Y_UNIT*m_game->GetHeight());
324 }
325