]> git.saurik.com Git - wxWidgets.git/blame - demos/bombs/bombs1.cpp
guarding all text methods against unset font
[wxWidgets.git] / demos / bombs / bombs1.cpp
CommitLineData
025e88c5
JS
1///////////////////////////////////////////////////////////////////////////////
2// Name: bombs1.cpp
3// Purpose: Bombs game
4// Author: P. Foggia 1996
c8059953 5// Modified by: Wlodzimierz Skiba (ABX) since 2003
025e88c5
JS
6// Created: 1996
7// RCS-ID: $Id$
8// Copyright: (c) 1996 P. Foggia
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12/*
13 * implementation of the methods DrawField and OnEvent of the
14 * class BombsCanvas
15 */
16
025e88c5
JS
17#include "wx/wxprec.h"
18
0c65afdb
DS
19#ifdef __BORLANDC__
20# pragma hdrstop
21#endif
22
025e88c5 23#ifndef WX_PRECOMP
0c65afdb 24# include "wx/wx.h"
025e88c5
JS
25#endif //precompiled headers
26
27#include "bombs.h"
28
0c65afdb
DS
29// Draws the field on the device context dc
30// xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
31// expressed in cells.
32void BombsCanvas::DrawField(wxDC *dc, int xc1, int yc1, int xc2, int yc2)
33{
34 wxString buf;
f3a8b1b6 35 wxCoord chw, chh;
0c65afdb 36
709d0081 37 wxColour wxYellow = wxTheColourDatabase->Find(wxT("YELLOW"));
0c65afdb 38 wxColour wxFocused = wxTheColourDatabase->Find(wxT("GREY"));
0c65afdb 39
709d0081
WS
40 wxPen *bluePen = wxThePenList->FindOrCreatePen(*wxBLUE, 1, wxSOLID);
41
0c65afdb 42 wxBrush *focusedBrush = wxTheBrushList->FindOrCreateBrush(wxFocused, wxSOLID);
709d0081 43 wxBrush *yellowBrush = wxTheBrushList->FindOrCreateBrush(wxYellow, wxSOLID);
0c65afdb 44
709d0081 45 dc->SetPen(*wxBLACK_PEN);
0c65afdb
DS
46
47 int x, y;
48 int xMax = this->GetGridSizeInPixels().GetWidth();
49 int yMax = this->GetGridSizeInPixels().GetHeight();
50 for(x=xc1; x<=xc2; x++)
51 dc->DrawLine(x*m_cellWidth*X_UNIT, 0, x*m_cellWidth*X_UNIT, yMax);
52 for(y=xc1; y<=yc2; y++)
53 dc->DrawLine(0, y*m_cellHeight*Y_UNIT, xMax, y*m_cellHeight*Y_UNIT);
54
55
56 wxFont font= BOMBS_FONT;
6759ff7d 57 dc->SetFont(font);
0c65afdb
DS
58
59 for(x=xc1; x<=xc2; x++)
60 for(y=yc1; y<=yc2; y++)
61 {
62 if (m_game->IsMarked(x,y))
63 {
709d0081 64 dc->SetPen(*wxBLACK_PEN);
0c65afdb
DS
65
66 if (m_game->IsFocussed(x, y))
709d0081 67 dc->SetBrush(*focusedBrush);
0c65afdb 68 else
709d0081 69 dc->SetBrush(*wxLIGHT_GREY_BRUSH);
0c65afdb
DS
70
71 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
72 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
73 buf = wxT("M");
74 if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
709d0081 75 dc->SetTextForeground(*wxBLUE);
0c65afdb 76 else
709d0081 77 dc->SetTextForeground(*wxRED);
0c65afdb 78
709d0081 79 dc->SetTextBackground(*wxLIGHT_GREY);
0c65afdb
DS
80 dc->GetTextExtent(buf, &chw, &chh);
81 dc->DrawText( buf,
82 x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
83 y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2 );
84
85 if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
86 {
709d0081 87 dc->SetPen(*wxRED_PEN);
0c65afdb
DS
88 dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
89 (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
90 dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
91 (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
92 }
93 }
94 else if (m_game->IsHidden(x,y))
95 {
709d0081 96 dc->SetPen(*wxBLACK_PEN);
0c65afdb 97 if (m_game->IsFocussed(x, y))
709d0081 98 dc->SetBrush(*focusedBrush);
0c65afdb 99 else
709d0081 100 dc->SetBrush(*wxLIGHT_GREY_BRUSH);
0c65afdb
DS
101
102 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
103 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
104 }
105 else if (m_game->IsBomb(x,y))
106 {
709d0081
WS
107 dc->SetPen(*wxBLACK_PEN);
108 dc->SetBrush(*wxRED_BRUSH);
0c65afdb
DS
109 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
110 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
111 buf = wxT("B");
709d0081
WS
112 dc->SetTextForeground(*wxBLACK);
113 dc->SetTextBackground(*wxRED);
0c65afdb
DS
114 dc->GetTextExtent(buf, &chw, &chh);
115 dc->DrawText( buf,
116 x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
117 y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
118 if (m_game->IsExploded(x,y))
119 {
709d0081 120 dc->SetPen(*bluePen);
0c65afdb
DS
121 dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
122 (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
123 dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
124 (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
125 }
126 }
127 else // Display a digit
128 {
709d0081 129 dc->SetPen(*wxBLACK_PEN);
0c65afdb 130 if (m_game->IsFocussed(x, y))
709d0081
WS
131 dc->SetBrush(*focusedBrush);
132 else if (m_game->IsSelected(x,y))
133 dc->SetBrush(*wxWHITE_BRUSH);
134 else
135 dc->SetBrush(*yellowBrush);
0c65afdb
DS
136 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
137 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
138
139 int digit_value = m_game->Get(x,y) & BG_MASK;
140 switch(digit_value)
141 {
142 case 0:
143 buf = wxT("0");
709d0081 144 dc->SetTextForeground(*wxGREEN);
0c65afdb 145 break;
6759ff7d 146 case 1:
0c65afdb 147 buf = wxT("1");
709d0081 148 dc->SetTextForeground(*wxBLUE);
0c65afdb
DS
149 break;
150 default:
151 buf.Printf(wxT("%d"),digit_value);
709d0081 152 dc->SetTextForeground(*wxBLACK);
0c65afdb
DS
153 break;
154 }
025e88c5 155 dc->GetTextExtent(buf, &chw, &chh);
709d0081 156 dc->SetTextBackground(*wxWHITE);
025e88c5 157 dc->DrawText( buf,
0c65afdb
DS
158 x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
159 y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
160 }
025e88c5 161 }
0c65afdb
DS
162 dc->SetFont(wxNullFont);
163
924fe7da 164 wxString msg;
709d0081
WS
165 msg.Printf(wxT("%d bombs, %u marked, %d remaining cells"),
166 m_game->GetNumBombs(), m_game->GetNumMarkedCells(),
167 m_game->GetNumRemainingCells() );
924fe7da
WS
168
169#if wxUSE_LOG && wxUSE_STATUSBAR
170 wxLogStatus(msg);
171#else
172 this->GetParent()->SetTitle(msg);
0c65afdb 173#endif
025e88c5
JS
174}
175
0c65afdb
DS
176// Refreshes the field image
177// xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
178// expressed in cells.
179void BombsCanvas::RefreshField(int xc1, int yc1, int xc2, int yc2)
180{
025e88c5
JS
181 wxClientDC dc(this);
182 DrawField(& dc, xc1, yc1, xc2, yc2);
0c65afdb
DS
183 if (m_bmp)
184 {
185 wxMemoryDC memDC;
186 memDC.SelectObject(*m_bmp);
025e88c5
JS
187 DrawField(&memDC, xc1, yc1, xc2, yc2);
188 memDC.SelectObject(wxNullBitmap);
0c65afdb
DS
189 }
190}
025e88c5 191
7874bf54 192// Called when uncovering a cell.
0c65afdb 193void BombsCanvas::Uncover(int x, int y)
7874bf54 194{
709d0081 195 m_game->Unhide(x,y,true);
0c65afdb
DS
196 RefreshField(x, y, x, y);
197
198 const int gridWidth = m_game->GetWidth();
199 const int gridHeight = m_game->GetHeight();
200
201 const bool hasWon = m_game->GetNumRemainingCells() == 0;
202 if (m_game->IsBomb(x,y) || hasWon)
203 {
204 wxBell();
205 if (hasWon)
206 {
207 wxMessageBox(wxT("Nice! You found all the bombs!"),
208 wxT("wxWin Bombs"), wxOK|wxCENTRE);
209 }
210 else // x,y is a bomb
211 {
212 m_game->Explode(x, y);
213 }
214
215 for(x=0; x<gridWidth; x++)
216 for(y=0; y<gridHeight; y++)
709d0081
WS
217 m_game->Unhide(x,y,false);
218
219 RefreshField(0, 0, gridWidth-1, gridHeight-1);
7874bf54 220 }
709d0081 221 else if (0 == (m_game->Get(x, y) & BG_MASK))
0c65afdb
DS
222 {
223 int left = ( x > 0 ) ? x-1 : 0;
224 int right = ( x < gridWidth - 1 )
225 ? x+1
226 : gridWidth - 1;
227 int top = ( y > 0 ) ? y-1 : 0;
228 int bottom = ( y < gridHeight - 1 )
229 ? y+1
230 : gridHeight - 1;
231
232 int i, j;
233 for (j=top; j<=bottom; j++)
234 for (i=left; i<=right; i++)
235 if ( (i != x || j != y) && m_game->IsHidden(i, j)
236 && !m_game->IsMarked(i, j) )
237 {
238 Uncover(i, j);
239 }
7874bf54
VZ
240 }
241}
242
025e88c5 243// Called when the canvas receives a mouse event.
0c65afdb 244void BombsCanvas::OnMouseEvent(wxMouseEvent& event)
f5d01a1c 245{
0c65afdb
DS
246 const int gridWidth = m_game->GetWidth();
247 const int gridHeight = m_game->GetHeight();
248
249 wxCoord fx, fy;
250 event.GetPosition(&fx, &fy);
251 int x = fx/(m_cellWidth*X_UNIT);
252 int y = fy/(m_cellHeight*Y_UNIT);
253 if (x<gridWidth && y<gridHeight)
254 {
255 if ( (event.RightDown() || (event.LeftDown() && event.ShiftDown()))
256 && (m_game->IsHidden(x,y)
257 || !m_game->GetNumRemainingCells() ) )
6759ff7d 258 {
0c65afdb
DS
259 // store previous and current field
260 int prevFocusX = m_game->m_gridFocusX;
261 int prevFocusY = m_game->m_gridFocusY;
262 m_game->m_gridFocusX = x;
263 m_game->m_gridFocusY = y;
264 RefreshField(prevFocusX, prevFocusY, prevFocusX, prevFocusY);
265 m_game->Mark(x, y);
266 RefreshField(x, y, x, y);
267 return;
025e88c5 268 }
0c65afdb
DS
269 else if (event.LeftDown() && m_game->IsHidden(x,y)
270 && !m_game->IsMarked(x,y))
271 {
272 // store previous and current field
273 int prevGridFocusX = m_game->m_gridFocusX;
274 int prevGridFocusY = m_game->m_gridFocusY;
275 m_game->m_gridFocusX = x;
276 m_game->m_gridFocusY = y;
277 RefreshField(prevGridFocusX, prevGridFocusY,
278 prevGridFocusX, prevGridFocusY);
279 Uncover(x, y);
280 return;
025e88c5
JS
281 }
282 }
283}
284
0c65afdb
DS
285void BombsCanvas::OnChar(wxKeyEvent& event)
286{
287 int keyCode = event.GetKeyCode();
288 int prevGridFocusX = m_game->m_gridFocusX;
289 int prevGridFocusY = m_game->m_gridFocusY;
290
291 const int gridWidth = m_game->GetWidth();
292 const int gridHeight = m_game->GetHeight();
293
294 switch(keyCode)
295 {
296
297 case WXK_RIGHT:
298 m_game->m_gridFocusX++;
299 if (m_game->m_gridFocusX >= gridWidth) m_game->m_gridFocusX = 0;
300 break;
301
302 case WXK_LEFT:
303 m_game->m_gridFocusX--;
304 if (m_game->m_gridFocusX<0) m_game->m_gridFocusX = gridWidth-1;
305 break;
306
307 case WXK_DOWN:
308 m_game->m_gridFocusY++;
309 if (m_game->m_gridFocusY >= gridHeight) m_game->m_gridFocusY = 0;
310 break;
311
312 case WXK_UP:
313 m_game->m_gridFocusY--;
314 if (m_game->m_gridFocusY<0) m_game->m_gridFocusY = gridHeight-1;
315 break;
316
317 case WXK_RETURN:
318 if ( (prevGridFocusX == m_game->m_gridFocusX)
319 && (prevGridFocusY == m_game->m_gridFocusY)
320 && (m_game->IsHidden(m_game->m_gridFocusX, m_game->m_gridFocusY)) )
321 {
322 m_game->Mark(m_game->m_gridFocusX, m_game->m_gridFocusY);
323 if (!m_game->IsMarked(m_game->m_gridFocusX, m_game->m_gridFocusY))
324 {
325 Uncover(m_game->m_gridFocusX, m_game->m_gridFocusY);
326 }
327 RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
328 m_game->m_gridFocusX, m_game->m_gridFocusY);
329 }
330 break;
331
332 default:
333 event.Skip();
334
335 }
336
337 if ((prevGridFocusX != m_game->m_gridFocusX)
338 || (prevGridFocusY != m_game->m_gridFocusY))
339 {
23290a8c
JS
340 // cause focused field to be visible after first key hit after launching new game
341 if( m_game->m_gridFocusX < 0 ) m_game->m_gridFocusX = 0;
342 if( m_game->m_gridFocusY < 0 ) m_game->m_gridFocusY = 0;
343
0c65afdb
DS
344 // refresh previous field and focused field
345 RefreshField(prevGridFocusX, prevGridFocusY,
346 prevGridFocusX, prevGridFocusY);
347 RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
348 m_game->m_gridFocusX, m_game->m_gridFocusY);
349 }
350}