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
UseNicePalette(HDC hdc,HPALETTE hPalette)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
RestorePalette(HDC hdc,HPALETTE hOldPal)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
RegisterCardWindow()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
CardWindow()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
Create(HWND hwndParent,DWORD dwExStyle,DWORD dwStyle,int x,int y,int width,int height)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
Destroy()123 BOOL CardWindow::Destroy()
124 {
125 DestroyWindow(m_hWnd);
126 m_hWnd = 0;
127
128 return TRUE;
129 }
130
~CardWindow()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
DeleteAll()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
SetBackColor(COLORREF cr)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
GetBackColor()224 COLORREF CardWindow::GetBackColor()
225 {
226 return crBackgnd;
227 }
228
CardButtonFromPoint(int x,int y)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
CardRegionFromPoint(int x,int y)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 //
CardWndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)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
Paint(HDC hdc)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
WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)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
CardRegionFromId(int id)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
CardButtonFromId(int id)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
Redraw()553 void CardWindow::Redraw()
554 {
555 InvalidateRect(m_hWnd, 0, 0);
556 UpdateWindow(m_hWnd);
557 }
558
DeleteButton(CardButton * pButton)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
DeleteRegion(CardRegion * pRegion)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
EmptyStacks(void)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
DistributeStacks(int nIdFrom,int nNumStacks,UINT xJustify,int xSpacing,int nStartX)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
Update()687 void CardWindow::Update()
688 {
689 for(int i = 0; i < nNumCardRegions; i++)
690 {
691 Regions[i]->AdjustPosition(nWidth, nHeight);
692 }
693 }
694
695
SetResizeProc(pResizeWndProc proc)696 void CardWindow::SetResizeProc(pResizeWndProc proc)
697 {
698 ResizeWndCallback = proc;
699 }
700
701
CreateCardPalette()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
SetBackCardIdx(UINT uBackIdx)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
GetBackCardIdx()738 UINT CardWindow::GetBackCardIdx()
739 {
740 return nBackCardIdx;
741 }
742
PaintCardRgn(HDC hdc,int dx,int dy,int width,int height,int sx,int sy)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
SetBackImage(HBITMAP hBitmap)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