[KERNEL32]
[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
239 if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_OPTIONS), hwnd, OptionsDlgProc))
240 {
241 if ((dwOldOptions & OPTION_THREE_CARDS) != (dwOptions & OPTION_THREE_CARDS))
242 NewGame();
243
244 if ((dwOldOptions & OPTION_SHOW_STATUS) != (dwOptions & OPTION_SHOW_STATUS))
245 {
246 int nWidth, nHeight, nStatusHeight;
247
248 GetClientRect(hwndMain, &rcMain);
249 nHeight = rcMain.bottom - rcMain.top;
250 nWidth = rcMain.right - rcMain.left;
251
252 if (dwOptions & OPTION_SHOW_STATUS)
253 {
254 RECT rc;
255
256 ShowWindow(hwndStatus, SW_SHOW);
257 GetWindowRect(hwndStatus, &rcStatus);
258 nStatusHeight = rcStatus.bottom - rcStatus.top;
259 MoveWindow(SolWnd, 0, 0, nWidth, nHeight-nStatusHeight, TRUE);
260 MoveWindow(hwndStatus, 0, nHeight-nStatusHeight, nWidth, nHeight, TRUE);
261
262 // Force the window to process WM_GETMINMAXINFO again
263 GetWindowRect(hwndMain, &rc);
264 SetWindowPos(hwndMain, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
265 }
266 else
267 {
268 ShowWindow(hwndStatus, SW_HIDE);
269 MoveWindow(SolWnd, 0, 0, nWidth, nHeight, TRUE);
270 }
271 }
272 }
273 }
274
275
276 LRESULT CALLBACK
277 CardImageWndProc(HWND hwnd,
278 UINT msg,
279 WPARAM wParam,
280 LPARAM lParam)
281 {
282 PCARDBACK pCardBack = (PCARDBACK)GetWindowLongPtr(hwnd,
283 GWL_USERDATA);
284 static WNDPROC hOldProc = NULL;
285
286 if (!hOldProc && pCardBack)
287 hOldProc = pCardBack->hOldProc;
288
289 switch (msg)
290 {
291 case WM_PAINT:
292 {
293 HDC hdc;
294 PAINTSTRUCT ps;
295 HPEN hPen, hOldPen;
296 HBRUSH hBrush, hOldBrush;
297 RECT rc;
298
299 hdc = BeginPaint(hwnd, &ps);
300
301 if (pCardBack->bSelected)
302 {
303 hPen = CreatePen(PS_SOLID, 2, RGB(0,0,0));
304 }
305 else
306 {
307 DWORD Face = GetSysColor(COLOR_3DFACE);
308 hPen = CreatePen(PS_SOLID, 2, Face);
309 }
310
311 GetClientRect(hwnd, &rc);
312 hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
313 hOldPen = (HPEN)SelectObject(hdc, hPen);
314 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
315
316 Rectangle(hdc,
317 rc.left+1,
318 rc.top+1,
319 rc.right,
320 rc.bottom);
321
322 StretchBlt(hdc,
323 2,
324 2,
325 CARDBACK_OPTIONS_WIDTH,
326 CARDBACK_OPTIONS_HEIGHT,
327 __hdcCardBitmaps,
328 pCardBack->hdcNum * __cardwidth,
329 0,
330 __cardwidth,
331 __cardheight,
332 SRCCOPY);
333
334 SelectObject(hdc, hOldPen);
335 SelectObject(hdc, hOldBrush);
336
337 EndPaint(hwnd, &ps);
338
339 break;
340 }
341
342 case WM_LBUTTONDOWN:
343 pCardBack->bSelected = pCardBack->bSelected ? FALSE : TRUE;
344 break;
345 }
346
347 return CallWindowProc(hOldProc,
348 hwnd,
349 msg,
350 wParam,
351 lParam);
352 }
353
354
355 INT_PTR CALLBACK CardBackDlgProc(HWND hDlg,
356 UINT uMsg,
357 WPARAM wParam,
358 LPARAM lParam)
359 {
360 static PCARDBACK pCardBacks = NULL;
361
362 switch (uMsg)
363 {
364 case WM_INITDIALOG:
365 {
366 INT i, c;
367 SIZE_T size = sizeof(CARDBACK) * NUM_CARDBACKS;
368
369 pCardBacks = (PCARDBACK)HeapAlloc(GetProcessHeap(),
370 0,
371 size);
372
373 for (i = 0, c = CARDBACK_START; c <= CARDBACK_END; i++, c++)
374 {
375 pCardBacks[i].hSelf = GetDlgItem(hDlg, c);
376 pCardBacks[i].bSelected = FALSE;
377 pCardBacks[i].hdcNum = CARDBACK_RES_START + i;
378 pCardBacks[i].imgNum = i + 1;
379 pCardBacks[i].hOldProc = (WNDPROC)SetWindowLongPtr(pCardBacks[i].hSelf,
380 GWLP_WNDPROC,
381 (LONG_PTR)CardImageWndProc);
382
383 SetWindowLongPtr(pCardBacks[i].hSelf,
384 GWL_USERDATA,
385 (LONG_PTR)&pCardBacks[i]);
386 }
387
388 return TRUE;
389 }
390
391 case WM_COMMAND:
392 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
393 {
394 INT i, num = 0;
395 for (i = 0; i < NUM_CARDBACKS; i++)
396 {
397 if (pCardBacks[i].bSelected)
398 {
399 num = pCardBacks[i].imgNum;
400 }
401 }
402
403 EndDialog(hDlg, LOWORD(wParam) == IDOK ? num : FALSE);
404 HeapFree(GetProcessHeap(), 0, pCardBacks);
405 return TRUE;
406 }
407
408 if (HIWORD(wParam) == STN_CLICKED)
409 {
410 INT i;
411 RECT rc;
412 for (i = 0; i < NUM_CARDBACKS; i++)
413 {
414 if (pCardBacks[i].hSelf == (HWND)lParam)
415 {
416 pCardBacks[i].bSelected = TRUE;
417 }
418 else
419 pCardBacks[i].bSelected = FALSE;
420
421 GetClientRect(pCardBacks[i].hSelf, &rc);
422 InvalidateRect(pCardBacks[i].hSelf, &rc, TRUE);
423 }
424
425 break;
426 }
427 }
428
429 return FALSE;
430 }
431
432
433 VOID ShowDeckOptionsDlg(HWND hwnd)
434 {
435 INT cardBack;
436
437 if ((cardBack = DialogBox(hInstance,
438 MAKEINTRESOURCE(IDD_CARDBACK),
439 hwnd,
440 CardBackDlgProc)))
441 {
442 SolWnd.SetBackCardIdx(CARDBACK_RES_START + (cardBack - 1));
443 SolWnd.Redraw();
444 }
445 }
446
447 //-----------------------------------------------------------------------------
448 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
449 {
450 static int nWidth, nHeight, nStatusHeight;
451
452 switch(iMsg)
453 {
454 case WM_CREATE:
455 {
456 int parts[] = { 100, -1 };
457 RECT rcStatus;
458
459 hwndStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, _T("Ready"), hwnd, 0);
460
461 //SendMessage(hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0);
462
463 SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts);
464 SendMessage(hwndStatus, SB_SETTEXT, 0 | SBT_NOBORDERS, (LPARAM)"");
465
466 SolWnd.Create(hwnd, WS_EX_CLIENTEDGE, WS_CHILD|WS_VISIBLE, 0, 0, 0, 0);
467
468 CreateSol();
469
470 // The status bar height is fixed and needed later in WM_SIZE and WM_GETMINMAXINFO
471 // Force the window to process WM_GETMINMAXINFO again
472 GetWindowRect(hwndStatus, &rcStatus);
473 nStatusHeight = rcStatus.bottom - rcStatus.top;
474
475 // Hide status bar if options say so
476 if (!(dwOptions & OPTION_SHOW_STATUS))
477 {
478 ShowWindow(hwndStatus, SW_HIDE);
479 }
480
481 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
482
483 NewGame();
484
485 dwAppStartTime = GetTickCount();
486
487 return 0;
488 }
489
490 case WM_DESTROY:
491 PostQuitMessage(0);
492 return 0;
493
494 case WM_SIZE:
495 nWidth = LOWORD(lParam);
496 nHeight = HIWORD(lParam);
497
498 if (dwOptions & OPTION_SHOW_STATUS)
499 {
500 MoveWindow(SolWnd, 0, 0, nWidth, nHeight - nStatusHeight, TRUE);
501 MoveWindow(hwndStatus, 0, nHeight - nStatusHeight, nWidth, nStatusHeight, TRUE);
502 }
503 else
504 {
505 MoveWindow(SolWnd, 0, 0, nWidth, nHeight, TRUE);
506 }
507 //parts[0] = nWidth - 256;
508 //SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts);
509 return 0;
510
511 case WM_GETMINMAXINFO:
512 {
513 MINMAXINFO *mmi;
514
515 mmi = (MINMAXINFO *)lParam;
516 mmi->ptMinTrackSize.x = X_BORDER + NUM_ROW_STACKS * (__cardwidth + X_ROWSTACK_BORDER) + X_BORDER;
517 mmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION) +
518 GetSystemMetrics(SM_CYMENU) +
519 Y_BORDER +
520 __cardheight +
521 Y_ROWSTACK_BORDER +
522 6 * yRowStackCardOffset +
523 __cardheight +
524 Y_BORDER +
525 (dwOptions & OPTION_SHOW_STATUS ? nStatusHeight : 0);
526 return 0;
527 }
528
529 case WM_COMMAND:
530 switch(LOWORD(wParam))
531 {
532 case IDM_GAME_NEW:
533 //simulate a button click on the new button..
534 NewGame();
535 return 0;
536
537 case IDM_GAME_DECK:
538 ShowDeckOptionsDlg(hwnd);
539 return 0;
540
541 case IDM_GAME_OPTIONS:
542 ShowGameOptionsDlg(hwnd);
543 return 0;
544
545 case IDM_HELP_CONTENTS:
546 WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play");
547 return 0;
548
549 case IDM_HELP_ABOUT:
550 MessageBox(hwnd, MsgAbout, szAppName, MB_OK|MB_ICONINFORMATION);
551 return 0;
552
553 case IDM_GAME_EXIT:
554 PostMessage(hwnd, WM_CLOSE, 0, 0);
555 return 0;
556 }
557
558 return 0;
559
560 case WM_CLOSE:
561 if (fGameStarted == false)
562 {
563 DestroyWindow(hwnd);
564 return 0;
565 }
566 else
567 {
568 int ret;
569
570 ret = MessageBox(hwnd, MsgQuit, szAppName, MB_YESNO|MB_ICONQUESTION);
571 if (ret == IDYES)
572 {
573 WinHelp(hwnd, szHelpPath, HELP_QUIT, 0);
574 DestroyWindow(hwnd);
575 }
576 }
577 return 0;
578 }
579
580 return DefWindowProc (hwnd, iMsg, wParam, lParam);
581 }
582
583
584