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