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