Applied patch for Forty, print patch and wxHTML book patch
[wxWidgets.git] / demos / forty / pile.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: pile.cpp
3 // Purpose: Forty Thieves patience game
4 // Author: Chris Breeze
5 // Modified by:
6 // Created: 21/07/97
7 // RCS-ID: $Id$
8 // Copyright: (c) 1993-1998 Chris Breeze
9 // Licence: wxWindows licence
10 //---------------------------------------------------------------------------
11 // Last modified: 22nd July 1998 - ported to wxWindows 2.0
12 /////////////////////////////////////////////////////////////////////////////
13 //+-------------------------------------------------------------+
14 //| Description: |
15 //| The base class for holding piles of playing cards. |
16 //+-------------------------------------------------------------+
17
18 #ifdef __GNUG__
19 #pragma implementation
20 #pragma interface
21 #endif
22
23 // For compilers that support precompilation, includes "wx/wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx/wx.h"
32 #endif
33 #ifdef __GNUG__
34 #pragma implementation
35 #endif
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <time.h>
40 #include <string.h>
41 #include "card.h"
42 #include "pile.h"
43
44 #include "wx/app.h"
45
46 //+-------------------------------------------------------------+
47 //| Pile::Pile() |
48 //+-------------------------------------------------------------+
49 //| Description: |
50 //| Initialise the pile to be empty of cards. |
51 //+-------------------------------------------------------------+
52 Pile::Pile(int x, int y, int dx, int dy)
53 {
54 m_x = x;
55 m_y = y;
56 m_dx = dx;
57 m_dy = dy;
58 for (m_topCard = 0; m_topCard < NumCards; m_topCard++)
59 {
60 m_cards[m_topCard] = 0;
61 }
62 m_topCard = -1; // i.e. empty
63 }
64
65
66 //+-------------------------------------------------------------+
67 //| Pile::Redraw() |
68 //+-------------------------------------------------------------+
69 //| Description: |
70 //| Redraw the pile on the screen. If the pile is empty |
71 //| just draw a NULL card as a place holder for the pile. |
72 //| Otherwise draw the pile from the bottom up, starting |
73 //| at the origin of the pile, shifting each subsequent |
74 //| card by the pile's x and y offsets. |
75 //+-------------------------------------------------------------+
76 void Pile::Redraw(wxDC& dc )
77 {
78 wxWindow *frame = wxTheApp->GetTopWindow();
79 wxWindow *canvas = (wxWindow *) NULL;
80 if (frame)
81 {
82 wxNode *node = frame->GetChildren().First();
83 if (node) canvas = (wxWindow*)node->Data();
84 }
85
86 if (m_topCard >= 0)
87 {
88 if (m_dx == 0 && m_dy == 0)
89 {
90 if ((canvas) && (canvas->IsExposed(m_x,m_y,Card::GetScale()*60,Card::GetScale()*200)))
91 m_cards[m_topCard]->Draw(dc, m_x, m_y);
92 }
93 else
94 {
95 int x = m_x;
96 int y = m_y;
97 for (int i = 0; i <= m_topCard; i++)
98 {
99 if ((canvas) && (canvas->IsExposed(x,y,Card::GetScale()*60,Card::GetScale()*200)))
100 m_cards[i]->Draw(dc, x, y);
101 x += (int)Card::GetScale()*m_dx;
102 y += (int)Card::GetScale()*m_dy;
103 }
104 }
105 }
106 else
107 {
108 if ((canvas) && (canvas->IsExposed(m_x,m_y,Card::GetScale()*60,Card::GetScale()*200)))
109 Card::DrawNullCard(dc, m_x, m_y);
110 }
111 }
112
113
114 //+-------------------------------------------------------------+
115 //| Pile::GetTopCard() |
116 //+-------------------------------------------------------------+
117 //| Description: |
118 //| Return a pointer to the top card in the pile or NULL |
119 //| if the pile is empty. |
120 //| NB: Gets a copy of the card without removing it from the |
121 //| pile. |
122 //+-------------------------------------------------------------+
123 Card* Pile::GetTopCard()
124 {
125 Card* card = 0;
126
127 if (m_topCard >= 0)
128 {
129 card = m_cards[m_topCard];
130 }
131 return card;
132 }
133
134
135 //+-------------------------------------------------------------+
136 //| Pile::RemoveTopCard() |
137 //+-------------------------------------------------------------+
138 //| Description: |
139 //| If the pile is not empty, remove the top card from the |
140 //| pile and return the pointer to the removed card. |
141 //| If the pile is empty return a NULL pointer. |
142 //+-------------------------------------------------------------+
143 Card* Pile::RemoveTopCard()
144 {
145 Card* card = 0;
146
147 if (m_topCard >= 0)
148 {
149 card = m_cards[m_topCard--];
150 }
151 return card;
152 }
153
154
155 //+-------------------------------------------------------------+
156 //| Pile::RemoveTopCard() |
157 //+-------------------------------------------------------------+
158 //| Description: |
159 //| As RemoveTopCard() but also redraw the top of the pile |
160 //| after the card has been removed. |
161 //| NB: the offset allows for the redrawn area to be in a |
162 //| bitmap ready for 'dragging' cards acrosss the screen. |
163 //+-------------------------------------------------------------+
164 Card* Pile::RemoveTopCard(wxDC& dc, int xOffset, int yOffset)
165 {
166 int topX, topY, x, y;
167
168 GetTopCardPos(topX, topY);
169 Card* card = RemoveTopCard();
170
171 if (card)
172 {
173 card->Erase(dc, topX - xOffset, topY - yOffset);
174 GetTopCardPos(x, y);
175 if (m_topCard < 0)
176 {
177 Card::DrawNullCard(dc, x - xOffset, y - yOffset);
178 }
179 else
180 {
181 m_cards[m_topCard]->Draw(dc, x - xOffset, y - yOffset);
182 }
183 }
184
185 return card;
186 }
187
188
189 void Pile::GetTopCardPos(int& x, int& y)
190 {
191 if (m_topCard < 0)
192 {
193 x = m_x;
194 y = m_y;
195 }
196 else
197 {
198 x = m_x + (int)Card::GetScale()*m_dx * m_topCard;
199 y = m_y + (int)Card::GetScale()*m_dy * m_topCard;
200 }
201 }
202
203 void Pile::AddCard(Card* card)
204 {
205 if (m_topCard < -1) m_topCard = -1;
206
207 m_cards[++m_topCard] = card;
208 }
209
210 void Pile::AddCard(wxDC& dc, Card* card)
211 {
212 AddCard(card);
213 int x, y;
214 GetTopCardPos(x, y);
215 card->Draw(dc, x, y);
216 }
217
218 // Can the card leave this pile.
219 // If it is a member of the pile then the answer is yes.
220 // Derived classes may override this behaviour to incorporate
221 // the rules of the game
222 bool Pile::CanCardLeave(Card* card)
223 {
224 for (int i = 0; i <= m_topCard; i++)
225 {
226 if (card == m_cards[i]) return TRUE;
227 }
228 return FALSE;
229 }
230
231 // Calculate how far x, y is from top card in the pile
232 // Returns the square of the distance
233 int Pile::CalcDistance(int x, int y)
234 {
235 int cx, cy;
236 GetTopCardPos(cx, cy);
237 return ((cx - x) * (cx - x) + (cy - y) * (cy - y));
238 }
239
240
241 // Return the card at x, y. Check the top card first, then
242 // work down the pile. If a card is found then return a pointer
243 // to the card, otherwise return NULL
244 Card* Pile::GetCard(int x, int y)
245 {
246 int cardX;
247 int cardY;
248 GetTopCardPos(cardX, cardY);
249
250 for (int i = m_topCard; i >= 0; i--)
251 {
252 if (x >= cardX && x <= cardX + Card::GetWidth() &&
253 y >= cardY && y <= cardY + Card::GetHeight())
254 {
255 return m_cards[i];
256 }
257 cardX -= (int)Card::GetScale()*m_dx;
258 cardY -= (int)Card::GetScale()*m_dy;
259 }
260 return 0;
261 }
262
263
264 // Return the position of the given card. If it is not a member of this pile
265 // return the origin of the pile.
266 void Pile::GetCardPos(Card* card, int& x, int& y)
267 {
268 x = m_x;
269 y = m_y;
270
271 for (int i = 0; i <= m_topCard; i++)
272 {
273 if (card == m_cards[i])
274 {
275 return;
276 }
277 x += (int)Card::GetScale()*m_dx;
278 y += (int)Card::GetScale()*m_dy;
279 }
280
281 // card not found in pile, return origin of pile
282 x = m_x;
283 y = m_y;
284 }
285
286
287 bool Pile::Overlap(int x, int y)
288 {
289 int cardX;
290 int cardY;
291 GetTopCardPos(cardX, cardY);
292
293 if (x >= cardX - Card::GetWidth() && x <= cardX + Card::GetWidth() &&
294 y >= cardY - Card::GetHeight() && y <= cardY + Card::GetHeight())
295 {
296 return TRUE;
297 }
298 return FALSE;
299 }
300
301
302 Pile::~Pile()
303 {
304 // nothing special at the moment
305 }