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