bf45a53e9bd0ef3e2e732b3c96a7b21f8a7bdcbf
[reactos.git] / base / applications / games / solitaire / solitaire.cpp
1
2 #include "solitaire.h"
3
4 TCHAR szHelpPath[MAX_PATH];
5
6 DWORD dwAppStartTime;
7 HWND hwndMain;
8 HWND hwndStatus;
9 HINSTANCE hInstance;
10
11 TCHAR szAppName[128];
12 TCHAR MsgQuit[128];
13 TCHAR MsgAbout[128];
14 TCHAR MsgWin[128];
15 TCHAR MsgDeal[128];
16 DWORD dwOptions = OPTION_THREE_CARDS;
17
18 CardWindow SolWnd;
19
20 typedef struct _CardBack
21 {
22 HWND hSelf;
23 WNDPROC hOldProc;
24 INT hdcNum;
25 INT imgNum;
26 BOOL bSelected;
27 } CARDBACK, *PCARDBACK;
28
29 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
30
31 void MakePath(TCHAR *szDest, UINT nDestLen, const TCHAR *szExt)
32 {
33 TCHAR *ptr;
34
35 ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1;
36 while(*ptr-- != '.');
37 lstrcpy(ptr + 1, szExt);
38 }
39
40 VOID LoadSettings(VOID)
41 {
42 DWORD dwDisposition;
43 DWORD dwSize;
44 DWORD dwBack;
45 HKEY hKey;
46
47 if (RegCreateKeyEx(HKEY_CURRENT_USER,
48 _T("Software\\ReactOS\\Solitaire"),
49 0,
50 NULL,
51 REG_OPTION_NON_VOLATILE,
52 KEY_READ,
53 NULL,
54 &hKey,
55 &dwDisposition))
56 return;
57
58 dwSize = sizeof(DWORD);
59 RegQueryValueEx(hKey,
60 _T("Options"),
61 NULL,
62 NULL,
63 (LPBYTE)&dwOptions,
64 &dwSize);
65
66 dwSize = sizeof(DWORD);
67 RegQueryValueEx(hKey,
68 _T("Back"),
69 NULL,
70 NULL,
71 (LPBYTE)&dwBack,
72 &dwSize);
73 SolWnd.SetBackCardIdx(dwBack);
74
75 RegCloseKey(hKey);
76 }
77
78 VOID SaveSettings(VOID)
79 {
80 DWORD dwDisposition;
81 DWORD dwBack;
82 HKEY hKey;
83
84 if (RegCreateKeyEx(HKEY_CURRENT_USER,
85 _T("Software\\ReactOS\\Solitaire"),
86 0,
87 NULL,
88 REG_OPTION_NON_VOLATILE,
89 KEY_WRITE,
90 NULL,
91 &hKey,
92 &dwDisposition))
93 return;
94
95 RegSetValueEx(hKey,
96 _T("Options"),
97 0,
98 REG_DWORD,
99 (CONST BYTE *)&dwOptions,
100 sizeof(DWORD));
101
102 dwBack = SolWnd.GetBackCardIdx();
103 RegSetValueEx(hKey,
104 _T("Back"),
105 0,
106 REG_DWORD,
107 (CONST BYTE *)&dwBack,
108 sizeof(DWORD));
109
110 RegCloseKey(hKey);
111 }
112
113 //
114 // Main entry point
115 //
116 int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int iCmdShow)
117 {
118 HWND hwnd;
119 MSG msg;
120 WNDCLASS wndclass;
121 INITCOMMONCONTROLSEX ice;
122 HACCEL hAccelTable;
123
124 hInstance = hInst;
125
126 // Load application title
127 LoadString(hInst, IDS_SOL_NAME, szAppName, sizeof(szAppName) / sizeof(szAppName[0]));
128 // Load MsgBox() texts here to avoid loading them many times later
129 LoadString(hInst, IDS_SOL_ABOUT, MsgAbout, sizeof(MsgAbout) / sizeof(MsgAbout[0]));
130 LoadString(hInst, IDS_SOL_QUIT, MsgQuit, sizeof(MsgQuit) / sizeof(MsgQuit[0]));
131 LoadString(hInst, IDS_SOL_WIN, MsgWin, sizeof(MsgWin) / sizeof(MsgWin[0]));
132 LoadString(hInst, IDS_SOL_DEAL, MsgDeal, sizeof(MsgDeal) / sizeof(MsgDeal[0]));
133
134 //Window class for the main application parent window
135 wndclass.style = 0;//CS_HREDRAW | CS_VREDRAW;
136 wndclass.lpfnWndProc = WndProc;
137 wndclass.cbClsExtra = 0;
138 wndclass.cbWndExtra = 0;
139 wndclass.hInstance = hInst;
140 wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_SOLITAIRE));
141 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
142 wndclass.hbrBackground = (HBRUSH)NULL;
143 wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
144 wndclass.lpszClassName = szAppName;
145
146 RegisterClass(&wndclass);
147
148 ice.dwSize = sizeof(ice);
149 ice.dwICC = ICC_BAR_CLASSES;
150 InitCommonControlsEx(&ice);
151
152 srand((unsigned)GetTickCount());//timeGetTime());
153
154 // InitCardLib();
155
156 LoadSettings();
157
158 //Construct the path to our help file
159 MakePath(szHelpPath, MAX_PATH, _T(".hlp"));
160
161 hwnd = CreateWindow(szAppName, // window class name
162 szAppName, // window caption
163 WS_OVERLAPPEDWINDOW
164 ,//|WS_CLIPCHILDREN, // window style
165 CW_USEDEFAULT, // initial x position
166 CW_USEDEFAULT, // initial y position
167 0, // The real size will be computed in WndProc through WM_GETMINMAXINFO
168 0, // The real size will be computed in WndProc through WM_GETMINMAXINFO
169 NULL, // parent window handle
170 NULL, // use window class menu
171 hInst, // program instance handle
172 NULL); // creation parameters
173
174 hwndMain = hwnd;
175
176 ShowWindow(hwnd, iCmdShow);
177 UpdateWindow(hwnd);
178
179 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
180
181 while(GetMessage(&msg, NULL,0,0))
182 {
183 if(!TranslateAccelerator(hwnd, hAccelTable, &msg))
184 {
185 TranslateMessage(&msg);
186 DispatchMessage(&msg);
187 }
188 }
189
190 SaveSettings();
191
192 return msg.wParam;
193 }
194
195
196 INT_PTR CALLBACK OptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
197 {
198 switch (uMsg)
199 {
200 case WM_INITDIALOG:
201 CheckRadioButton(hDlg, IDC_OPT_DRAWONE, IDC_OPT_DRAWTHREE,
202 (dwOptions & OPTION_THREE_CARDS) ? IDC_OPT_DRAWTHREE : IDC_OPT_DRAWONE);
203
204 CheckDlgButton(hDlg,
205 IDC_OPT_STATUSBAR,
206 (dwOptions & OPTION_SHOW_STATUS) ? BST_CHECKED : BST_UNCHECKED);
207 return TRUE;
208
209 case WM_COMMAND:
210 switch(LOWORD(wParam))
211 {
212 case IDOK:
213 dwOptions &= ~OPTION_THREE_CARDS;
214 if (IsDlgButtonChecked(hDlg, IDC_OPT_DRAWTHREE) == BST_CHECKED)
215 dwOptions |= OPTION_THREE_CARDS;
216
217 if (IsDlgButtonChecked(hDlg, IDC_OPT_STATUSBAR) == BST_CHECKED)
218 dwOptions |= OPTION_SHOW_STATUS;
219 else
220 dwOptions &= ~OPTION_SHOW_STATUS;
221
222 EndDialog(hDlg, TRUE);
223 return TRUE;
224
225 case IDCANCEL:
226 EndDialog(hDlg, FALSE);
227 return TRUE;
228 }
229 break;
230 }
231 return FALSE;
232 }
233
234 VOID ShowGameOptionsDlg(HWND hwnd)
235 {
236 DWORD dwOldOptions = dwOptions;
237 RECT rcMain, rcStatus;
238 int nWidth, nHeight, nStatusHeight;
239
240 if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_OPTIONS), hwnd, OptionsDlgProc))
241 {
242 if ((dwOldOptions & OPTION_THREE_CARDS) != (dwOptions & OPTION_THREE_CARDS))
243 NewGame();
244
245 if ((dwOldOptions & OPTION_SHOW_STATUS) != (dwOptions & OPTION_SHOW_STATUS))
246 {
247 GetClientRect(hwndMain, &rcMain);
248 nHeight = rcMain.bottom - rcMain.top;
249 nWidth = rcMain.right - rcMain.left;
250
251 if (dwOptions & OPTION_SHOW_STATUS)
252 {
253 RECT rc;
254
255 ShowWindow(hwndStatus, SW_SHOW);
256 GetWindowRect(hwndStatus, &rcStatus);
257 nStatusHeight = rcStatus.bottom - rcStatus.top;
258 MoveWindow(SolWnd, 0, 0, nWidth, nHeight-nStatusHeight, TRUE);
259 MoveWindow(hwndStatus, 0, nHeight-nStatusHeight, nWidth, nHeight, TRUE);
260
261 // Force the window to process WM_GETMINMAXINFO again
262 GetWindowRect(hwndMain, &rc);
263 SetWindowPos(hwndMain, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
264 }
265 else
266 {
267 ShowWindow(hwndStatus, SW_HIDE);
268 MoveWindow(SolWnd, 0, 0, nWidth, nHeight, TRUE);
269 }
270 }
271 }
272 }
273
274
275 LRESULT CALLBACK
276 CardImageWndProc(HWND hwnd,
277 UINT msg,
278 WPARAM wParam,
279 LPARAM lParam)
280 {
281 PCARDBACK pCardBack = (PCARDBACK)GetWindowLongPtr(hwnd,
282 GWL_USERDATA);
283 static WNDPROC hOldProc = NULL;
284
285 if (!hOldProc && pCardBack)
286 hOldProc = pCardBack->hOldProc;
287
288 switch (msg)
289 {
290 case WM_PAINT:
291 {
292 HDC hdc;
293 PAINTSTRUCT ps;
294 HPEN hPen, hOldPen;
295 HBRUSH hBrush, hOldBrush;
296 RECT rc;
297
298 hdc = BeginPaint(hwnd, &ps);
299
300 if (pCardBack->bSelected)
301 {
302 hPen = CreatePen(PS_SOLID, 2, RGB(0,0,0));
303 }
304 else
305 {
306 DWORD Face = GetSysColor(COLOR_3DFACE);
307 hPen = CreatePen(PS_SOLID, 2, Face);
308 }
309
310 GetClientRect(hwnd, &rc);
311 hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
312 hOldPen = (HPEN)SelectObject(hdc, hPen);
313 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
314
315 Rectangle(hdc,
316 rc.left+1,
317 rc.top+1,
318 rc.right,
319 rc.bottom);
320
321 StretchBlt(hdc,
322 2,
323 2,
324 CARDBACK_OPTIONS_WIDTH,
325 CARDBACK_OPTIONS_HEIGHT,
326 __hdcCardBitmaps,
327 pCardBack->hdcNum * __cardwidth,
328 0,
329 __cardwidth,
330 __cardheight,
331 SRCCOPY);
332
333 SelectObject(hdc, hOldPen);
334 SelectObject(hdc, hOldBrush);
335
336 EndPaint(hwnd, &ps);
337
338 break;
339 }
340
341 case WM_LBUTTONDOWN:
342 pCardBack->bSelected = pCardBack->bSelected ? FALSE : TRUE;
343 break;
344 }
345
346 return CallWindowProc(hOldProc,
347 hwnd,
348 msg,
349 wParam,
350 lParam);
351 }
352
353
354 INT_PTR CALLBACK CardBackDlgProc(HWND hDlg,
355 UINT uMsg,
356 WPARAM wParam,
357 LPARAM lParam)
358 {
359 static PCARDBACK pCardBacks = NULL;
360
361 switch (uMsg)
362 {
363 case WM_INITDIALOG:
364 {
365 INT i, c;
366 SIZE_T size = sizeof(CARDBACK) * NUM_CARDBACKS;
367
368 pCardBacks = (PCARDBACK)HeapAlloc(GetProcessHeap(),
369 0,
370 size);
371
372 for (i = 0, c = CARDBACK_START; c <= CARDBACK_END; i++, c++)
373 {
374 pCardBacks[i].hSelf = GetDlgItem(hDlg, c);
375 pCardBacks[i].bSelected = FALSE;
376 pCardBacks[i].hdcNum = CARDBACK_RES_START + i;
377 pCardBacks[i].imgNum = i + 1;
378 pCardBacks[i].hOldProc = (WNDPROC)SetWindowLongPtr(pCardBacks[i].hSelf,
379 GWLP_WNDPROC,
380 (LONG_PTR)CardImageWndProc);
381
382 SetWindowLongPtr(pCardBacks[i].hSelf,
383 GWL_USERDATA,
384 (LONG_PTR)&pCardBacks[i]);
385 }
386
387 return TRUE;
388 }
389
390 case WM_COMMAND:
391 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
392 {
393 INT i, num = 0;
394 for (i = 0; i < NUM_CARDBACKS; i++)
395 {
396 if (pCardBacks[i].bSelected)
397 {
398 num = pCardBacks[i].imgNum;
399 }
400 }
401
402 EndDialog(hDlg, LOWORD(wParam) == IDOK ? num : FALSE);
403 HeapFree(GetProcessHeap(), 0, pCardBacks);
404 return TRUE;
405 }
406
407 if (HIWORD(wParam) == STN_CLICKED)
408 {
409 INT i;
410 RECT rc;
411 for (i = 0; i < NUM_CARDBACKS; i++)
412 {
413 if (pCardBacks[i].hSelf == (HWND)lParam)
414 {
415 pCardBacks[i].bSelected = TRUE;
416 }
417 else
418 pCardBacks[i].bSelected = FALSE;
419
420 GetClientRect(pCardBacks[i].hSelf, &rc);
421 InvalidateRect(pCardBacks[i].hSelf, &rc, TRUE);
422 }
423
424 break;
425 }
426 }
427
428 return FALSE;
429 }
430
431
432 VOID ShowDeckOptionsDlg(HWND hwnd)
433 {
434 INT cardBack;
435
436 if ((cardBack = DialogBox(hInstance,
437 MAKEINTRESOURCE(IDD_CARDBACK),
438 hwnd,
439 CardBackDlgProc)))
440 {
441 SolWnd.SetBackCardIdx(CARDBACK_RES_START + (cardBack - 1));
442 SolWnd.Redraw();
443 }
444 }
445
446 //-----------------------------------------------------------------------------
447 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
448 {
449 static int nWidth, nHeight, nStatusHeight;
450
451 switch(iMsg)
452 {
453 case WM_CREATE:
454 {
455 int parts[] = { 100, -1 };
456 RECT rcStatus;
457
458 hwndStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, _T("Ready"), hwnd, 0);
459
460 //SendMessage(hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0);
461
462 SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts);
463 SendMessage(hwndStatus, SB_SETTEXT, 0 | SBT_NOBORDERS, (LPARAM)"");
464
465 SolWnd.Create(hwnd, WS_EX_CLIENTEDGE, WS_CHILD|WS_VISIBLE, 0, 0, 0, 0);
466
467 CreateSol();
468
469 // The status bar height is fixed and needed later in WM_SIZE and WM_GETMINMAXINFO
470 // Force the window to process WM_GETMINMAXINFO again
471 GetWindowRect(hwndStatus, &rcStatus);
472 nStatusHeight = rcStatus.bottom - rcStatus.top;
473
474 // Hide status bar if options say so
475 if (!(dwOptions & OPTION_SHOW_STATUS))
476 {
477 ShowWindow(hwndStatus, SW_HIDE);
478 }
479
480 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
481
482 NewGame();
483
484 dwAppStartTime = GetTickCount();
485
486 return 0;
487 }
488
489 case WM_DESTROY:
490 PostQuitMessage(0);
491 return 0;
492
493 case WM_SIZE:
494 nWidth = LOWORD(lParam);
495 nHeight = HIWORD(lParam);
496
497 if (dwOptions & OPTION_SHOW_STATUS)
498 {
499 MoveWindow(SolWnd, 0, 0, nWidth, nHeight - nStatusHeight, TRUE);
500 MoveWindow(hwndStatus, 0, nHeight - nStatusHeight, nWidth, nStatusHeight, TRUE);
501 }
502 else
503 {
504 MoveWindow(SolWnd, 0, 0, nWidth, nHeight, TRUE);
505 }
506 //parts[0] = nWidth - 256;
507 //SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts);
508 return 0;
509
510 case WM_GETMINMAXINFO:
511 {
512 MINMAXINFO *mmi;
513
514 mmi = (MINMAXINFO *)lParam;
515 mmi->ptMinTrackSize.x = X_BORDER + NUM_ROW_STACKS * (__cardwidth + X_ROWSTACK_BORDER) + X_BORDER;
516 mmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION) +
517 GetSystemMetrics(SM_CYMENU) +
518 Y_BORDER +
519 __cardheight +
520 Y_ROWSTACK_BORDER +
521 6 * yRowStackCardOffset +
522 __cardheight +
523 Y_BORDER +
524 (dwOptions & OPTION_SHOW_STATUS ? nStatusHeight : 0);
525 return 0;
526 }
527
528 case WM_COMMAND:
529 switch(LOWORD(wParam))
530 {
531 case IDM_GAME_NEW:
532 //simulate a button click on the new button..
533 NewGame();
534 return 0;
535
536 case IDM_GAME_DECK:
537 ShowDeckOptionsDlg(hwnd);
538 return 0;
539
540 case IDM_GAME_OPTIONS:
541 ShowGameOptionsDlg(hwnd);
542 return 0;
543
544 case IDM_HELP_CONTENTS:
545 WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play");
546 return 0;
547
548 case IDM_HELP_ABOUT:
549 MessageBox(hwnd, MsgAbout, szAppName, MB_OK|MB_ICONINFORMATION);
550 return 0;
551
552 case IDM_GAME_EXIT:
553 PostMessage(hwnd, WM_CLOSE, 0, 0);
554 return 0;
555 }
556
557 return 0;
558
559 case WM_CLOSE:
560 if (fGameStarted == false)
561 {
562 DestroyWindow(hwnd);
563 return 0;
564 }
565 else
566 {
567 int ret;
568
569 ret = MessageBox(hwnd, MsgQuit, szAppName, MB_OKCANCEL|MB_ICONQUESTION);
570 if (ret == IDOK)
571 {
572 WinHelp(hwnd, szHelpPath, HELP_QUIT, 0);
573 DestroyWindow(hwnd);
574 }
575 }
576 return 0;
577 }
578
579 return DefWindowProc (hwnd, iMsg, wParam, lParam);
580 }
581
582
583