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 <tchar.h> 13 14 TCHAR szHelpPath[MAX_PATH]; 15 16 DWORD dwAppStartTime; 17 HWND hwndMain; 18 HINSTANCE hInstance; 19 20 TCHAR szAppName[128]; 21 TCHAR MsgQuit[128]; 22 TCHAR MsgAbout[128]; 23 TCHAR MsgWin[128]; 24 TCHAR MsgDeal[128]; 25 DWORD dwDifficulty; 26 27 CardWindow SpiderWnd; 28 29 typedef struct _CardBack 30 { 31 HWND hSelf; 32 WNDPROC hOldProc; 33 INT hdcNum; 34 INT imgNum; 35 BOOL bSelected; 36 } CARDBACK, *PCARDBACK; 37 38 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); 39 40 void MakePath(TCHAR *szDest, UINT nDestLen, const TCHAR *szExt) 41 { 42 TCHAR *ptr; 43 44 ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1; 45 while(*ptr-- != '.'); 46 lstrcpy(ptr + 1, szExt); 47 } 48 49 INT_PTR CALLBACK DifficultyDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 50 { 51 switch (uMsg) 52 { 53 case WM_INITDIALOG: 54 CheckRadioButton(hDlg, IDC_DIF_ONECOLOR, IDC_DIF_FOURCOLORS, IDC_DIF_ONECOLOR); 55 return TRUE; 56 57 case WM_COMMAND: 58 switch(LOWORD(wParam)) 59 { 60 case IDOK: 61 if (IsDlgButtonChecked(hDlg, IDC_DIF_ONECOLOR) == BST_CHECKED) 62 dwDifficulty = IDC_DIF_ONECOLOR; 63 else if (IsDlgButtonChecked(hDlg, IDC_DIF_TWOCOLORS) == BST_CHECKED) 64 dwDifficulty = IDC_DIF_TWOCOLORS; 65 else if (IsDlgButtonChecked(hDlg, IDC_DIF_FOURCOLORS) == BST_CHECKED) 66 dwDifficulty = IDC_DIF_FOURCOLORS; 67 68 NewGame(); 69 EndDialog(hDlg, TRUE); 70 return TRUE; 71 72 case IDCANCEL: 73 EndDialog(hDlg, FALSE); 74 return TRUE; 75 } 76 break; 77 } 78 return FALSE; 79 } 80 81 int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int iCmdShow) 82 { 83 HWND hwnd; 84 MSG msg; 85 WNDCLASS wndclass; 86 INITCOMMONCONTROLSEX ice; 87 HACCEL hAccelTable; 88 89 hInstance = hInst; 90 91 /* Load application title */ 92 LoadString(hInst, IDS_SPI_NAME, szAppName, sizeof(szAppName) / sizeof(szAppName[0])); 93 /* Load MsgBox() texts here to avoid loading them many times later */ 94 LoadString(hInst, IDS_SPI_ABOUT, MsgAbout, sizeof(MsgAbout) / sizeof(MsgAbout[0])); 95 LoadString(hInst, IDS_SPI_QUIT, MsgQuit, sizeof(MsgQuit) / sizeof(MsgQuit[0])); 96 LoadString(hInst, IDS_SPI_WIN, MsgWin, sizeof(MsgWin) / sizeof(MsgWin[0])); 97 LoadString(hInst, IDS_SPI_DEAL, MsgDeal, sizeof(MsgDeal) / sizeof(MsgDeal[0])); 98 99 /* Window class for the main application parent window */ 100 wndclass.style = 0; 101 wndclass.lpfnWndProc = WndProc; 102 wndclass.cbClsExtra = 0; 103 wndclass.cbWndExtra = 0; 104 wndclass.hInstance = hInst; 105 wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_SPIDER)); 106 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); 107 wndclass.hbrBackground = (HBRUSH)NULL; 108 wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); 109 wndclass.lpszClassName = szAppName; 110 111 RegisterClass(&wndclass); 112 113 ice.dwSize = sizeof(ice); 114 ice.dwICC = ICC_BAR_CLASSES; 115 InitCommonControlsEx(&ice); 116 117 srand((unsigned)GetTickCount()); 118 119 /* InitCardLib(); */ 120 121 /* Construct the path to our help file */ 122 MakePath(szHelpPath, MAX_PATH, _T(".hlp")); 123 124 hwnd = CreateWindow(szAppName, 125 szAppName, 126 WS_OVERLAPPEDWINDOW, 127 CW_USEDEFAULT, 128 CW_USEDEFAULT, 129 0, /*The real size will be computed in WndProc through WM_GETMINMAXINFO */ 130 0, /* The real size will be computed in WndProc through WM_GETMINMAXINFO */ 131 NULL, 132 NULL, 133 hInst, 134 NULL); 135 136 hwndMain = hwnd; 137 138 ShowWindow(hwnd, iCmdShow); 139 UpdateWindow(hwnd); 140 141 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); 142 143 DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIFFICULTY), hwnd, DifficultyDlgProc); 144 145 while (GetMessage(&msg, NULL,0,0)) 146 { 147 if (!TranslateAccelerator(hwnd, hAccelTable, &msg)) 148 { 149 TranslateMessage(&msg); 150 DispatchMessage(&msg); 151 } 152 } 153 return msg.wParam; 154 } 155 156 LRESULT CALLBACK CardImageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 157 { 158 PCARDBACK pCardBack = (PCARDBACK)GetWindowLongPtr(hwnd, GWLP_USERDATA); 159 static WNDPROC hOldProc = NULL; 160 161 if (!pCardBack) 162 return FALSE; 163 164 if (!hOldProc) 165 hOldProc = pCardBack->hOldProc; 166 167 switch (msg) 168 { 169 case WM_PAINT: 170 { 171 HDC hdc; 172 PAINTSTRUCT ps; 173 HPEN hPen, hOldPen; 174 HBRUSH hBrush, hOldBrush; 175 RECT rc; 176 177 hdc = BeginPaint(hwnd, &ps); 178 179 if (pCardBack->bSelected) 180 { 181 hPen = CreatePen(PS_SOLID, 2, RGB(0,0,0)); 182 } 183 else 184 { 185 DWORD Face = GetSysColor(COLOR_3DFACE); 186 hPen = CreatePen(PS_SOLID, 2, Face); 187 } 188 189 GetClientRect(hwnd, &rc); 190 hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); 191 hOldPen = (HPEN)SelectObject(hdc, hPen); 192 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); 193 194 Rectangle(hdc, rc.left+1, rc.top+1, rc.right, rc.bottom); 195 196 StretchBlt(hdc, 197 2, 198 2, 199 CARDBACK_OPTIONS_WIDTH, 200 CARDBACK_OPTIONS_HEIGHT, 201 __hdcCardBitmaps, 202 pCardBack->hdcNum * __cardwidth, 203 0, 204 __cardwidth, 205 __cardheight, 206 SRCCOPY); 207 208 SelectObject(hdc, hOldPen); 209 SelectObject(hdc, hOldBrush); 210 211 EndPaint(hwnd, &ps); 212 213 break; 214 } 215 216 case WM_LBUTTONDOWN: 217 pCardBack->bSelected = pCardBack->bSelected ? FALSE : TRUE; 218 break; 219 } 220 221 return CallWindowProc(hOldProc, hwnd, msg, wParam, lParam); 222 } 223 224 225 INT_PTR CALLBACK CardBackDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 226 { 227 static PCARDBACK pCardBacks = NULL; 228 229 switch (uMsg) 230 { 231 case WM_INITDIALOG: 232 { 233 INT i, c; 234 SIZE_T size = sizeof(CARDBACK) * NUM_CARDBACKS; 235 236 pCardBacks = (PCARDBACK)HeapAlloc(GetProcessHeap(), 0, size); 237 238 if (!pCardBacks) 239 return FALSE; 240 241 for (i = 0, c = CARDBACK_START; c <= CARDBACK_END; i++, c++) 242 { 243 pCardBacks[i].hSelf = GetDlgItem(hDlg, c); 244 pCardBacks[i].bSelected = FALSE; 245 pCardBacks[i].hdcNum = CARDBACK_RES_START + i; 246 pCardBacks[i].imgNum = i + 1; 247 pCardBacks[i].hOldProc = (WNDPROC)SetWindowLongPtr(pCardBacks[i].hSelf, 248 GWLP_WNDPROC, 249 (LONG_PTR)CardImageWndProc); 250 251 SetWindowLongPtr(pCardBacks[i].hSelf, GWLP_USERDATA, (LONG_PTR)&pCardBacks[i]); 252 } 253 254 return TRUE; 255 } 256 257 case WM_COMMAND: 258 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 259 { 260 INT i, num = 0; 261 for (i = 0; i < NUM_CARDBACKS; i++) 262 { 263 if (pCardBacks[i].bSelected) 264 { 265 num = pCardBacks[i].imgNum; 266 } 267 } 268 269 EndDialog(hDlg, LOWORD(wParam) == IDOK ? num : FALSE); 270 HeapFree(GetProcessHeap(), 0, pCardBacks); 271 return TRUE; 272 } 273 274 if (HIWORD(wParam) == STN_CLICKED) 275 { 276 INT i; 277 RECT rc; 278 for (i = 0; i < NUM_CARDBACKS; i++) 279 { 280 pCardBacks[i].bSelected = pCardBacks[i].hSelf == (HWND)lParam; 281 282 GetClientRect(pCardBacks[i].hSelf, &rc); 283 InvalidateRect(pCardBacks[i].hSelf, &rc, TRUE); 284 } 285 286 break; 287 } 288 } 289 290 return FALSE; 291 } 292 293 294 VOID ShowDeckOptionsDlg(HWND hwnd) 295 { 296 INT cardBack; 297 298 if ((cardBack = DialogBox(hInstance, MAKEINTRESOURCE(IDD_CARDBACK), hwnd, CardBackDlgProc))) 299 { 300 SpiderWnd.SetBackCardIdx(CARDBACK_RES_START + (cardBack - 1)); 301 SpiderWnd.Redraw(); 302 } 303 } 304 305 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 306 { 307 static int nWidth, nHeight; 308 309 switch (iMsg) 310 { 311 case WM_CREATE: 312 { 313 // For now, the Help dialog is disabled because of lacking of HTML Help support 314 EnableMenuItem(GetMenu(hwnd), IDM_HELP_CONTENTS, MF_BYCOMMAND | MF_GRAYED); 315 316 SpiderWnd.Create(hwnd, 0, WS_CHILD | WS_VISIBLE, 0, 0, 100, 100); 317 dwDifficulty = IDC_DIF_ONECOLOR; 318 CreateSpider(); 319 320 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER); 321 322 dwAppStartTime = GetTickCount(); 323 324 return 0; 325 } 326 327 case WM_DESTROY: 328 PostQuitMessage(0); 329 return 0; 330 331 case WM_SIZE: 332 nWidth = LOWORD(lParam); 333 nHeight = HIWORD(lParam); 334 335 MoveWindow(SpiderWnd, 0, 0, nWidth, nHeight, TRUE); 336 return 0; 337 338 case WM_GETMINMAXINFO: 339 { 340 MINMAXINFO *mmi; 341 342 mmi = (MINMAXINFO *)lParam; 343 mmi->ptMinTrackSize.x = NUM_STACKS * __cardwidth + (NUM_STACKS + 3) * X_BORDER + 12; // Border left and right of 6px 344 mmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION) + 345 GetSystemMetrics(SM_CYMENU) + 346 2 * Y_BORDER + 347 3 * __cardheight + 348 6 * yRowStackCardOffset; 349 return 0; 350 } 351 352 case WM_COMMAND: 353 switch (LOWORD(wParam)) 354 { 355 case IDM_GAME_NEW: 356 NewGame(); 357 return 0; 358 359 case IDM_GAME_DECK: 360 ShowDeckOptionsDlg(hwnd); 361 return 0; 362 363 case IDM_HELP_CONTENTS: 364 WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play"); 365 return 0; 366 367 case IDM_HELP_ABOUT: 368 MessageBox(hwnd, MsgAbout, szAppName, MB_OK|MB_ICONINFORMATION); 369 return 0; 370 371 case IDM_GAME_EXIT: 372 PostMessage(hwnd, WM_CLOSE, 0, 0); 373 return 0; 374 } 375 376 return 0; 377 378 case WM_CLOSE: 379 if (fGameStarted == false) 380 { 381 DestroyWindow(hwnd); 382 return 0; 383 } 384 else 385 { 386 int ret; 387 388 ret = MessageBox(hwnd, MsgQuit, szAppName, MB_YESNO|MB_ICONQUESTION); 389 if (ret == IDYES) 390 { 391 WinHelp(hwnd, szHelpPath, HELP_QUIT, 0); 392 DestroyWindow(hwnd); 393 } 394 } 395 return 0; 396 } 397 return DefWindowProc (hwnd, iMsg, wParam, lParam); 398 } 399 400