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