]> git.saurik.com Git - wxWidgets.git/blob - demos/bombs/bombs1.cpp
extract (and expand and clean up and document) the header window implementation used...
[wxWidgets.git] / demos / bombs / bombs1.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: bombs1.cpp
3 // Purpose: Bombs game
4 // Author: P. Foggia 1996
5 // Modified by: Wlodzimierz Skiba (ABX) since 2003
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
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 # pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 # include "wx/wx.h"
25 #endif //precompiled headers
26
27 #include "bombs.h"
28
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.
32 void BombsCanvas::DrawField(wxDC *dc, int xc1, int yc1, int xc2, int yc2)
33 {
34 wxString buf;
35 wxCoord chw, chh;
36
37 wxColour wxYellow = wxTheColourDatabase->Find(wxT("YELLOW"));
38 wxColour wxFocused = wxTheColourDatabase->Find(wxT("GREY"));
39
40 wxPen *bluePen = wxThePenList->FindOrCreatePen(*wxBLUE, 1, wxSOLID);
41
42 wxBrush *focusedBrush = wxTheBrushList->FindOrCreateBrush(wxFocused, wxSOLID);
43 wxBrush *yellowBrush = wxTheBrushList->FindOrCreateBrush(wxYellow, wxSOLID);
44
45 dc->SetPen(*wxBLACK_PEN);
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;
57 dc->SetFont(font);
58
59 for(x=xc1; x<=xc2; x++)
60 for(y=yc1; y<=yc2; y++)
61 {
62 if (m_game->IsMarked(x,y))
63 {
64 dc->SetPen(*wxBLACK_PEN);
65
66 if (m_game->IsFocussed(x, y))
67 dc->SetBrush(*focusedBrush);
68 else
69 dc->SetBrush(*wxLIGHT_GREY_BRUSH);
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))
75 dc->SetTextForeground(*wxBLUE);
76 else
77 dc->SetTextForeground(*wxRED);
78
79 dc->SetTextBackground(*wxLIGHT_GREY);
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 {
87 dc->SetPen(*wxRED_PEN);
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 {
96 dc->SetPen(*wxBLACK_PEN);
97 if (m_game->IsFocussed(x, y))
98 dc->SetBrush(*focusedBrush);
99 else
100 dc->SetBrush(*wxLIGHT_GREY_BRUSH);
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 {
107 dc->SetPen(*wxBLACK_PEN);
108 dc->SetBrush(*wxRED_BRUSH);
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");
112 dc->SetTextForeground(*wxBLACK);
113 dc->SetTextBackground(*wxRED);
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 {
120 dc->SetPen(*bluePen);
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 {
129 dc->SetPen(*wxBLACK_PEN);
130 if (m_game->IsFocussed(x, y))
131 dc->SetBrush(*focusedBrush);
132 else if (m_game->IsSelected(x,y))
133 dc->SetBrush(*wxWHITE_BRUSH);
134 else
135 dc->SetBrush(*yellowBrush);
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");
144 dc->SetTextForeground(*wxGREEN);
145 break;
146 case 1:
147 buf = wxT("1");
148 dc->SetTextForeground(*wxBLUE);
149 break;
150 default:
151 buf.Printf(wxT("%d"),digit_value);
152 dc->SetTextForeground(*wxBLACK);
153 break;
154 }
155 dc->GetTextExtent(buf, &chw, &chh);
156 dc->SetTextBackground(*wxWHITE);
157 dc->DrawText( buf,
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 }
161 }
162 dc->SetFont(wxNullFont);
163
164 wxString msg;
165 msg.Printf(wxT("%d bombs, %u marked, %d remaining cells"),
166 m_game->GetNumBombs(), m_game->GetNumMarkedCells(),
167 m_game->GetNumRemainingCells() );
168
169 #if wxUSE_LOG && wxUSE_STATUSBAR
170 wxLogStatus(msg);
171 #else
172 this->GetParent()->SetTitle(msg);
173 #endif
174 }
175
176 // Refreshes the field image
177 // xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
178 // expressed in cells.
179 void BombsCanvas::RefreshField(int xc1, int yc1, int xc2, int yc2)
180 {
181 wxClientDC dc(this);
182 DrawField(& dc, xc1, yc1, xc2, yc2);
183 if (m_bmp)
184 {
185 wxMemoryDC memDC;
186 memDC.SelectObject(*m_bmp);
187 DrawField(&memDC, xc1, yc1, xc2, yc2);
188 memDC.SelectObject(wxNullBitmap);
189 }
190 }
191
192 // Called when uncovering a cell.
193 void BombsCanvas::Uncover(int x, int y)
194 {
195 m_game->Unhide(x,y,true);
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++)
217 m_game->Unhide(x,y,false);
218
219 RefreshField(0, 0, gridWidth-1, gridHeight-1);
220 }
221 else if (0 == (m_game->Get(x, y) & BG_MASK))
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 }
240 }
241 }
242
243 // Called when the canvas receives a mouse event.
244 void BombsCanvas::OnMouseEvent(wxMouseEvent& event)
245 {
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() ) )
258 {
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;
268 }
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;
281 }
282 }
283 }
284
285 void 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 {
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
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 }