1 // 2 // CardLib - CardWindow class 3 // 4 // Freeware 5 // Copyright J Brown 2001 6 // 7 8 #include "cardlib.h" 9 10 #include <tchar.h> 11 12 extern HPALETTE __holdplacepal; 13 14 HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette) 15 { 16 HPALETTE hOld; 17 18 hOld = SelectPalette(hdc, hPalette, FALSE); 19 RealizePalette(hdc); 20 21 return hOld; 22 } 23 24 void RestorePalette(HDC hdc, HPALETTE hOldPal) 25 { 26 SelectPalette(hdc, hOldPal, TRUE); 27 } 28 29 HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours); 30 void PaintRect(HDC hdc, RECT *rect, COLORREF colour); 31 HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height); 32 void GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2); 33 34 void LoadCardBitmaps(); 35 void FreeCardBitmaps(); 36 37 static TCHAR szCardName[] = _T("CardWnd32"); 38 static bool fRegistered = false; 39 static LONG uCardBitmapRef = 0; 40 41 42 void RegisterCardWindow() 43 { 44 WNDCLASSEX wc; 45 46 //Window class for the main application parent window 47 wc.cbSize = sizeof(wc); 48 wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW; 49 wc.lpfnWndProc = CardWindow::CardWndProc; 50 wc.cbClsExtra = 0; 51 wc.cbWndExtra = sizeof(CardWindow *); 52 wc.hInstance = GetModuleHandle(0); 53 wc.hIcon = 0; 54 wc.hCursor = LoadCursor (NULL, IDC_ARROW); 55 wc.hbrBackground = 0; 56 wc.lpszMenuName = 0; 57 wc.lpszClassName = szCardName; 58 wc.hIconSm = 0; 59 60 RegisterClassEx(&wc); 61 } 62 63 CardWindow::CardWindow() : m_hWnd(0) 64 { 65 HDC hdc = GetDC(0); 66 67 nNumButtons = 0; 68 nNumCardRegions = 0; 69 nNumDropZones = 0; 70 nBackCardIdx = 53; 71 72 ResizeWndCallback = 0; 73 hbmBackImage = 0; 74 hdcBackImage = 0; 75 76 srand((unsigned)GetTickCount()); 77 78 //All colours (buttons, highlights, decks) 79 //are calculated off this single base colour 80 crBackgnd = PALETTERGB(0,80,0);//PALETTERGB(0,64,100); 81 82 // If uCardBitmapRef was previously zero, then 83 // load the card bitmaps 84 if(1 == InterlockedIncrement(&uCardBitmapRef)) 85 { 86 LoadCardBitmaps(); 87 88 __hPalette = CreateCardPalette(); 89 90 __hdcPlaceHolder = CreateCompatibleDC(hdc); 91 92 __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette); 93 94 __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight); 95 96 } 97 98 ReleaseDC(0, hdc); 99 100 //register the window class if necessary 101 if(!fRegistered) 102 { 103 fRegistered = true; 104 RegisterCardWindow(); 105 } 106 107 } 108 109 BOOL CardWindow::Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height) 110 { 111 if(m_hWnd) 112 return FALSE; 113 114 //Create the window associated with this object 115 m_hWnd = CreateWindowEx(dwExStyle, szCardName, NULL, 116 dwStyle, 117 x, y, width, height, 118 hwndParent, NULL, GetModuleHandle(NULL), this); 119 120 return TRUE; 121 } 122 123 BOOL CardWindow::Destroy() 124 { 125 DestroyWindow(m_hWnd); 126 m_hWnd = 0; 127 128 return TRUE; 129 } 130 131 CardWindow::~CardWindow() 132 { 133 if(m_hWnd) 134 DestroyWindow(m_hWnd); 135 136 DeleteAll(); 137 138 if(0 == InterlockedDecrement(&uCardBitmapRef)) 139 { 140 FreeCardBitmaps(); 141 142 DeleteObject(__hbmPlaceHolder); 143 DeleteDC (__hdcPlaceHolder); 144 145 RestorePalette(__hdcPlaceHolder, __holdplacepal); 146 147 if(__hPalette) 148 DeleteObject(__hPalette); 149 } 150 } 151 152 bool CardWindow::DeleteAll() 153 { 154 int i; 155 156 for(i = 0; i < nNumCardRegions; i++) 157 { 158 delete Regions[i]; 159 } 160 161 for(i = 0; i < nNumButtons; i++) 162 { 163 delete Buttons[i]; 164 } 165 166 for(i = 0; i < nNumDropZones; i++) 167 { 168 delete dropzone[i]; 169 } 170 171 nNumCardRegions = nNumButtons = nNumDropZones = 0; 172 173 return true; 174 } 175 176 void CardWindow::SetBackColor(COLORREF cr) 177 { 178 crBackgnd = cr; 179 int i; 180 181 // 182 // Create the exact palette we need to render the buttons/stacks 183 // 184 RestorePalette(__hdcPlaceHolder, __holdplacepal); 185 186 if(__hPalette) 187 DeleteObject(__hPalette); 188 189 __hPalette = CreateCardPalette(); 190 191 // 192 // re-create the place-holder! 193 HDC hdc = GetDC(m_hWnd); 194 195 DeleteObject(__hbmPlaceHolder); 196 197 __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette); 198 199 __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight); 200 //SelectObject(__hdcPlaceHolder, __hbmPlaceHolder); 201 202 //reset all buttons to same colour 203 for(i = 0; i < nNumButtons; i++) 204 { 205 if(Buttons[i]->GetStyle() & CB_PUSHBUTTON) 206 { 207 Buttons[i]->SetBackColor(ColorScaleRGB(crBackgnd, RGB(255,255,255), 0.1)); 208 } 209 else 210 { 211 Buttons[i]->SetBackColor(crBackgnd); 212 } 213 } 214 215 for(i = 0; i < nNumCardRegions; i++) 216 { 217 Regions[i]->SetBackColor(crBackgnd); 218 } 219 220 221 ReleaseDC(m_hWnd, hdc); 222 } 223 224 COLORREF CardWindow::GetBackColor() 225 { 226 return crBackgnd; 227 } 228 229 CardButton* CardWindow::CardButtonFromPoint(int x, int y) 230 { 231 CardButton *bptr = 0; 232 233 POINT pt; 234 pt.x = x; 235 pt.y = y; 236 237 //Search BACKWARDS...to reflect the implicit Z-order that 238 //the button creation provided 239 for(int i = nNumButtons - 1; i >= 0; i--) 240 { 241 bptr = Buttons[i]; 242 if(PtInRect(&bptr->rect, pt) && bptr->fVisible) 243 return bptr; 244 } 245 246 return 0; 247 } 248 249 CardRegion* CardWindow::CardRegionFromPoint(int x, int y) 250 { 251 POINT pt; 252 pt.x = x; 253 pt.y = y; 254 255 //Search BACKWARDS...to reflect the implicit Z-order that 256 //the stack creation provided 257 for(int i = nNumCardRegions - 1; i >= 0; i--) 258 { 259 if(Regions[i]->IsPointInStack(x, y)) 260 return Regions[i]; 261 } 262 263 return 0; 264 } 265 266 // 267 // Forward all window messages onto the appropriate 268 // class instance 269 // 270 LRESULT CALLBACK CardWindow::CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 271 { 272 CardWindow *cw = (CardWindow *)GetWindowLongPtr(hwnd, 0); 273 return cw->WndProc(hwnd, iMsg, wParam, lParam); 274 } 275 276 void CardWindow::Paint(HDC hdc) 277 { 278 int i; 279 RECT rect; 280 HPALETTE hOldPal; 281 282 hOldPal = UseNicePalette(hdc, __hPalette); 283 284 // 285 // Clip the card stacks so that they won't 286 // get painted over 287 // 288 for(i = 0; i < nNumCardRegions; i++) 289 { 290 Regions[i]->Clip(hdc); 291 } 292 293 // 294 // Clip the buttons 295 // 296 for(i = 0; i < nNumButtons; i++) 297 { 298 Buttons[i]->Clip(hdc); 299 } 300 301 302 // Now paint the whole screen with background colour, 303 // 304 GetClientRect(m_hWnd, &rect); 305 306 //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd)); 307 PaintCardRgn(hdc, 0, 0, rect.right, rect.bottom, 0, 0); 308 SelectClipRgn(hdc, NULL); 309 310 // Don't let cards draw over buttons, so clip buttons again 311 // 312 for(i = 0; i < nNumButtons; i++) 313 { 314 Buttons[i]->Clip(hdc); 315 } 316 317 // Paint each card stack in turn 318 // 319 for(i = 0; i < nNumCardRegions; i++) 320 { 321 Regions[i]->Render(hdc); 322 } 323 324 // Paint each button now 325 // 326 SelectClipRgn(hdc, NULL); 327 328 for(i = 0; i < nNumButtons; i++) 329 { 330 Buttons[i]->Redraw(); 331 } 332 333 RestorePalette(hdc, hOldPal); 334 } 335 336 337 338 339 LRESULT CALLBACK CardWindow::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 340 { 341 HDC hdc; 342 PAINTSTRUCT ps; 343 344 CREATESTRUCT *cs; 345 346 static CardButton *buttonptr = 0; 347 static CardRegion *stackptr = 0; 348 349 int x, y, i; 350 351 switch(iMsg) 352 { 353 case WM_NCCREATE: 354 355 // When we created this window, we passed in the 356 // pointer to the class object (CardWindow *) in the 357 // call to CreateWindow. 358 cs = (CREATESTRUCT *)lParam; 359 360 // 361 // associate this class with the window 362 // 363 SetWindowLongPtr(hwnd, 0, (LONG_PTR)cs->lpCreateParams); 364 365 return 1; 366 367 case WM_NCDESTROY: 368 // Don't delete anything here.. 369 break; 370 371 case WM_SIZE: 372 nWidth = LOWORD(lParam); 373 nHeight = HIWORD(lParam); 374 375 // 376 // reposition all the stacks and buttons 377 // in case any of them are centered, right-justified etc 378 // 379 for(i = 0; i < nNumCardRegions; i++) 380 { 381 Regions[i]->AdjustPosition(nWidth, nHeight); 382 } 383 384 for(i = 0; i < nNumButtons; i++) 385 { 386 Buttons[i]->AdjustPosition(nWidth, nHeight); 387 } 388 389 // 390 // Call the user-defined resize proc AFTER all the stacks 391 // have been positioned 392 // 393 if(ResizeWndCallback) 394 ResizeWndCallback(nWidth, nHeight); 395 396 return 0; 397 398 case WM_PAINT: 399 400 hdc = BeginPaint(hwnd, &ps); 401 402 Paint(hdc); 403 404 EndPaint(hwnd, &ps); 405 return 0; 406 407 case WM_TIMER: 408 409 //find the timer object in the registered funcs 410 /*if(wParam >= 0x10000) 411 { 412 for(i = 0; i < nRegFuncs; i++) 413 { 414 if(RegFuncs[i].id == wParam) 415 { 416 KillTimer(hwnd, wParam); 417 418 //call the registered function!! 419 RegFuncs[i].func(RegFuncs[i].dwParam); 420 421 RegFuncs[i] = RegFuncs[nRegFuncs-1]; 422 nRegFuncs--; 423 } 424 } 425 } 426 else*/ 427 { 428 //find the cardstack 429 CardRegion *stackobj = (CardRegion *)wParam;//CardStackFromId(wParam); 430 stackobj->DoFlash(); 431 } 432 433 return 0; 434 435 case WM_LBUTTONDBLCLK: 436 437 x = (short)LOWORD(lParam); 438 y = (short)HIWORD(lParam); 439 440 if((buttonptr = CardButtonFromPoint(x, y)) != 0) 441 { 442 buttonptr->OnLButtonDown(hwnd, x, y); 443 return 0; 444 } 445 446 if((stackptr = CardRegionFromPoint(x, y)) != 0) 447 { 448 stackptr->OnLButtonDblClk(x, y); 449 stackptr = 0; 450 } 451 452 return 0; 453 454 case WM_LBUTTONDOWN: 455 456 x = (short)LOWORD(lParam); 457 y = (short)HIWORD(lParam); 458 459 //if clicked on a button 460 if((buttonptr = CardButtonFromPoint(x, y)) != 0) 461 { 462 if(buttonptr->OnLButtonDown(hwnd, x, y) == 0) 463 buttonptr = 0; 464 465 return 0; 466 } 467 468 if((stackptr = CardRegionFromPoint(x, y)) != 0) 469 { 470 if(!stackptr->OnLButtonDown(x, y)) 471 stackptr = 0; 472 } 473 474 return 0; 475 476 case WM_LBUTTONUP: 477 478 x = (short)LOWORD(lParam); 479 y = (short)HIWORD(lParam); 480 481 // 482 // if we were clicking a button 483 // 484 if(buttonptr != 0) 485 { 486 buttonptr->OnLButtonUp(hwnd, x, y); 487 buttonptr = 0; 488 return 0; 489 } 490 491 if(stackptr != 0) 492 { 493 stackptr->OnLButtonUp(x, y); 494 stackptr = 0; 495 return 0; 496 } 497 498 if ((stackptr = CardRegionFromPoint(x, y)) != 0) 499 { 500 stackptr->ClickRelease(x, y); 501 stackptr = 0; 502 } 503 504 return 0; 505 506 case WM_MOUSEMOVE: 507 508 x = (short)LOWORD(lParam); 509 y = (short)HIWORD(lParam); 510 511 // if we were clicking a button 512 if(buttonptr != 0) 513 { 514 buttonptr->OnMouseMove(hwnd, x, y); 515 return 0; 516 } 517 518 if(stackptr != 0) 519 { 520 return stackptr->OnMouseMove(x, y); 521 } 522 523 return 0; 524 525 } 526 527 return DefWindowProc (hwnd, iMsg, wParam, lParam); 528 } 529 530 531 CardRegion* CardWindow::CardRegionFromId(int id) 532 { 533 for(int i = 0; i < nNumCardRegions; i++) 534 { 535 if(Regions[i]->id == id) 536 return Regions[i]; 537 } 538 539 return 0; 540 } 541 542 CardButton* CardWindow::CardButtonFromId(int id) 543 { 544 for(int i = 0; i < nNumButtons; i++) 545 { 546 if(Buttons[i]->id == id) 547 return Buttons[i]; 548 } 549 550 return 0; 551 } 552 553 void CardWindow::Redraw() 554 { 555 InvalidateRect(m_hWnd, 0, 0); 556 UpdateWindow(m_hWnd); 557 } 558 559 bool CardWindow::DeleteButton(CardButton *pButton) 560 { 561 for(int i = 0; i < nNumButtons; i++) 562 { 563 if(Buttons[i] == pButton) 564 { 565 CardButton *cb = Buttons[i]; 566 567 //shift any after this one backwards 568 for(int j = i; j < nNumButtons - 1; j++) 569 { 570 Buttons[j] = Buttons[j + 1]; 571 } 572 573 delete cb; 574 nNumButtons--; 575 576 return true; 577 } 578 } 579 580 return false; 581 } 582 583 bool CardWindow::DeleteRegion(CardRegion *pRegion) 584 { 585 for(int i = 0; i < nNumCardRegions; i++) 586 { 587 if(Regions[i] == pRegion) 588 { 589 CardRegion *cr = Regions[i]; 590 591 //shift any after this one backwards 592 for(int j = i; j < nNumCardRegions - 1; j++) 593 { 594 Regions[j] = Regions[j + 1]; 595 } 596 597 delete cr; 598 nNumCardRegions--; 599 600 return true; 601 } 602 } 603 604 return false; 605 } 606 607 void CardWindow::EmptyStacks(void) 608 { 609 for(int i = 0; i < nNumCardRegions; i++) 610 { 611 Regions[i]->Clear(); 612 Regions[i]->Update(); 613 } 614 615 Redraw(); 616 } 617 618 bool CardWindow::DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX) 619 { 620 int numvisiblestacks = 0; 621 int curx = nStartX; 622 int startindex = -1; 623 int i; 624 625 //find the stack which starts with our ID 626 for(i = 0; i < nNumCardRegions; i++) 627 { 628 if(Regions[i]->Id() == nIdFrom) 629 { 630 startindex = i; 631 break; 632 } 633 } 634 635 //if didn't find, return 636 if(i == nNumCardRegions) return false; 637 638 //count the stacks that are visible 639 for(i = startindex; i < startindex + nNumStacks; i++) 640 { 641 if(Regions[i]->IsVisible()) 642 numvisiblestacks++; 643 } 644 645 if(xJustify == CS_XJUST_CENTER) 646 { 647 //startx -= ((numvisiblestacks + spacing) * cardwidth - spacing) / 2; 648 int viswidth; 649 viswidth = numvisiblestacks * __cardwidth; 650 viswidth += xSpacing * (numvisiblestacks - 1); 651 curx = -(viswidth - __cardwidth) / 2; 652 653 for(i = startindex; i < startindex + nNumStacks; i++) 654 { 655 if(Regions[i]->IsVisible()) 656 { 657 Regions[i]->xadjust = curx; 658 Regions[i]->xjustify = CS_XJUST_CENTER; 659 curx += Regions[i]->width + xSpacing; 660 } 661 662 } 663 } 664 665 if(xJustify == CS_XJUST_RIGHT) 666 { 667 nStartX -= ((numvisiblestacks + xSpacing) * __cardwidth - xSpacing); 668 } 669 670 if(xJustify == CS_XJUST_NONE) 671 { 672 for(i = startindex; i < startindex + nNumStacks; i++) 673 { 674 if(Regions[i]->IsVisible()) 675 { 676 Regions[i]->xpos = curx; 677 curx += Regions[i]->width + xSpacing; 678 Regions[i]->UpdateSize(); 679 } 680 681 } 682 } 683 684 return 0; 685 } 686 687 void CardWindow::Update() 688 { 689 for(int i = 0; i < nNumCardRegions; i++) 690 { 691 Regions[i]->AdjustPosition(nWidth, nHeight); 692 } 693 } 694 695 696 void CardWindow::SetResizeProc(pResizeWndProc proc) 697 { 698 ResizeWndCallback = proc; 699 } 700 701 702 HPALETTE CardWindow::CreateCardPalette() 703 { 704 COLORREF cols[10]; 705 int nNumCols; 706 707 708 //include button text colours 709 cols[0] = RGB(0, 0, 0); 710 cols[1] = RGB(255, 255, 255); 711 712 //include the base background colour 713 cols[2] = crBackgnd; 714 715 //include the standard button colours... 716 cols[3] = CardButton::GetHighlight(crBackgnd); 717 cols[4] = CardButton::GetShadow(crBackgnd); 718 cols[5] = CardButton::GetFace(crBackgnd); 719 720 //include the sunken image bitmap colours... 721 GetSinkCols(crBackgnd, &cols[6], &cols[7], &cols[8], &cols[9]); 722 723 nNumCols = 10; 724 725 return MakePaletteFromCols(cols, nNumCols); 726 } 727 728 void CardWindow::SetBackCardIdx(UINT uBackIdx) 729 { 730 if(uBackIdx >= 52 && uBackIdx <= 68) 731 nBackCardIdx = uBackIdx; 732 733 for(int i = 0; i < nNumCardRegions; i++) 734 Regions[i]->SetBackCardIdx(uBackIdx); 735 736 } 737 738 UINT CardWindow::GetBackCardIdx() 739 { 740 return nBackCardIdx; 741 } 742 743 void CardWindow::PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy) 744 { 745 RECT rect; 746 747 //if just a solid background colour 748 if(hbmBackImage == 0) 749 { 750 SetRect(&rect, dx, dy, dx+width, dy+height); 751 752 /*if(GetVersion() < 0x80000000) 753 { 754 PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd)); 755 } 756 else*/ 757 { 758 HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBackgnd)); 759 FillRect(hdc, &rect, hbr); 760 DeleteObject(hbr); 761 } 762 } 763 //otherwise, paint using the bitmap 764 else 765 { 766 // Draw whatever part of background we can 767 BitBlt(hdc, dx, dy, width, height, hdcBackImage, sx, sy, SRCCOPY); 768 769 // Now we need to paint any area outside the bitmap, 770 // just in case the bitmap is too small to fill whole window 771 if(0)//sx + width > bm.bmWidth || sy + height > bm.bmHeight) 772 { 773 // Find out size of bitmap 774 BITMAP bm; 775 GetObject(hbmBackImage, sizeof(bm), &bm); 776 777 HRGN hr1 = CreateRectRgn(sx, sy, sx+width, sy+height); 778 HRGN hr2 = CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight); 779 HRGN hr3 = CreateRectRgn(0,0, 1, 1); 780 HRGN hr4 = CreateRectRgn(0,0, 1, 1); 781 782 CombineRgn(hr3, hr1, hr2, RGN_DIFF); 783 784 GetClipRgn(hdc, hr4); 785 786 CombineRgn(hr3, hr4, hr3, RGN_AND); 787 SelectClipRgn(hdc, hr3); 788 789 // Fill remaining space not filled with bitmap 790 HBRUSH hbr = CreateSolidBrush(crBackgnd); 791 FillRgn(hdc, hr3, hbr); 792 DeleteObject(hbr); 793 794 // Clean up 795 SelectClipRgn(hdc, hr4); 796 797 DeleteObject(hr1); 798 DeleteObject(hr2); 799 DeleteObject(hr3); 800 DeleteObject(hr4); 801 } 802 } 803 } 804 805 void CardWindow::SetBackImage(HBITMAP hBitmap) 806 { 807 //delete current image?? NO! 808 if(hdcBackImage == 0) 809 { 810 hdcBackImage = CreateCompatibleDC(0); 811 } 812 813 hbmBackImage = hBitmap; 814 815 if(hBitmap) 816 SelectObject(hdcBackImage, hBitmap); 817 } 818