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