-//\r
-// CardLib - CardWindow class\r
-//\r
-// Freeware\r
-// Copyright J Brown 2001\r
-//\r
-#include <windows.h>\r
-#include <tchar.h>\r
-\r
-#include "globals.h"\r
-#include "cardlib.h"\r
-#include "cardbutton.h"\r
-#include "cardregion.h"\r
-#include "cardwindow.h"\r
-#include "cardcolor.h"\r
-\r
-extern HPALETTE __holdplacepal;\r
-\r
-HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette)\r
-{\r
- HPALETTE hOld;\r
-\r
- hOld = SelectPalette(hdc, hPalette, FALSE);\r
- RealizePalette(hdc);\r
-\r
- return hOld;\r
-}\r
-\r
-void RestorePalette(HDC hdc, HPALETTE hOldPal)\r
-{\r
- SelectPalette(hdc, hOldPal, TRUE);\r
-}\r
-\r
-HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours);\r
-void PaintRect(HDC hdc, RECT *rect, COLORREF colour);\r
-HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height);\r
-void GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2);\r
-\r
-void LoadCardBitmaps();\r
-void FreeCardBitmaps();\r
-\r
-static TCHAR szCardName[] = _T("CardWnd32");\r
-static bool fRegistered = false;\r
-static LONG uCardBitmapRef = 0;\r
-\r
-\r
-void RegisterCardWindow()\r
-{\r
- WNDCLASSEX wc;\r
-\r
- //Window class for the main application parent window\r
- wc.cbSize = sizeof(wc);\r
- wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;\r
- wc.lpfnWndProc = CardWindow::CardWndProc;\r
- wc.cbClsExtra = 0;\r
- wc.cbWndExtra = sizeof(CardWindow *);\r
- wc.hInstance = GetModuleHandle(0);\r
- wc.hIcon = 0;\r
- wc.hCursor = LoadCursor (NULL, IDC_ARROW);\r
- wc.hbrBackground = 0;\r
- wc.lpszMenuName = 0;\r
- wc.lpszClassName = szCardName;\r
- wc.hIconSm = 0;\r
-\r
- RegisterClassEx(&wc);\r
-}\r
-\r
-CardWindow::CardWindow() : m_hWnd(0)\r
-{\r
- HDC hdc = GetDC(0);\r
-\r
- nNumButtons = 0;\r
- nNumCardRegions = 0;\r
- nNumDropZones = 0;\r
- nBackCardIdx = 53;\r
-\r
- ResizeWndCallback = 0;\r
- hbmBackImage = 0;\r
- hdcBackImage = 0;\r
-\r
- srand((unsigned)GetTickCount());\r
-\r
- //All colours (buttons, highlights, decks)\r
- //are calculated off this single base colour\r
- crBackgnd = PALETTERGB(0,80,0);//PALETTERGB(0,64,100);\r
-\r
- // If uCardBitmapRef was previously zero, then\r
- // load the card bitmaps\r
- if(1 == InterlockedIncrement(&uCardBitmapRef))\r
- {\r
- LoadCardBitmaps();\r
-\r
- __hPalette = CreateCardPalette();\r
-\r
- __hdcPlaceHolder = CreateCompatibleDC(hdc);\r
- \r
- __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette);\r
-\r
- __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);\r
-\r
- }\r
-\r
- ReleaseDC(0, hdc);\r
-\r
- //register the window class if necessary\r
- if(!fRegistered)\r
- {\r
- fRegistered = true;\r
- RegisterCardWindow();\r
- }\r
-\r
-}\r
-\r
-BOOL CardWindow::Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height)\r
-{\r
- if(m_hWnd)\r
- return FALSE;\r
-\r
- //Create the window associated with this object\r
- m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szCardName, 0, \r
- WS_CHILD | WS_VISIBLE,\r
- 0,0,100,100, \r
- hwndParent, 0, GetModuleHandle(0), this);\r
-\r
- return TRUE;\r
-}\r
-\r
-BOOL CardWindow::Destroy()\r
-{\r
- DestroyWindow(m_hWnd);\r
- m_hWnd = 0;\r
-\r
- return TRUE;\r
-}\r
-\r
-CardWindow::~CardWindow()\r
-{\r
- if(m_hWnd)\r
- DestroyWindow(m_hWnd);\r
-\r
- DeleteAll();\r
-\r
- if(0 == InterlockedDecrement(&uCardBitmapRef))\r
- {\r
- FreeCardBitmaps();\r
-\r
- DeleteObject(__hbmPlaceHolder);\r
- DeleteDC (__hdcPlaceHolder);\r
-\r
- RestorePalette(__hdcPlaceHolder, __holdplacepal);\r
-\r
- if(__hPalette)\r
- DeleteObject(__hPalette);\r
- }\r
-}\r
-\r
-bool CardWindow::DeleteAll()\r
-{\r
- int i;\r
-\r
- for(i = 0; i < nNumCardRegions; i++)\r
- {\r
- delete Regions[i];\r
- }\r
-\r
- for(i = 0; i < nNumButtons; i++)\r
- {\r
- delete Buttons[i];\r
- }\r
-\r
- for(i = 0; i < nNumDropZones; i++)\r
- {\r
- delete dropzone[i];\r
- }\r
-\r
- nNumCardRegions = nNumButtons = nNumDropZones = 0;\r
-\r
- return true;\r
-}\r
-\r
-void CardWindow::SetBackColor(COLORREF cr)\r
-{\r
- crBackgnd = cr;\r
- int i;\r
- \r
- //\r
- // Create the exact palette we need to render the buttons/stacks\r
- //\r
- RestorePalette(__hdcPlaceHolder, __holdplacepal);\r
-\r
- if(__hPalette)\r
- DeleteObject(__hPalette);\r
-\r
- __hPalette = CreateCardPalette();\r
-\r
- //\r
- // re-create the place-holder!\r
- HDC hdc = GetDC(m_hWnd);\r
-\r
- DeleteObject(__hbmPlaceHolder);\r
-\r
- __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette);\r
-\r
- __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);\r
- //SelectObject(__hdcPlaceHolder, __hbmPlaceHolder);\r
-\r
- //reset all buttons to same colour\r
- for(i = 0; i < nNumButtons; i++)\r
- {\r
- if(Buttons[i]->GetStyle() & CB_PUSHBUTTON)\r
- {\r
- Buttons[i]->SetBackColor(ColorScaleRGB(crBackgnd, RGB(255,255,255), 0.1));\r
- }\r
- else\r
- {\r
- Buttons[i]->SetBackColor(crBackgnd);\r
- }\r
- }\r
-\r
- for(i = 0; i < nNumCardRegions; i++)\r
- {\r
- Regions[i]->SetBackColor(crBackgnd);\r
- }\r
-\r
-\r
- ReleaseDC(m_hWnd, hdc);\r
-}\r
-\r
-COLORREF CardWindow::GetBackColor()\r
-{\r
- return crBackgnd;\r
-}\r
-\r
-CardButton* CardWindow::CardButtonFromPoint(int x, int y)\r
-{\r
- CardButton *bptr = 0;\r
-\r
- POINT pt;\r
- pt.x = x;\r
- pt.y = y;\r
-\r
- //Search BACKWARDS...to reflect the implicit Z-order that\r
- //the button creation provided\r
- for(int i = nNumButtons - 1; i >= 0; i--)\r
- {\r
- bptr = Buttons[i];\r
- if(PtInRect(&bptr->rect, pt) && bptr->fVisible)\r
- return bptr;\r
- }\r
-\r
- return 0; \r
-}\r
-\r
-CardRegion* CardWindow::CardRegionFromPoint(int x, int y)\r
-{\r
- POINT pt;\r
- pt.x = x;\r
- pt.y = y;\r
-\r
- //Search BACKWARDS...to reflect the implicit Z-order that\r
- //the stack creation provided\r
- for(int i = nNumCardRegions - 1; i >= 0; i--)\r
- {\r
- if(Regions[i]->IsPointInStack(x, y))\r
- return Regions[i];\r
- }\r
-\r
- return 0; \r
-}\r
-\r
-//\r
-// Forward all window messages onto the appropriate\r
-// class instance\r
-//\r
-LRESULT CALLBACK CardWindow::CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
- CardWindow *cw = (CardWindow *)GetWindowLong(hwnd, 0);\r
- return cw->WndProc(hwnd, iMsg, wParam, lParam);\r
-}\r
-\r
-void CardWindow::Paint(HDC hdc)\r
-{\r
- int i;\r
- RECT rect;\r
- HPALETTE hOldPal;\r
-\r
- hOldPal = UseNicePalette(hdc, __hPalette);\r
-\r
- //\r
- // Clip the card stacks so that they won't\r
- // get painted over\r
- //\r
- for(i = 0; i < nNumCardRegions; i++)\r
- {\r
- Regions[i]->Clip(hdc);\r
- }\r
-\r
- //\r
- // Clip the buttons \r
- //\r
- for(i = 0; i < nNumButtons; i++)\r
- {\r
- Buttons[i]->Clip(hdc);\r
- }\r
-\r
-\r
- // Now paint the whole screen with background colour, \r
- //\r
- GetClientRect(m_hWnd, &rect);\r
- \r
- //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));\r
- PaintCardRgn(hdc, 0, 0, rect.right, rect.bottom, 0, 0);\r
- SelectClipRgn(hdc, NULL);\r
-\r
- // Don't let cards draw over buttons, so clip buttons again\r
- //\r
- for(i = 0; i < nNumButtons; i++)\r
- {\r
- Buttons[i]->Clip(hdc);\r
- }\r
-\r
- // Paint each card stack in turn\r
- //\r
- for(i = 0; i < nNumCardRegions; i++)\r
- {\r
- Regions[i]->Render(hdc);\r
- }\r
- \r
- // Paint each button now\r
- //\r
- SelectClipRgn(hdc, NULL);\r
-\r
- for(i = 0; i < nNumButtons; i++)\r
- {\r
- Buttons[i]->Redraw();\r
- }\r
-\r
- RestorePalette(hdc, hOldPal);\r
-}\r
-\r
-\r
-\r
-\r
-LRESULT CALLBACK CardWindow::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
- HDC hdc;\r
- PAINTSTRUCT ps;\r
-\r
- CREATESTRUCT *cs;\r
-\r
- static CardButton *buttonptr = 0;\r
- static CardRegion *stackptr = 0;\r
-\r
- int x, y, i;\r
-\r
- switch(iMsg)\r
- {\r
- case WM_NCCREATE:\r
-\r
- // When we created this window, we passed in the\r
- // pointer to the class object (CardWindow *) in the\r
- // call to CreateWindow.\r
- cs = (CREATESTRUCT *)lParam;\r
-\r
- //\r
- // associate this class with the window\r
- //\r
- SetWindowLong(hwnd, 0, (LONG)cs->lpCreateParams);\r
-\r
- return 1;\r
-\r
- case WM_NCDESTROY:\r
- // Don't delete anything here..\r
- break;\r
-\r
- case WM_SIZE:\r
- nWidth = LOWORD(lParam);\r
- nHeight = HIWORD(lParam);\r
- \r
- //\r
- // reposition all the stacks and buttons\r
- // in case any of them are centered, right-justified etc\r
- //\r
- for(i = 0; i < nNumCardRegions; i++)\r
- {\r
- Regions[i]->AdjustPosition(nWidth, nHeight);\r
- }\r
- \r
- for(i = 0; i < nNumButtons; i++)\r
- {\r
- Buttons[i]->AdjustPosition(nWidth, nHeight);\r
- }\r
-\r
- // \r
- // Call the user-defined resize proc AFTER all the stacks\r
- // have been positioned\r
- //\r
- if(ResizeWndCallback) \r
- ResizeWndCallback(nWidth, nHeight);\r
-\r
- return 0;\r
-\r
- case WM_PAINT:\r
-\r
- hdc = BeginPaint(hwnd, &ps);\r
-\r
- Paint(hdc);\r
-\r
- EndPaint(hwnd, &ps);\r
- return 0;\r
-\r
- case WM_TIMER:\r
- \r
- //find the timer object in the registered funcs\r
- /*if(wParam >= 0x10000)\r
- {\r
- for(i = 0; i < nRegFuncs; i++)\r
- {\r
- if(RegFuncs[i].id == wParam)\r
- {\r
- KillTimer(hwnd, wParam);\r
- \r
- //call the registered function!!\r
- RegFuncs[i].func(RegFuncs[i].dwParam);\r
- \r
- RegFuncs[i] = RegFuncs[nRegFuncs-1];\r
- nRegFuncs--;\r
- }\r
- }\r
- }\r
- else*/\r
- {\r
- //find the cardstack\r
- CardRegion *stackobj = (CardRegion *)wParam;//CardStackFromId(wParam);\r
- stackobj->DoFlash();\r
- }\r
-\r
- return 0;\r
-\r
- case WM_LBUTTONDBLCLK:\r
-\r
- x = (short)LOWORD(lParam);\r
- y = (short)HIWORD(lParam);\r
-\r
- if((buttonptr = CardButtonFromPoint(x, y)) != 0)\r
- {\r
- buttonptr->OnLButtonDown(hwnd, x, y);\r
- return 0;\r
- }\r
-\r
- if((stackptr = CardRegionFromPoint(x, y)) != 0)\r
- {\r
- stackptr->OnLButtonDblClk(x, y);\r
- stackptr = 0;\r
- }\r
-\r
- return 0;\r
-\r
- case WM_LBUTTONDOWN:\r
-\r
- x = (short)LOWORD(lParam);\r
- y = (short)HIWORD(lParam);\r
-\r
- //if clicked on a button\r
- if((buttonptr = CardButtonFromPoint(x, y)) != 0)\r
- {\r
- if(buttonptr->OnLButtonDown(hwnd, x, y) == 0)\r
- buttonptr = 0;\r
-\r
- return 0;\r
- }\r
-\r
- if((stackptr = CardRegionFromPoint(x, y)) != 0)\r
- {\r
- if(!stackptr->OnLButtonDown(x, y))\r
- stackptr = 0;\r
- }\r
- \r
- return 0;\r
-\r
- case WM_LBUTTONUP:\r
- \r
- x = (short)LOWORD(lParam);\r
- y = (short)HIWORD(lParam);\r
-\r
- //\r
- // if we were clicking a button\r
- //\r
- if(buttonptr != 0)\r
- {\r
- buttonptr->OnLButtonUp(hwnd, x, y);\r
- buttonptr = 0;\r
- return 0;\r
- }\r
- \r
- if(stackptr != 0)\r
- {\r
- stackptr->OnLButtonUp(x, y);\r
- stackptr = 0;\r
- return 0;\r
- }\r
-\r
- return 0;\r
-\r
- case WM_MOUSEMOVE:\r
- \r
- x = (short)LOWORD(lParam);\r
- y = (short)HIWORD(lParam);\r
-\r
- // if we were clicking a button\r
- if(buttonptr != 0)\r
- {\r
- buttonptr->OnMouseMove(hwnd, x, y);\r
- return 0;\r
- }\r
-\r
- if(stackptr != 0)\r
- {\r
- return stackptr->OnMouseMove(x, y);\r
- }\r
- \r
- return 0;\r
-\r
- }\r
-\r
- return DefWindowProc (hwnd, iMsg, wParam, lParam);\r
-}\r
-\r
-\r
-CardRegion* CardWindow::CardRegionFromId(int id)\r
-{\r
- for(int i = 0; i < nNumCardRegions; i++)\r
- {\r
- if(Regions[i]->id == id)\r
- return Regions[i];\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-CardButton* CardWindow::CardButtonFromId(int id)\r
-{\r
- for(int i = 0; i < nNumButtons; i++)\r
- {\r
- if(Buttons[i]->id == id)\r
- return Buttons[i];\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-void CardWindow::Redraw()\r
-{\r
- InvalidateRect(m_hWnd, 0, 0);\r
- UpdateWindow(m_hWnd);\r
-}\r
-\r
-bool CardWindow::DeleteButton(CardButton *pButton)\r
-{\r
- for(int i = 0; i < nNumButtons; i++)\r
- {\r
- if(Buttons[i] == pButton)\r
- {\r
- CardButton *cb = Buttons[i];\r
- \r
- //shift any after this one backwards\r
- for(int j = i; j < nNumButtons - 1; j++)\r
- {\r
- Buttons[j] = Buttons[j + 1];\r
- }\r
-\r
- delete cb;\r
- nNumButtons--;\r
- \r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
-}\r
-\r
-bool CardWindow::DeleteRegion(CardRegion *pRegion)\r
-{\r
- for(int i = 0; i < nNumCardRegions; i++)\r
- {\r
- if(Regions[i] == pRegion)\r
- {\r
- CardRegion *cr = Regions[i];\r
- \r
- //shift any after this one backwards\r
- for(int j = i; j < nNumCardRegions - 1; j++)\r
- {\r
- Regions[j] = Regions[j + 1];\r
- }\r
-\r
- delete cr;\r
- nNumCardRegions--;\r
-\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
-}\r
-\r
-void CardWindow::EmptyStacks(void)\r
-{\r
- for(int i = 0; i < nNumCardRegions; i++)\r
- {\r
- Regions[i]->Clear();\r
- Regions[i]->Update();\r
- }\r
-\r
- Redraw();\r
-}\r
-\r
-bool CardWindow::DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX)\r
-{\r
- int numvisiblestacks = 0;\r
- int curx = nStartX;\r
- int startindex = -1;\r
- int i;\r
-\r
- //find the stack which starts with our ID\r
- for(i = 0; i < nNumCardRegions; i++)\r
- {\r
- if(Regions[i]->Id() == nIdFrom)\r
- {\r
- startindex = i;\r
- break;\r
- }\r
- }\r
-\r
- //if didn't find, return\r
- if(i == nNumCardRegions) return false;\r
-\r
- //count the stacks that are visible\r
- for(i = startindex; i < startindex + nNumStacks; i++)\r
- {\r
- if(Regions[i]->IsVisible())\r
- numvisiblestacks++;\r
- }\r
- \r
- if(xJustify == CS_XJUST_CENTER)\r
- {\r
- //startx -= ((numvisiblestacks + spacing) * cardwidth - spacing) / 2;\r
- int viswidth;\r
- viswidth = numvisiblestacks * __cardwidth;\r
- viswidth += xSpacing * (numvisiblestacks - 1);\r
- curx = -(viswidth - __cardwidth) / 2;\r
-\r
- for(i = startindex; i < startindex + nNumStacks; i++)\r
- {\r
- if(Regions[i]->IsVisible())\r
- {\r
- Regions[i]->xadjust = curx;\r
- Regions[i]->xjustify = CS_XJUST_CENTER;\r
- curx += Regions[i]->width + xSpacing;\r
- }\r
- \r
- }\r
- }\r
-\r
- if(xJustify == CS_XJUST_RIGHT)\r
- {\r
- nStartX -= ((numvisiblestacks + xSpacing) * __cardwidth - xSpacing);\r
- }\r
- \r
- if(xJustify == CS_XJUST_NONE)\r
- {\r
- for(i = startindex; i < startindex + nNumStacks; i++)\r
- {\r
- if(Regions[i]->IsVisible())\r
- {\r
- Regions[i]->xpos = curx;\r
- curx += Regions[i]->width + xSpacing;\r
- Regions[i]->UpdateSize();\r
- }\r
- \r
- }\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-void CardWindow::Update()\r
-{\r
- for(int i = 0; i < nNumCardRegions; i++)\r
- {\r
- Regions[i]->AdjustPosition(nWidth, nHeight);\r
- }\r
-}\r
-\r
-\r
-void CardWindow::SetResizeProc(pResizeWndProc proc)\r
-{\r
- ResizeWndCallback = proc;\r
-}\r
-\r
-\r
-HPALETTE CardWindow::CreateCardPalette()\r
-{\r
- COLORREF cols[10];\r
- int nNumCols;\r
-\r
-\r
- //include button text colours\r
- cols[0] = RGB(0, 0, 0);\r
- cols[1] = RGB(255, 255, 255);\r
-\r
- //include the base background colour\r
- cols[1] = crBackgnd;\r
-\r
- //include the standard button colours...\r
- cols[3] = CardButton::GetHighlight(crBackgnd);\r
- cols[4] = CardButton::GetShadow(crBackgnd);\r
- cols[5] = CardButton::GetFace(crBackgnd);\r
-\r
- //include the sunken image bitmap colours...\r
- GetSinkCols(crBackgnd, &cols[6], &cols[7], &cols[8], &cols[9]);\r
-\r
- nNumCols = 10;\r
-\r
- return MakePaletteFromCols(cols, nNumCols);\r
-}\r
-\r
-void CardWindow::SetBackCardIdx(UINT uBackIdx)\r
-{\r
- if(uBackIdx >= 52 && uBackIdx <= 68)\r
- nBackCardIdx = uBackIdx;\r
-\r
- for(int i = 0; i < nNumCardRegions; i++)\r
- Regions[i]->SetBackCardIdx(uBackIdx);\r
-\r
-}\r
-\r
-void CardWindow::PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy)\r
-{\r
- RECT rect;\r
-\r
- //if just a solid background colour\r
- if(hbmBackImage == 0)\r
- {\r
- SetRect(&rect, dx, dy, dx+width, dy+height);\r
- \r
- /*if(GetVersion() < 0x80000000)\r
- {\r
- PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));\r
- }\r
- else*/\r
- {\r
- HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBackgnd));\r
- FillRect(hdc, &rect, hbr);\r
- DeleteObject(hbr);\r
- }\r
- }\r
- //otherwise, paint using the bitmap\r
- else\r
- {\r
- // Draw whatever part of background we can \r
- BitBlt(hdc, dx, dy, width, height, hdcBackImage, sx, sy, SRCCOPY);\r
-\r
- // Now we need to paint any area outside the bitmap,\r
- // just in case the bitmap is too small to fill whole window\r
- if(0)//sx + width > bm.bmWidth || sy + height > bm.bmHeight)\r
- {\r
- // Find out size of bitmap\r
- BITMAP bm;\r
- GetObject(hbmBackImage, sizeof(bm), &bm);\r
-\r
- HRGN hr1 = CreateRectRgn(sx, sy, sx+width, sy+height);\r
- HRGN hr2 = CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight);\r
- HRGN hr3 = CreateRectRgn(0,0, 1, 1);\r
- HRGN hr4 = CreateRectRgn(0,0, 1, 1);\r
- \r
- CombineRgn(hr3, hr1, hr2, RGN_DIFF);\r
- \r
- GetClipRgn(hdc, hr4);\r
- \r
- CombineRgn(hr3, hr4, hr3, RGN_AND);\r
- SelectClipRgn(hdc, hr3);\r
- \r
- // Fill remaining space not filled with bitmap\r
- HBRUSH hbr = CreateSolidBrush(crBackgnd);\r
- FillRgn(hdc, hr3, hbr);\r
- DeleteObject(hbr);\r
-\r
- // Clean up\r
- SelectClipRgn(hdc, hr4);\r
- \r
- DeleteObject(hr1);\r
- DeleteObject(hr2);\r
- DeleteObject(hr3);\r
- DeleteObject(hr4);\r
- }\r
- }\r
-}\r
-\r
-void CardWindow::SetBackImage(HBITMAP hBitmap)\r
-{\r
- //delete current image?? NO!\r
- if(hdcBackImage == 0)\r
- {\r
- hdcBackImage = CreateCompatibleDC(0);\r
- }\r
-\r
- hbmBackImage = hBitmap;\r
-\r
- if(hBitmap)\r
- SelectObject(hdcBackImage, hBitmap);\r
-}\r
+//
+// CardLib - CardWindow class
+//
+// Freeware
+// Copyright J Brown 2001
+//
+#include <windows.h>
+#include <tchar.h>
+
+#include "globals.h"
+#include "cardlib.h"
+#include "cardbutton.h"
+#include "cardregion.h"
+#include "cardwindow.h"
+#include "cardcolor.h"
+
+extern HPALETTE __holdplacepal;
+
+HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette)
+{
+ HPALETTE hOld;
+
+ hOld = SelectPalette(hdc, hPalette, FALSE);
+ RealizePalette(hdc);
+
+ return hOld;
+}
+
+void RestorePalette(HDC hdc, HPALETTE hOldPal)
+{
+ SelectPalette(hdc, hOldPal, TRUE);
+}
+
+HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours);
+void PaintRect(HDC hdc, RECT *rect, COLORREF colour);
+HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height);
+void GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2);
+
+void LoadCardBitmaps();
+void FreeCardBitmaps();
+
+static TCHAR szCardName[] = _T("CardWnd32");
+static bool fRegistered = false;
+static LONG uCardBitmapRef = 0;
+
+
+void RegisterCardWindow()
+{
+ WNDCLASSEX wc;
+
+ //Window class for the main application parent window
+ wc.cbSize = sizeof(wc);
+ wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
+ wc.lpfnWndProc = CardWindow::CardWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(CardWindow *);
+ wc.hInstance = GetModuleHandle(0);
+ wc.hIcon = 0;
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.hbrBackground = 0;
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = szCardName;
+ wc.hIconSm = 0;
+
+ RegisterClassEx(&wc);
+}
+
+CardWindow::CardWindow() : m_hWnd(0)
+{
+ HDC hdc = GetDC(0);
+
+ nNumButtons = 0;
+ nNumCardRegions = 0;
+ nNumDropZones = 0;
+ nBackCardIdx = 53;
+
+ ResizeWndCallback = 0;
+ hbmBackImage = 0;
+ hdcBackImage = 0;
+
+ srand((unsigned)GetTickCount());
+
+ //All colours (buttons, highlights, decks)
+ //are calculated off this single base colour
+ crBackgnd = PALETTERGB(0,80,0);//PALETTERGB(0,64,100);
+
+ // If uCardBitmapRef was previously zero, then
+ // load the card bitmaps
+ if(1 == InterlockedIncrement(&uCardBitmapRef))
+ {
+ LoadCardBitmaps();
+
+ __hPalette = CreateCardPalette();
+
+ __hdcPlaceHolder = CreateCompatibleDC(hdc);
+
+ __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette);
+
+ __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);
+
+ }
+
+ ReleaseDC(0, hdc);
+
+ //register the window class if necessary
+ if(!fRegistered)
+ {
+ fRegistered = true;
+ RegisterCardWindow();
+ }
+
+}
+
+BOOL CardWindow::Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height)
+{
+ if(m_hWnd)
+ return FALSE;
+
+ //Create the window associated with this object
+ m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szCardName, 0,
+ WS_CHILD | WS_VISIBLE,
+ 0,0,100,100,
+ hwndParent, 0, GetModuleHandle(0), this);
+
+ return TRUE;
+}
+
+BOOL CardWindow::Destroy()
+{
+ DestroyWindow(m_hWnd);
+ m_hWnd = 0;
+
+ return TRUE;
+}
+
+CardWindow::~CardWindow()
+{
+ if(m_hWnd)
+ DestroyWindow(m_hWnd);
+
+ DeleteAll();
+
+ if(0 == InterlockedDecrement(&uCardBitmapRef))
+ {
+ FreeCardBitmaps();
+
+ DeleteObject(__hbmPlaceHolder);
+ DeleteDC (__hdcPlaceHolder);
+
+ RestorePalette(__hdcPlaceHolder, __holdplacepal);
+
+ if(__hPalette)
+ DeleteObject(__hPalette);
+ }
+}
+
+bool CardWindow::DeleteAll()
+{
+ int i;
+
+ for(i = 0; i < nNumCardRegions; i++)
+ {
+ delete Regions[i];
+ }
+
+ for(i = 0; i < nNumButtons; i++)
+ {
+ delete Buttons[i];
+ }
+
+ for(i = 0; i < nNumDropZones; i++)
+ {
+ delete dropzone[i];
+ }
+
+ nNumCardRegions = nNumButtons = nNumDropZones = 0;
+
+ return true;
+}
+
+void CardWindow::SetBackColor(COLORREF cr)
+{
+ crBackgnd = cr;
+ int i;
+
+ //
+ // Create the exact palette we need to render the buttons/stacks
+ //
+ RestorePalette(__hdcPlaceHolder, __holdplacepal);
+
+ if(__hPalette)
+ DeleteObject(__hPalette);
+
+ __hPalette = CreateCardPalette();
+
+ //
+ // re-create the place-holder!
+ HDC hdc = GetDC(m_hWnd);
+
+ DeleteObject(__hbmPlaceHolder);
+
+ __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette);
+
+ __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);
+ //SelectObject(__hdcPlaceHolder, __hbmPlaceHolder);
+
+ //reset all buttons to same colour
+ for(i = 0; i < nNumButtons; i++)
+ {
+ if(Buttons[i]->GetStyle() & CB_PUSHBUTTON)
+ {
+ Buttons[i]->SetBackColor(ColorScaleRGB(crBackgnd, RGB(255,255,255), 0.1));
+ }
+ else
+ {
+ Buttons[i]->SetBackColor(crBackgnd);
+ }
+ }
+
+ for(i = 0; i < nNumCardRegions; i++)
+ {
+ Regions[i]->SetBackColor(crBackgnd);
+ }
+
+
+ ReleaseDC(m_hWnd, hdc);
+}
+
+COLORREF CardWindow::GetBackColor()
+{
+ return crBackgnd;
+}
+
+CardButton* CardWindow::CardButtonFromPoint(int x, int y)
+{
+ CardButton *bptr = 0;
+
+ POINT pt;
+ pt.x = x;
+ pt.y = y;
+
+ //Search BACKWARDS...to reflect the implicit Z-order that
+ //the button creation provided
+ for(int i = nNumButtons - 1; i >= 0; i--)
+ {
+ bptr = Buttons[i];
+ if(PtInRect(&bptr->rect, pt) && bptr->fVisible)
+ return bptr;
+ }
+
+ return 0;
+}
+
+CardRegion* CardWindow::CardRegionFromPoint(int x, int y)
+{
+ POINT pt;
+ pt.x = x;
+ pt.y = y;
+
+ //Search BACKWARDS...to reflect the implicit Z-order that
+ //the stack creation provided
+ for(int i = nNumCardRegions - 1; i >= 0; i--)
+ {
+ if(Regions[i]->IsPointInStack(x, y))
+ return Regions[i];
+ }
+
+ return 0;
+}
+
+//
+// Forward all window messages onto the appropriate
+// class instance
+//
+LRESULT CALLBACK CardWindow::CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ CardWindow *cw = (CardWindow *)GetWindowLong(hwnd, 0);
+ return cw->WndProc(hwnd, iMsg, wParam, lParam);
+}
+
+void CardWindow::Paint(HDC hdc)
+{
+ int i;
+ RECT rect;
+ HPALETTE hOldPal;
+
+ hOldPal = UseNicePalette(hdc, __hPalette);
+
+ //
+ // Clip the card stacks so that they won't
+ // get painted over
+ //
+ for(i = 0; i < nNumCardRegions; i++)
+ {
+ Regions[i]->Clip(hdc);
+ }
+
+ //
+ // Clip the buttons
+ //
+ for(i = 0; i < nNumButtons; i++)
+ {
+ Buttons[i]->Clip(hdc);
+ }
+
+
+ // Now paint the whole screen with background colour,
+ //
+ GetClientRect(m_hWnd, &rect);
+
+ //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));
+ PaintCardRgn(hdc, 0, 0, rect.right, rect.bottom, 0, 0);
+ SelectClipRgn(hdc, NULL);
+
+ // Don't let cards draw over buttons, so clip buttons again
+ //
+ for(i = 0; i < nNumButtons; i++)
+ {
+ Buttons[i]->Clip(hdc);
+ }
+
+ // Paint each card stack in turn
+ //
+ for(i = 0; i < nNumCardRegions; i++)
+ {
+ Regions[i]->Render(hdc);
+ }
+
+ // Paint each button now
+ //
+ SelectClipRgn(hdc, NULL);
+
+ for(i = 0; i < nNumButtons; i++)
+ {
+ Buttons[i]->Redraw();
+ }
+
+ RestorePalette(hdc, hOldPal);
+}
+
+
+
+
+LRESULT CALLBACK CardWindow::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+
+ CREATESTRUCT *cs;
+
+ static CardButton *buttonptr = 0;
+ static CardRegion *stackptr = 0;
+
+ int x, y, i;
+
+ switch(iMsg)
+ {
+ case WM_NCCREATE:
+
+ // When we created this window, we passed in the
+ // pointer to the class object (CardWindow *) in the
+ // call to CreateWindow.
+ cs = (CREATESTRUCT *)lParam;
+
+ //
+ // associate this class with the window
+ //
+ SetWindowLong(hwnd, 0, (LONG)cs->lpCreateParams);
+
+ return 1;
+
+ case WM_NCDESTROY:
+ // Don't delete anything here..
+ break;
+
+ case WM_SIZE:
+ nWidth = LOWORD(lParam);
+ nHeight = HIWORD(lParam);
+
+ //
+ // reposition all the stacks and buttons
+ // in case any of them are centered, right-justified etc
+ //
+ for(i = 0; i < nNumCardRegions; i++)
+ {
+ Regions[i]->AdjustPosition(nWidth, nHeight);
+ }
+
+ for(i = 0; i < nNumButtons; i++)
+ {
+ Buttons[i]->AdjustPosition(nWidth, nHeight);
+ }
+
+ //
+ // Call the user-defined resize proc AFTER all the stacks
+ // have been positioned
+ //
+ if(ResizeWndCallback)
+ ResizeWndCallback(nWidth, nHeight);
+
+ return 0;
+
+ case WM_PAINT:
+
+ hdc = BeginPaint(hwnd, &ps);
+
+ Paint(hdc);
+
+ EndPaint(hwnd, &ps);
+ return 0;
+
+ case WM_TIMER:
+
+ //find the timer object in the registered funcs
+ /*if(wParam >= 0x10000)
+ {
+ for(i = 0; i < nRegFuncs; i++)
+ {
+ if(RegFuncs[i].id == wParam)
+ {
+ KillTimer(hwnd, wParam);
+
+ //call the registered function!!
+ RegFuncs[i].func(RegFuncs[i].dwParam);
+
+ RegFuncs[i] = RegFuncs[nRegFuncs-1];
+ nRegFuncs--;
+ }
+ }
+ }
+ else*/
+ {
+ //find the cardstack
+ CardRegion *stackobj = (CardRegion *)wParam;//CardStackFromId(wParam);
+ stackobj->DoFlash();
+ }
+
+ return 0;
+
+ case WM_LBUTTONDBLCLK:
+
+ x = (short)LOWORD(lParam);
+ y = (short)HIWORD(lParam);
+
+ if((buttonptr = CardButtonFromPoint(x, y)) != 0)
+ {
+ buttonptr->OnLButtonDown(hwnd, x, y);
+ return 0;
+ }
+
+ if((stackptr = CardRegionFromPoint(x, y)) != 0)
+ {
+ stackptr->OnLButtonDblClk(x, y);
+ stackptr = 0;
+ }
+
+ return 0;
+
+ case WM_LBUTTONDOWN:
+
+ x = (short)LOWORD(lParam);
+ y = (short)HIWORD(lParam);
+
+ //if clicked on a button
+ if((buttonptr = CardButtonFromPoint(x, y)) != 0)
+ {
+ if(buttonptr->OnLButtonDown(hwnd, x, y) == 0)
+ buttonptr = 0;
+
+ return 0;
+ }
+
+ if((stackptr = CardRegionFromPoint(x, y)) != 0)
+ {
+ if(!stackptr->OnLButtonDown(x, y))
+ stackptr = 0;
+ }
+
+ return 0;
+
+ case WM_LBUTTONUP:
+
+ x = (short)LOWORD(lParam);
+ y = (short)HIWORD(lParam);
+
+ //
+ // if we were clicking a button
+ //
+ if(buttonptr != 0)
+ {
+ buttonptr->OnLButtonUp(hwnd, x, y);
+ buttonptr = 0;
+ return 0;
+ }
+
+ if(stackptr != 0)
+ {
+ stackptr->OnLButtonUp(x, y);
+ stackptr = 0;
+ return 0;
+ }
+
+ return 0;
+
+ case WM_MOUSEMOVE:
+
+ x = (short)LOWORD(lParam);
+ y = (short)HIWORD(lParam);
+
+ // if we were clicking a button
+ if(buttonptr != 0)
+ {
+ buttonptr->OnMouseMove(hwnd, x, y);
+ return 0;
+ }
+
+ if(stackptr != 0)
+ {
+ return stackptr->OnMouseMove(x, y);
+ }
+
+ return 0;
+
+ }
+
+ return DefWindowProc (hwnd, iMsg, wParam, lParam);
+}
+
+
+CardRegion* CardWindow::CardRegionFromId(int id)
+{
+ for(int i = 0; i < nNumCardRegions; i++)
+ {
+ if(Regions[i]->id == id)
+ return Regions[i];
+ }
+
+ return 0;
+}
+
+CardButton* CardWindow::CardButtonFromId(int id)
+{
+ for(int i = 0; i < nNumButtons; i++)
+ {
+ if(Buttons[i]->id == id)
+ return Buttons[i];
+ }
+
+ return 0;
+}
+
+void CardWindow::Redraw()
+{
+ InvalidateRect(m_hWnd, 0, 0);
+ UpdateWindow(m_hWnd);
+}
+
+bool CardWindow::DeleteButton(CardButton *pButton)
+{
+ for(int i = 0; i < nNumButtons; i++)
+ {
+ if(Buttons[i] == pButton)
+ {
+ CardButton *cb = Buttons[i];
+
+ //shift any after this one backwards
+ for(int j = i; j < nNumButtons - 1; j++)
+ {
+ Buttons[j] = Buttons[j + 1];
+ }
+
+ delete cb;
+ nNumButtons--;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CardWindow::DeleteRegion(CardRegion *pRegion)
+{
+ for(int i = 0; i < nNumCardRegions; i++)
+ {
+ if(Regions[i] == pRegion)
+ {
+ CardRegion *cr = Regions[i];
+
+ //shift any after this one backwards
+ for(int j = i; j < nNumCardRegions - 1; j++)
+ {
+ Regions[j] = Regions[j + 1];
+ }
+
+ delete cr;
+ nNumCardRegions--;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CardWindow::EmptyStacks(void)
+{
+ for(int i = 0; i < nNumCardRegions; i++)
+ {
+ Regions[i]->Clear();
+ Regions[i]->Update();
+ }
+
+ Redraw();
+}
+
+bool CardWindow::DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX)
+{
+ int numvisiblestacks = 0;
+ int curx = nStartX;
+ int startindex = -1;
+ int i;
+
+ //find the stack which starts with our ID
+ for(i = 0; i < nNumCardRegions; i++)
+ {
+ if(Regions[i]->Id() == nIdFrom)
+ {
+ startindex = i;
+ break;
+ }
+ }
+
+ //if didn't find, return
+ if(i == nNumCardRegions) return false;
+
+ //count the stacks that are visible
+ for(i = startindex; i < startindex + nNumStacks; i++)
+ {
+ if(Regions[i]->IsVisible())
+ numvisiblestacks++;
+ }
+
+ if(xJustify == CS_XJUST_CENTER)
+ {
+ //startx -= ((numvisiblestacks + spacing) * cardwidth - spacing) / 2;
+ int viswidth;
+ viswidth = numvisiblestacks * __cardwidth;
+ viswidth += xSpacing * (numvisiblestacks - 1);
+ curx = -(viswidth - __cardwidth) / 2;
+
+ for(i = startindex; i < startindex + nNumStacks; i++)
+ {
+ if(Regions[i]->IsVisible())
+ {
+ Regions[i]->xadjust = curx;
+ Regions[i]->xjustify = CS_XJUST_CENTER;
+ curx += Regions[i]->width + xSpacing;
+ }
+
+ }
+ }
+
+ if(xJustify == CS_XJUST_RIGHT)
+ {
+ nStartX -= ((numvisiblestacks + xSpacing) * __cardwidth - xSpacing);
+ }
+
+ if(xJustify == CS_XJUST_NONE)
+ {
+ for(i = startindex; i < startindex + nNumStacks; i++)
+ {
+ if(Regions[i]->IsVisible())
+ {
+ Regions[i]->xpos = curx;
+ curx += Regions[i]->width + xSpacing;
+ Regions[i]->UpdateSize();
+ }
+
+ }
+ }
+
+ return 0;
+}
+
+void CardWindow::Update()
+{
+ for(int i = 0; i < nNumCardRegions; i++)
+ {
+ Regions[i]->AdjustPosition(nWidth, nHeight);
+ }
+}
+
+
+void CardWindow::SetResizeProc(pResizeWndProc proc)
+{
+ ResizeWndCallback = proc;
+}
+
+
+HPALETTE CardWindow::CreateCardPalette()
+{
+ COLORREF cols[10];
+ int nNumCols;
+
+
+ //include button text colours
+ cols[0] = RGB(0, 0, 0);
+ cols[1] = RGB(255, 255, 255);
+
+ //include the base background colour
+ cols[1] = crBackgnd;
+
+ //include the standard button colours...
+ cols[3] = CardButton::GetHighlight(crBackgnd);
+ cols[4] = CardButton::GetShadow(crBackgnd);
+ cols[5] = CardButton::GetFace(crBackgnd);
+
+ //include the sunken image bitmap colours...
+ GetSinkCols(crBackgnd, &cols[6], &cols[7], &cols[8], &cols[9]);
+
+ nNumCols = 10;
+
+ return MakePaletteFromCols(cols, nNumCols);
+}
+
+void CardWindow::SetBackCardIdx(UINT uBackIdx)
+{
+ if(uBackIdx >= 52 && uBackIdx <= 68)
+ nBackCardIdx = uBackIdx;
+
+ for(int i = 0; i < nNumCardRegions; i++)
+ Regions[i]->SetBackCardIdx(uBackIdx);
+
+}
+
+void CardWindow::PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy)
+{
+ RECT rect;
+
+ //if just a solid background colour
+ if(hbmBackImage == 0)
+ {
+ SetRect(&rect, dx, dy, dx+width, dy+height);
+
+ /*if(GetVersion() < 0x80000000)
+ {
+ PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));
+ }
+ else*/
+ {
+ HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBackgnd));
+ FillRect(hdc, &rect, hbr);
+ DeleteObject(hbr);
+ }
+ }
+ //otherwise, paint using the bitmap
+ else
+ {
+ // Draw whatever part of background we can
+ BitBlt(hdc, dx, dy, width, height, hdcBackImage, sx, sy, SRCCOPY);
+
+ // Now we need to paint any area outside the bitmap,
+ // just in case the bitmap is too small to fill whole window
+ if(0)//sx + width > bm.bmWidth || sy + height > bm.bmHeight)
+ {
+ // Find out size of bitmap
+ BITMAP bm;
+ GetObject(hbmBackImage, sizeof(bm), &bm);
+
+ HRGN hr1 = CreateRectRgn(sx, sy, sx+width, sy+height);
+ HRGN hr2 = CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight);
+ HRGN hr3 = CreateRectRgn(0,0, 1, 1);
+ HRGN hr4 = CreateRectRgn(0,0, 1, 1);
+
+ CombineRgn(hr3, hr1, hr2, RGN_DIFF);
+
+ GetClipRgn(hdc, hr4);
+
+ CombineRgn(hr3, hr4, hr3, RGN_AND);
+ SelectClipRgn(hdc, hr3);
+
+ // Fill remaining space not filled with bitmap
+ HBRUSH hbr = CreateSolidBrush(crBackgnd);
+ FillRgn(hdc, hr3, hbr);
+ DeleteObject(hbr);
+
+ // Clean up
+ SelectClipRgn(hdc, hr4);
+
+ DeleteObject(hr1);
+ DeleteObject(hr2);
+ DeleteObject(hr3);
+ DeleteObject(hr4);
+ }
+ }
+}
+
+void CardWindow::SetBackImage(HBITMAP hBitmap)
+{
+ //delete current image?? NO!
+ if(hdcBackImage == 0)
+ {
+ hdcBackImage = CreateCompatibleDC(0);
+ }
+
+ hbmBackImage = hBitmap;
+
+ if(hBitmap)
+ SelectObject(hdcBackImage, hBitmap);
+}