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 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 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 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 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 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 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 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