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