1 /*
2 * PROJECT: Spider Solitaire
3 * LICENSE: See COPYING in top level directory
4 * FILE: base/applications/games/spider/spider.cpp
5 * PURPOSE: Window and message queue for Spider Solitaire
6 * PROGRAMMER: Gregor Schneider
7 */
8
9 #include "spider.h"
10
11 #include <commctrl.h>
12 #include <shellapi.h>
13 #include <tchar.h>
14
15 TCHAR szHelpPath[MAX_PATH];
16
17 DWORD dwAppStartTime;
18 HWND hwndMain;
19 HINSTANCE hInstance;
20
21 TCHAR szAppName[128];
22 TCHAR MsgQuit[128];
23 TCHAR MsgAbout[128];
24 TCHAR MsgWin[128];
25 TCHAR MsgDeal[128];
26 DWORD dwDifficulty;
27
28 CardWindow SpiderWnd;
29
30 typedef struct _CardBack
31 {
32 HWND hSelf;
33 WNDPROC hOldProc;
34 INT hdcNum;
35 INT imgNum;
36 BOOL bSelected;
37 } CARDBACK, *PCARDBACK;
38
39 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
40
MakePath(TCHAR * szDest,UINT nDestLen,const TCHAR * szExt)41 void MakePath(TCHAR *szDest, UINT nDestLen, const TCHAR *szExt)
42 {
43 TCHAR *ptr;
44
45 ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1;
46 while(*ptr-- != '.');
47 lstrcpy(ptr + 1, szExt);
48 }
49
DifficultyDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)50 INT_PTR CALLBACK DifficultyDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
51 {
52 switch (uMsg)
53 {
54 case WM_INITDIALOG:
55 CheckRadioButton(hDlg, IDC_DIF_ONECOLOR, IDC_DIF_FOURCOLORS, IDC_DIF_ONECOLOR);
56 return TRUE;
57
58 case WM_COMMAND:
59 switch(LOWORD(wParam))
60 {
61 case IDOK:
62 if (IsDlgButtonChecked(hDlg, IDC_DIF_ONECOLOR) == BST_CHECKED)
63 dwDifficulty = IDC_DIF_ONECOLOR;
64 else if (IsDlgButtonChecked(hDlg, IDC_DIF_TWOCOLORS) == BST_CHECKED)
65 dwDifficulty = IDC_DIF_TWOCOLORS;
66 else if (IsDlgButtonChecked(hDlg, IDC_DIF_FOURCOLORS) == BST_CHECKED)
67 dwDifficulty = IDC_DIF_FOURCOLORS;
68
69 NewGame();
70 EndDialog(hDlg, TRUE);
71 return TRUE;
72
73 case IDCANCEL:
74 EndDialog(hDlg, FALSE);
75 return TRUE;
76 }
77 break;
78 }
79 return FALSE;
80 }
81
_tWinMain(HINSTANCE hInst,HINSTANCE hPrev,LPTSTR szCmdLine,int iCmdShow)82 int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int iCmdShow)
83 {
84 HWND hwnd;
85 MSG msg;
86 WNDCLASS wndclass;
87 INITCOMMONCONTROLSEX ice;
88 HACCEL hAccelTable;
89
90 hInstance = hInst;
91
92 /* Load application title */
93 LoadString(hInst, IDS_SPI_NAME, szAppName, sizeof(szAppName) / sizeof(szAppName[0]));
94 /* Load MsgBox() texts here to avoid loading them many times later */
95 LoadString(hInst, IDS_SPI_ABOUT, MsgAbout, sizeof(MsgAbout) / sizeof(MsgAbout[0]));
96 LoadString(hInst, IDS_SPI_QUIT, MsgQuit, sizeof(MsgQuit) / sizeof(MsgQuit[0]));
97 LoadString(hInst, IDS_SPI_WIN, MsgWin, sizeof(MsgWin) / sizeof(MsgWin[0]));
98 LoadString(hInst, IDS_SPI_DEAL, MsgDeal, sizeof(MsgDeal) / sizeof(MsgDeal[0]));
99
100 /* Window class for the main application parent window */
101 wndclass.style = 0;
102 wndclass.lpfnWndProc = WndProc;
103 wndclass.cbClsExtra = 0;
104 wndclass.cbWndExtra = 0;
105 wndclass.hInstance = hInst;
106 wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_SPIDER));
107 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
108 wndclass.hbrBackground = (HBRUSH)NULL;
109 wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
110 wndclass.lpszClassName = szAppName;
111
112 RegisterClass(&wndclass);
113
114 ice.dwSize = sizeof(ice);
115 ice.dwICC = ICC_BAR_CLASSES;
116 InitCommonControlsEx(&ice);
117
118 srand((unsigned)GetTickCount());
119
120 /* InitCardLib(); */
121
122 /* Construct the path to our help file */
123 MakePath(szHelpPath, MAX_PATH, _T(".hlp"));
124
125 hwnd = CreateWindow(szAppName,
126 szAppName,
127 WS_OVERLAPPEDWINDOW,
128 CW_USEDEFAULT,
129 CW_USEDEFAULT,
130 0, /*The real size will be computed in WndProc through WM_GETMINMAXINFO */
131 0, /* The real size will be computed in WndProc through WM_GETMINMAXINFO */
132 NULL,
133 NULL,
134 hInst,
135 NULL);
136
137 hwndMain = hwnd;
138
139 ShowWindow(hwnd, iCmdShow);
140 UpdateWindow(hwnd);
141
142 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
143
144 DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIFFICULTY), hwnd, DifficultyDlgProc);
145
146 while (GetMessage(&msg, NULL,0,0))
147 {
148 if (!TranslateAccelerator(hwnd, hAccelTable, &msg))
149 {
150 TranslateMessage(&msg);
151 DispatchMessage(&msg);
152 }
153 }
154 return msg.wParam;
155 }
156
CardImageWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)157 LRESULT CALLBACK CardImageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
158 {
159 PCARDBACK pCardBack = (PCARDBACK)GetWindowLongPtr(hwnd, GWLP_USERDATA);
160 static WNDPROC hOldProc = NULL;
161
162 if (!pCardBack)
163 return FALSE;
164
165 if (!hOldProc)
166 hOldProc = pCardBack->hOldProc;
167
168 switch (msg)
169 {
170 case WM_PAINT:
171 {
172 HDC hdc;
173 PAINTSTRUCT ps;
174 HPEN hPen, hOldPen;
175 HBRUSH hBrush, hOldBrush;
176 RECT rc;
177
178 hdc = BeginPaint(hwnd, &ps);
179
180 if (pCardBack->bSelected)
181 {
182 hPen = CreatePen(PS_SOLID, 2, RGB(0,0,0));
183 }
184 else
185 {
186 DWORD Face = GetSysColor(COLOR_3DFACE);
187 hPen = CreatePen(PS_SOLID, 2, Face);
188 }
189
190 GetClientRect(hwnd, &rc);
191 hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
192 hOldPen = (HPEN)SelectObject(hdc, hPen);
193 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
194
195 Rectangle(hdc, rc.left+1, rc.top+1, rc.right, rc.bottom);
196
197 StretchBlt(hdc,
198 2,
199 2,
200 CARDBACK_OPTIONS_WIDTH,
201 CARDBACK_OPTIONS_HEIGHT,
202 __hdcCardBitmaps,
203 pCardBack->hdcNum * __cardwidth,
204 0,
205 __cardwidth,
206 __cardheight,
207 SRCCOPY);
208
209 SelectObject(hdc, hOldPen);
210 SelectObject(hdc, hOldBrush);
211
212 EndPaint(hwnd, &ps);
213
214 break;
215 }
216
217 case WM_LBUTTONDOWN:
218 pCardBack->bSelected = pCardBack->bSelected ? FALSE : TRUE;
219 break;
220 }
221
222 return CallWindowProc(hOldProc, hwnd, msg, wParam, lParam);
223 }
224
225
CardBackDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)226 INT_PTR CALLBACK CardBackDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
227 {
228 static PCARDBACK pCardBacks = NULL;
229
230 switch (uMsg)
231 {
232 case WM_INITDIALOG:
233 {
234 INT i, c;
235 SIZE_T size = sizeof(CARDBACK) * NUM_CARDBACKS;
236
237 pCardBacks = (PCARDBACK)HeapAlloc(GetProcessHeap(), 0, size);
238
239 if (!pCardBacks)
240 return FALSE;
241
242 for (i = 0, c = CARDBACK_START; c <= CARDBACK_END; i++, c++)
243 {
244 pCardBacks[i].hSelf = GetDlgItem(hDlg, c);
245 pCardBacks[i].bSelected = FALSE;
246 pCardBacks[i].hdcNum = CARDBACK_RES_START + i;
247 pCardBacks[i].imgNum = i + 1;
248 pCardBacks[i].hOldProc = (WNDPROC)SetWindowLongPtr(pCardBacks[i].hSelf,
249 GWLP_WNDPROC,
250 (LONG_PTR)CardImageWndProc);
251
252 SetWindowLongPtr(pCardBacks[i].hSelf, GWLP_USERDATA, (LONG_PTR)&pCardBacks[i]);
253 }
254
255 return TRUE;
256 }
257
258 case WM_COMMAND:
259 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
260 {
261 INT i, num = 0;
262 for (i = 0; i < NUM_CARDBACKS; i++)
263 {
264 if (pCardBacks[i].bSelected)
265 {
266 num = pCardBacks[i].imgNum;
267 }
268 }
269
270 EndDialog(hDlg, LOWORD(wParam) == IDOK ? num : FALSE);
271 HeapFree(GetProcessHeap(), 0, pCardBacks);
272 return TRUE;
273 }
274
275 if (HIWORD(wParam) == STN_CLICKED)
276 {
277 INT i;
278 RECT rc;
279 for (i = 0; i < NUM_CARDBACKS; i++)
280 {
281 pCardBacks[i].bSelected = pCardBacks[i].hSelf == (HWND)lParam;
282
283 GetClientRect(pCardBacks[i].hSelf, &rc);
284 InvalidateRect(pCardBacks[i].hSelf, &rc, TRUE);
285 }
286
287 break;
288 }
289 }
290
291 return FALSE;
292 }
293
294
ShowDeckOptionsDlg(HWND hwnd)295 VOID ShowDeckOptionsDlg(HWND hwnd)
296 {
297 INT cardBack;
298
299 if ((cardBack = DialogBox(hInstance, MAKEINTRESOURCE(IDD_CARDBACK), hwnd, CardBackDlgProc)))
300 {
301 SpiderWnd.SetBackCardIdx(CARDBACK_RES_START + (cardBack - 1));
302 SpiderWnd.Redraw();
303 }
304 }
305
WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)306 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
307 {
308 static int nWidth, nHeight;
309
310 switch (iMsg)
311 {
312 case WM_CREATE:
313 {
314 // For now, the Help dialog is disabled because of lacking of HTML Help support
315 EnableMenuItem(GetMenu(hwnd), IDM_HELP_CONTENTS, MF_BYCOMMAND | MF_GRAYED);
316
317 SpiderWnd.Create(hwnd, 0, WS_CHILD | WS_VISIBLE, 0, 0, 100, 100);
318 dwDifficulty = IDC_DIF_ONECOLOR;
319 CreateSpider();
320
321 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
322
323 dwAppStartTime = GetTickCount();
324
325 return 0;
326 }
327
328 case WM_DESTROY:
329 PostQuitMessage(0);
330 return 0;
331
332 case WM_SIZE:
333 nWidth = LOWORD(lParam);
334 nHeight = HIWORD(lParam);
335
336 MoveWindow(SpiderWnd, 0, 0, nWidth, nHeight, TRUE);
337 return 0;
338
339 case WM_GETMINMAXINFO:
340 {
341 MINMAXINFO *mmi;
342
343 mmi = (MINMAXINFO *)lParam;
344 mmi->ptMinTrackSize.x = NUM_STACKS * __cardwidth + (NUM_STACKS + 3) * X_BORDER + 12; // Border left and right of 6px
345 mmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION) +
346 GetSystemMetrics(SM_CYMENU) +
347 2 * Y_BORDER +
348 3 * __cardheight +
349 6 * yRowStackCardOffset;
350 return 0;
351 }
352
353 case WM_COMMAND:
354 switch (LOWORD(wParam))
355 {
356 case IDM_GAME_NEW:
357 NewGame();
358 return 0;
359
360 case IDM_GAME_DECK:
361 ShowDeckOptionsDlg(hwnd);
362 return 0;
363
364 case IDM_HELP_CONTENTS:
365 WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play");
366 return 0;
367
368 case IDM_HELP_ABOUT:
369 ShellAbout(hwnd, szAppName, MsgAbout,
370 LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SPIDER)));
371 return 0;
372
373 case IDM_GAME_EXIT:
374 PostMessage(hwnd, WM_CLOSE, 0, 0);
375 return 0;
376 }
377
378 return 0;
379
380 case WM_CLOSE:
381 if (fGameStarted == false)
382 {
383 DestroyWindow(hwnd);
384 return 0;
385 }
386 else
387 {
388 int ret;
389
390 ret = MessageBox(hwnd, MsgQuit, szAppName, MB_YESNO|MB_ICONQUESTION);
391 if (ret == IDYES)
392 {
393 WinHelp(hwnd, szHelpPath, HELP_QUIT, 0);
394 DestroyWindow(hwnd);
395 }
396 }
397 return 0;
398 }
399 return DefWindowProc (hwnd, iMsg, wParam, lParam);
400 }
401
402