-//\r
-// CardLib - CardRegion class\r
-//\r
-// Freeware\r
-// Copyright J Brown 2001\r
-//\r
-#include <windows.h>\r
-\r
-#include "cardlib.h"\r
-#include "cardregion.h"\r
-#include "cardwindow.h"\r
-#include "cardcolor.h"\r
-\r
-HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, int width, int height);\r
-\r
-void PaintRect(HDC hdc, RECT *rect, COLORREF colour);\r
-\r
-CardRegion::CardRegion(CardWindow &parent, int Id, bool visible, int x, int y, int xOffset, int yOffset) \r
-: id(Id), parentWnd(parent), xpos(x), ypos(y), xoffset(xOffset), yoffset(yOffset), fVisible(visible)\r
-{\r
- width = __cardwidth;\r
- height = __cardheight;\r
-\r
- crBackgnd = RGB(0, 64, 100);\r
-\r
- uFaceDirType = CS_FACE_UP;\r
- nFaceDirOption = 0;\r
- uEmptyImage = CS_EI_SUNK;\r
-\r
- fVisible = visible;\r
-\r
- nThreedCount = 1;\r
- nBackCardIdx = 53;\r
-\r
- Update(); //Update this stack's size+card count\r
-\r
- hdcBackGnd = 0;\r
- hbmBackGnd = 0;\r
- hdcDragCard = 0;\r
- hbmDragCard = 0;\r
-\r
- nDragCardWidth = 0;\r
- nDragCardHeight = 0;\r
- \r
- CanDragCallback = 0;\r
- CanDropCallback = 0;\r
- AddCallback = 0;\r
- RemoveCallback = 0;\r
- ClickCallback = 0;\r
- DblClickCallback = 0;\r
-\r
- uDragRule = CS_DRAG_ALL;\r
- uDropRule = CS_DROP_ALL;\r
-\r
- xjustify = yjustify = xadjust = yadjust = 0;\r
-\r
- nFlashCount = 0;\r
- fFlashVisible = false;\r
- uFlashTimer = (UINT)-1;\r
-\r
- fMouseDragging = false;\r
-\r
- mxlock = CreateMutex(0, FALSE, 0);\r
-}\r
-\r
-CardRegion::~CardRegion()\r
-{\r
- CloseHandle(mxlock);\r
-}\r
-\r
-void CardRegion::SetBackColor(COLORREF cr)\r
-{\r
- crBackgnd = cr;\r
-}\r
-\r
-int CardRegion::CalcApparentCards(int realnum)\r
-{\r
- return ((realnum + nThreedCount - 1) - (realnum + nThreedCount - 1) % nThreedCount) / nThreedCount;\r
-}\r
-\r
-void CardRegion::CalcApparentCards()\r
-{\r
- nNumApparentCards = CalcApparentCards(cardstack.NumCards());\r
-}\r
-\r
-\r
-void CardRegion::UpdateSize(void)\r
-{\r
- if(cardstack.NumCards() > 0)\r
- {\r
- if(xoffset > 0)\r
- width = (nNumApparentCards - 1) * xoffset + __cardwidth;\r
- else\r
- width = (nNumApparentCards - 1) * -xoffset + __cardwidth;\r
-\r
- if(yoffset > 0)\r
- height = (nNumApparentCards - 1) * yoffset + __cardheight;\r
- else\r
- height = (nNumApparentCards - 1) * -yoffset + __cardheight;\r
- }\r
- else\r
- {\r
- width = __cardwidth;\r
- height = __cardheight;\r
- }\r
-}\r
-\r
-CardRegion *CardWindow::CreateRegion(int id, bool fVisible, int x, int y, int xoffset, int yoffset)\r
-{\r
- CardRegion *cr;\r
-\r
- if(nNumCardRegions == MAXCARDSTACKS)\r
- return FALSE;\r
-\r
- cr = new CardRegion(*this, id, fVisible, x, y, xoffset, yoffset);\r
- cr->SetBackColor(crBackgnd);\r
- cr->SetBackCardIdx(nBackCardIdx);\r
-\r
- Regions[nNumCardRegions++] = cr;\r
- \r
- return cr;\r
-}\r
-\r
-int CardRegion::GetOverlapRatio(int x, int y, int w, int h)\r
-{\r
- RECT me, him;\r
- RECT inter;\r
- SetRect(&him, x, y, x+w, y+h);\r
- SetRect(&me, xpos, ypos, xpos+width, ypos+height);\r
-\r
- //see if the specified rectangle overlaps us\r
- if(IntersectRect(&inter, &me, &him))\r
- {\r
- int wi = inter.right - inter.left;\r
- int hi = inter.bottom - inter.top;\r
-\r
- int overlap = wi * hi;\r
- int total = width * height;\r
-\r
- int percent = (overlap << 16) / total;\r
- return (percent * 100) >> 16;\r
- }\r
- //do not overlap\r
- else\r
- {\r
- return 0;\r
- }\r
-}\r
-\r
-bool CardRegion::SetDragRule(UINT uDragType, pCanDragProc proc)\r
-{ \r
- switch(uDragType)\r
- {\r
- case CS_DRAG_NONE: case CS_DRAG_ALL: case CS_DRAG_TOP:\r
- uDragRule = uDragType;\r
- return true;\r
-\r
- case CS_DRAG_CALLBACK:\r
- uDragRule = uDragType;\r
- CanDragCallback = proc;\r
- return true;\r
-\r
- default:\r
- return false;\r
- }\r
-}\r
-\r
-bool CardRegion::SetDropRule(UINT uDropType, pCanDropProc proc)\r
-{ \r
- switch(uDropType)\r
- {\r
- case CS_DROP_NONE: case CS_DROP_ALL: \r
- uDropRule = uDropType;\r
- return true;\r
-\r
- case CS_DROP_CALLBACK:\r
- uDropRule = uDropType;\r
- CanDropCallback = proc;\r
- return true;\r
-\r
- default:\r
- return false;\r
- }\r
-}\r
-\r
-void CardRegion::SetClickProc(pClickProc proc)\r
-{\r
- ClickCallback = proc;\r
-}\r
-\r
-void CardRegion::SetDblClickProc(pClickProc proc)\r
-{\r
- DblClickCallback = proc;\r
-}\r
-\r
-void CardRegion::SetAddCardProc(pAddProc proc)\r
-{\r
- AddCallback = proc;\r
-}\r
-\r
-void CardRegion::SetRemoveCardProc(pRemoveProc proc)\r
-{\r
- RemoveCallback = proc;\r
-}\r
-\r
-void CardRegion::Update()\r
-{\r
- CalcApparentCards();\r
- UpdateSize(); \r
- UpdateFaceDir(cardstack);\r
-}\r
-\r
-\r
-bool CardRegion::SetThreedCount(int count)\r
-{\r
- if(count < 1) \r
- {\r
- return false;\r
- }\r
- else\r
- {\r
- nThreedCount = count;\r
- return true;\r
- }\r
-}\r
-\r
-void CardRegion::SetOffsets(int x, int y)\r
-{\r
- xoffset = x;\r
- yoffset = y;\r
-}\r
-\r
-void CardRegion::SetPos(int x, int y)\r
-{\r
- xpos = x;\r
- ypos = y;\r
-}\r
-\r
-void CardRegion::Show(bool fShow)\r
-{\r
- fVisible = fShow;\r
-}\r
-\r
-bool CardRegion::IsVisible()\r
-{ \r
- return fVisible;\r
-}\r
-\r
-void CardRegion::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust)\r
-{\r
- xjustify = xJustify;\r
- yjustify = yJustify;\r
- xadjust = xAdjust;\r
- yadjust = yAdjust;\r
-}\r
-\r
-void CardRegion::SetFaceDirection(UINT uDirType, int nOption)\r
-{\r
- switch(uDirType)\r
- {\r
- case CS_FACE_UP: case CS_FACE_DOWN: case CS_FACE_DOWNUP:\r
- case CS_FACE_UPDOWN: case CS_FACE_ANY:\r
- uFaceDirType = uDirType;\r
- nFaceDirOption = nOption;\r
-\r
- UpdateFaceDir(cardstack);\r
-\r
- break;\r
- }\r
-}\r
-\r
-UINT CardRegion::GetFaceDirection(int *pnOption)\r
-{\r
- if(pnOption)\r
- *pnOption = nFaceDirOption;\r
-\r
- return uFaceDirType;\r
-}\r
-\r
-void CardRegion::AdjustPosition(int winwidth, int winheight)\r
-{\r
- Update(); //Update this stack's card count + size\r
-\r
- switch(xjustify)\r
- {\r
- default: case CS_XJUST_NONE: break;\r
- \r
- case CS_XJUST_CENTER: //centered\r
- xpos = (winwidth - (width & ~0x1)) / 2;\r
- xpos += xadjust;\r
-\r
- if(xoffset < 0) xpos += (width - __cardwidth);\r
- \r
- break;\r
-\r
- case CS_XJUST_RIGHT: //right-aligned\r
- xpos = winwidth - __cardwidth;//width - 20;\r
- xpos += xadjust;\r
- break;\r
- }\r
-\r
- switch(yjustify)\r
- {\r
- default: case CS_YJUST_NONE: break;\r
- \r
- case CS_YJUST_CENTER: //centered\r
- ypos = (winheight - height) / 2;\r
- ypos += yadjust;\r
- if(yoffset < 0) ypos += (height - __cardheight);\r
- break;\r
-\r
- case CS_YJUST_BOTTOM: //bottom-aligned\r
- ypos = winheight - __cardheight;//height - 20;\r
- ypos += yadjust;\r
- break;\r
- }\r
-\r
-}\r
-\r
-\r
-void CardRegion::Flash(int count, int milliseconds)\r
-{\r
- if(count <= 0) return;\r
-\r
- nFlashCount = count;\r
- fFlashVisible = false;\r
- uFlashTimer = SetTimer((HWND)parentWnd, (WPARAM)this, milliseconds, 0);\r
- \r
- parentWnd.Redraw();\r
-}\r
-\r
-void CardRegion::StopFlash()\r
-{\r
- if(uFlashTimer != (UINT)-1)\r
- {\r
- KillTimer((HWND)parentWnd, uFlashTimer);\r
- nFlashCount = 0;\r
- uFlashTimer = (UINT)-1;\r
- fFlashVisible = true;\r
- }\r
-}\r
-\r
-void CardRegion::DoFlash()\r
-{\r
- if(uFlashTimer != (UINT)-1)\r
- {\r
- fFlashVisible = !fFlashVisible;\r
-\r
- if(--nFlashCount == 0)\r
- {\r
- KillTimer((HWND)parentWnd, uFlashTimer);\r
- uFlashTimer = (UINT)-1;\r
- fFlashVisible = true;\r
- }\r
- \r
- parentWnd.Redraw();\r
- }\r
-}\r
-\r
-int CardRegion::Id()\r
-{\r
- return id;\r
-}\r
-\r
-void CardRegion::SetEmptyImage(UINT uImage)\r
-{\r
- switch(uImage)\r
- {\r
- case CS_EI_NONE: case CS_EI_SUNK:\r
- uEmptyImage = uImage;\r
- break;\r
-\r
- default:\r
- uEmptyImage = CS_EI_NONE;\r
- break;\r
- }\r
- \r
-}\r
-\r
-void CardRegion::SetBackCardIdx(UINT uBackIdx)\r
-{\r
- if(uBackIdx >= 52 && uBackIdx <= 68)\r
- nBackCardIdx = uBackIdx;\r
-}\r
-\r
-void CardRegion::SetCardStack(const CardStack &cs)\r
-{ \r
- //make a complete copy of the specified stack..\r
- cardstack = cs; \r
-\r
- // Update the face-direction and stack-size\r
- Update();\r
-}\r
-\r
-const CardStack & CardRegion::GetCardStack()\r
-{ \r
- //return reference to our internal stack\r
- return cardstack; \r
-}\r
-\r
-//\r
-// Update specified card-stack using THIS stack's\r
-// face direction rules!\r
-//\r
-void CardRegion::UpdateFaceDir(CardStack &cards)\r
-{\r
- int i, n, num;\r
-\r
- num = cards.NumCards();\r
-\r
- //Now apply the face direction rules..\r
- switch(uFaceDirType)\r
- {\r
- case CS_FACE_UP:\r
-\r
- for(i = 0; i < num; i++)\r
- {\r
- cards[i].SetFaceUp(true);\r
- }\r
-\r
- break;\r
-\r
- case CS_FACE_DOWN:\r
-\r
- for(i = 0; i < num; i++)\r
- {\r
- cards[i].SetFaceUp(false);\r
- }\r
-\r
- break;\r
-\r
- case CS_FACE_DOWNUP:\r
-\r
- num = cardstack.NumCards();\r
- n = min(nFaceDirOption, num);\r
-\r
- //bottom n cards..\r
- for(i = 0; i < n; i++)\r
- {\r
- cards[num - i - 1].SetFaceUp(false);\r
- }\r
-\r
- for(i = n; i < num; i++)\r
- {\r
- cards[num - i - 1].SetFaceUp(true);\r
- }\r
-\r
- break;\r
-\r
- case CS_FACE_UPDOWN:\r
-\r
- num = cardstack.NumCards();\r
- n = min(nFaceDirOption, num);\r
-\r
- for(i = 0; i < n; i++)\r
- {\r
- cards[num - i - 1].SetFaceUp(true);\r
- }\r
-\r
- for(i = n; i < num; i++)\r
- {\r
- cards[num - i - 1].SetFaceUp(false);\r
- }\r
-\r
- break;\r
-\r
- case CS_FACE_ANY: //cards can be any orientation\r
- default:\r
- break;\r
- }\r
-}\r
-\r
-bool CardRegion::MoveCard(CardRegion *pDestStack, int nNumCards, bool fAnimate)\r
-{\r
- HDC hdc;\r
-\r
- int x, y;\r
-\r
- if(pDestStack == 0) return false; //{ forcedfacedir = -1 ;return 0; }\r
-\r
- if(nNumCards < 0 || nNumCards > cardstack.NumCards())\r
- return false;\r
-\r
- x = xpos + xoffset * (nNumApparentCards - nNumCards);\r
- y = ypos + yoffset * (nNumApparentCards - nNumCards);\r
-\r
- oldx = x;\r
- oldy = y;\r
- \r
- dragstack = cardstack.Pop(nNumCards);\r
-\r
- //Alter the drag-stack so that it's cards are the same way up\r
- //as the destination. Use the destination's drag-rules\r
- //instead of this ones!!\r
- CardStack temp;\r
- temp.Push(pDestStack->GetCardStack());\r
- temp.Push(dragstack);\r
-\r
- pDestStack->UpdateFaceDir(temp);\r
-\r
- dragstack = temp.Pop(nNumCards);\r
-\r
- if(fAnimate)\r
- {\r
- iNumDragCards = nNumCards;\r
- PrepareDragBitmaps(nNumCards);\r
- }\r
-\r
- Update(); //Update this stack's size+card count\r
-\r
- if(fAnimate)\r
- {\r
- hdc = GetDC((HWND)parentWnd);\r
-\r
- ZoomCard(hdc, x, y, pDestStack);\r
- \r
- ReleaseDC((HWND)parentWnd, hdc);\r
- ReleaseDragBitmaps();\r
- }\r
-\r
- // Get a copy of the cardstack\r
- CardStack cs = pDestStack->GetCardStack();\r
- cs.Push(dragstack);\r
- \r
- pDestStack->SetCardStack(cs);\r
- \r
- //cs = pDestStack->GetCardStack();\r
- //pDestStack->Update();\r
- //pDestStack->UpdateFaceDir(cs);\r
-\r
- RedrawIfNotDim(pDestStack, false);\r
-\r
- //forcedfacedir = -1;\r
- return true;\r
-}\r
-\r
-//\r
-// Simple wrappers\r
-//\r
-int CardRegion::NumCards() const\r
-{\r
- if(fMouseDragging)\r
- return cardstack.NumCards() + dragstack.NumCards();\r
- else\r
- return cardstack.NumCards(); \r
-}\r
-\r
-bool CardRegion::Lock()\r
-{\r
- DWORD dw = WaitForSingleObject(mxlock, 0);\r
-\r
- if(dw == WAIT_OBJECT_0)\r
- {\r
- //TRACE("LockStack succeeded\n");\r
- return true; \r
- }\r
- else\r
- {\r
- //TRACE("LockStack failed\n");\r
- return false;\r
- }\r
- return false;\r
-}\r
-\r
-bool CardRegion::UnLock()\r
-{\r
- if(ReleaseMutex(mxlock))\r
- {\r
- //TRACE("Unlocking stack\n");\r
- return true;\r
- }\r
- else\r
- {\r
- //TRACE("Unlocking stack failed\n"); \r
- return false;\r
- }\r
-}\r
-\r
-bool CardRegion::PlayCard(CardRegion *pDestStack, int value, int num)\r
-{\r
- //search the stack for the specified card value...\r
- while(num--)\r
- {\r
- for(int i = 0; i < cardstack.NumCards(); i++)\r
- {\r
- if(cardstack[i].HiVal() == value)\r
- {\r
- //swap the card with one at top pos...\r
- Card card = cardstack.RemoveCard(i);\r
- cardstack.Push(card);\r
-\r
- Redraw();\r
-\r
- MoveCard(pDestStack, 1, true);\r
- break;\r
- }\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
-//\r
-// Redraw the current stack if it has a different\r
-// layout than the comparison stack.\r
-//\r
-void CardRegion::RedrawIfNotDim(CardRegion *pCompare, bool fFullRedraw)\r
-{\r
- //\r
- //\r
- //\r
- if( pCompare->xoffset != xoffset || \r
- pCompare->yoffset != yoffset || \r
- pCompare->nThreedCount != nThreedCount ||\r
- pCompare->uFaceDirType != uFaceDirType ||\r
- pCompare->uFaceDirType != CS_FACE_ANY\r
- )\r
- {\r
- if(fFullRedraw)\r
- parentWnd.Redraw();\r
- else\r
- pCompare->Redraw();\r
- }\r
- \r
-}\r
-\r
-//\r
-// SimulateDrag mimicks the complete drag+drop process.\r
-// It basically just a MoveCard(..), but it calls the\r
-// event callbacks as well.\r
-//\r
-bool CardRegion::SimulateDrag(CardRegion *pDestStack, int iNumDragCards, bool fAnimate)\r
-{\r
- if(pDestStack == 0)\r
- return false;\r
-\r
- if(CanDragCards(iNumDragCards) != false)\r
- {\r
- //make a list of the cards that would be in the drag list\r
- CardStack tempstack = cardstack.Top(iNumDragCards);\r
-\r
- if(pDestStack->CanDropCards(tempstack)) \r
- {\r
- MoveCard(pDestStack, iNumDragCards, fAnimate); \r
- \r
- if(RemoveCallback)\r
- RemoveCallback(*this, iNumDragCards);\r
-\r
- if(pDestStack->AddCallback)\r
- pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);\r
- \r
- RedrawIfNotDim(pDestStack, true);\r
- } \r
-\r
- }\r
-\r
- return true;\r
-}\r
+//
+// CardLib - CardRegion class
+//
+// Freeware
+// Copyright J Brown 2001
+//
+#include <windows.h>
+
+#include "cardlib.h"
+#include "cardregion.h"
+#include "cardwindow.h"
+#include "cardcolor.h"
+
+HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, int width, int height);
+
+void PaintRect(HDC hdc, RECT *rect, COLORREF colour);
+
+CardRegion::CardRegion(CardWindow &parent, int Id, bool visible, int x, int y, int xOffset, int yOffset)
+: id(Id), parentWnd(parent), xpos(x), ypos(y), xoffset(xOffset), yoffset(yOffset), fVisible(visible)
+{
+ width = __cardwidth;
+ height = __cardheight;
+
+ crBackgnd = RGB(0, 64, 100);
+
+ uFaceDirType = CS_FACE_UP;
+ nFaceDirOption = 0;
+ uEmptyImage = CS_EI_SUNK;
+
+ fVisible = visible;
+
+ nThreedCount = 1;
+ nBackCardIdx = 53;
+
+ Update(); //Update this stack's size+card count
+
+ hdcBackGnd = 0;
+ hbmBackGnd = 0;
+ hdcDragCard = 0;
+ hbmDragCard = 0;
+
+ nDragCardWidth = 0;
+ nDragCardHeight = 0;
+
+ CanDragCallback = 0;
+ CanDropCallback = 0;
+ AddCallback = 0;
+ RemoveCallback = 0;
+ ClickCallback = 0;
+ DblClickCallback = 0;
+
+ uDragRule = CS_DRAG_ALL;
+ uDropRule = CS_DROP_ALL;
+
+ xjustify = yjustify = xadjust = yadjust = 0;
+
+ nFlashCount = 0;
+ fFlashVisible = false;
+ uFlashTimer = (UINT)-1;
+
+ fMouseDragging = false;
+
+ mxlock = CreateMutex(0, FALSE, 0);
+}
+
+CardRegion::~CardRegion()
+{
+ CloseHandle(mxlock);
+}
+
+void CardRegion::SetBackColor(COLORREF cr)
+{
+ crBackgnd = cr;
+}
+
+int CardRegion::CalcApparentCards(int realnum)
+{
+ return ((realnum + nThreedCount - 1) - (realnum + nThreedCount - 1) % nThreedCount) / nThreedCount;
+}
+
+void CardRegion::CalcApparentCards()
+{
+ nNumApparentCards = CalcApparentCards(cardstack.NumCards());
+}
+
+
+void CardRegion::UpdateSize(void)
+{
+ if(cardstack.NumCards() > 0)
+ {
+ if(xoffset > 0)
+ width = (nNumApparentCards - 1) * xoffset + __cardwidth;
+ else
+ width = (nNumApparentCards - 1) * -xoffset + __cardwidth;
+
+ if(yoffset > 0)
+ height = (nNumApparentCards - 1) * yoffset + __cardheight;
+ else
+ height = (nNumApparentCards - 1) * -yoffset + __cardheight;
+ }
+ else
+ {
+ width = __cardwidth;
+ height = __cardheight;
+ }
+}
+
+CardRegion *CardWindow::CreateRegion(int id, bool fVisible, int x, int y, int xoffset, int yoffset)
+{
+ CardRegion *cr;
+
+ if(nNumCardRegions == MAXCARDSTACKS)
+ return FALSE;
+
+ cr = new CardRegion(*this, id, fVisible, x, y, xoffset, yoffset);
+ cr->SetBackColor(crBackgnd);
+ cr->SetBackCardIdx(nBackCardIdx);
+
+ Regions[nNumCardRegions++] = cr;
+
+ return cr;
+}
+
+int CardRegion::GetOverlapRatio(int x, int y, int w, int h)
+{
+ RECT me, him;
+ RECT inter;
+ SetRect(&him, x, y, x+w, y+h);
+ SetRect(&me, xpos, ypos, xpos+width, ypos+height);
+
+ //see if the specified rectangle overlaps us
+ if(IntersectRect(&inter, &me, &him))
+ {
+ int wi = inter.right - inter.left;
+ int hi = inter.bottom - inter.top;
+
+ int overlap = wi * hi;
+ int total = width * height;
+
+ int percent = (overlap << 16) / total;
+ return (percent * 100) >> 16;
+ }
+ //do not overlap
+ else
+ {
+ return 0;
+ }
+}
+
+bool CardRegion::SetDragRule(UINT uDragType, pCanDragProc proc)
+{
+ switch(uDragType)
+ {
+ case CS_DRAG_NONE: case CS_DRAG_ALL: case CS_DRAG_TOP:
+ uDragRule = uDragType;
+ return true;
+
+ case CS_DRAG_CALLBACK:
+ uDragRule = uDragType;
+ CanDragCallback = proc;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool CardRegion::SetDropRule(UINT uDropType, pCanDropProc proc)
+{
+ switch(uDropType)
+ {
+ case CS_DROP_NONE: case CS_DROP_ALL:
+ uDropRule = uDropType;
+ return true;
+
+ case CS_DROP_CALLBACK:
+ uDropRule = uDropType;
+ CanDropCallback = proc;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void CardRegion::SetClickProc(pClickProc proc)
+{
+ ClickCallback = proc;
+}
+
+void CardRegion::SetDblClickProc(pClickProc proc)
+{
+ DblClickCallback = proc;
+}
+
+void CardRegion::SetAddCardProc(pAddProc proc)
+{
+ AddCallback = proc;
+}
+
+void CardRegion::SetRemoveCardProc(pRemoveProc proc)
+{
+ RemoveCallback = proc;
+}
+
+void CardRegion::Update()
+{
+ CalcApparentCards();
+ UpdateSize();
+ UpdateFaceDir(cardstack);
+}
+
+
+bool CardRegion::SetThreedCount(int count)
+{
+ if(count < 1)
+ {
+ return false;
+ }
+ else
+ {
+ nThreedCount = count;
+ return true;
+ }
+}
+
+void CardRegion::SetOffsets(int x, int y)
+{
+ xoffset = x;
+ yoffset = y;
+}
+
+void CardRegion::SetPos(int x, int y)
+{
+ xpos = x;
+ ypos = y;
+}
+
+void CardRegion::Show(bool fShow)
+{
+ fVisible = fShow;
+}
+
+bool CardRegion::IsVisible()
+{
+ return fVisible;
+}
+
+void CardRegion::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust)
+{
+ xjustify = xJustify;
+ yjustify = yJustify;
+ xadjust = xAdjust;
+ yadjust = yAdjust;
+}
+
+void CardRegion::SetFaceDirection(UINT uDirType, int nOption)
+{
+ switch(uDirType)
+ {
+ case CS_FACE_UP: case CS_FACE_DOWN: case CS_FACE_DOWNUP:
+ case CS_FACE_UPDOWN: case CS_FACE_ANY:
+ uFaceDirType = uDirType;
+ nFaceDirOption = nOption;
+
+ UpdateFaceDir(cardstack);
+
+ break;
+ }
+}
+
+UINT CardRegion::GetFaceDirection(int *pnOption)
+{
+ if(pnOption)
+ *pnOption = nFaceDirOption;
+
+ return uFaceDirType;
+}
+
+void CardRegion::AdjustPosition(int winwidth, int winheight)
+{
+ Update(); //Update this stack's card count + size
+
+ switch(xjustify)
+ {
+ default: case CS_XJUST_NONE: break;
+
+ case CS_XJUST_CENTER: //centered
+ xpos = (winwidth - (width & ~0x1)) / 2;
+ xpos += xadjust;
+
+ if(xoffset < 0) xpos += (width - __cardwidth);
+
+ break;
+
+ case CS_XJUST_RIGHT: //right-aligned
+ xpos = winwidth - __cardwidth;//width - 20;
+ xpos += xadjust;
+ break;
+ }
+
+ switch(yjustify)
+ {
+ default: case CS_YJUST_NONE: break;
+
+ case CS_YJUST_CENTER: //centered
+ ypos = (winheight - height) / 2;
+ ypos += yadjust;
+ if(yoffset < 0) ypos += (height - __cardheight);
+ break;
+
+ case CS_YJUST_BOTTOM: //bottom-aligned
+ ypos = winheight - __cardheight;//height - 20;
+ ypos += yadjust;
+ break;
+ }
+
+}
+
+
+void CardRegion::Flash(int count, int milliseconds)
+{
+ if(count <= 0) return;
+
+ nFlashCount = count;
+ fFlashVisible = false;
+ uFlashTimer = SetTimer((HWND)parentWnd, (WPARAM)this, milliseconds, 0);
+
+ parentWnd.Redraw();
+}
+
+void CardRegion::StopFlash()
+{
+ if(uFlashTimer != (UINT)-1)
+ {
+ KillTimer((HWND)parentWnd, uFlashTimer);
+ nFlashCount = 0;
+ uFlashTimer = (UINT)-1;
+ fFlashVisible = true;
+ }
+}
+
+void CardRegion::DoFlash()
+{
+ if(uFlashTimer != (UINT)-1)
+ {
+ fFlashVisible = !fFlashVisible;
+
+ if(--nFlashCount == 0)
+ {
+ KillTimer((HWND)parentWnd, uFlashTimer);
+ uFlashTimer = (UINT)-1;
+ fFlashVisible = true;
+ }
+
+ parentWnd.Redraw();
+ }
+}
+
+int CardRegion::Id()
+{
+ return id;
+}
+
+void CardRegion::SetEmptyImage(UINT uImage)
+{
+ switch(uImage)
+ {
+ case CS_EI_NONE: case CS_EI_SUNK:
+ uEmptyImage = uImage;
+ break;
+
+ default:
+ uEmptyImage = CS_EI_NONE;
+ break;
+ }
+
+}
+
+void CardRegion::SetBackCardIdx(UINT uBackIdx)
+{
+ if(uBackIdx >= 52 && uBackIdx <= 68)
+ nBackCardIdx = uBackIdx;
+}
+
+void CardRegion::SetCardStack(const CardStack &cs)
+{
+ //make a complete copy of the specified stack..
+ cardstack = cs;
+
+ // Update the face-direction and stack-size
+ Update();
+}
+
+const CardStack & CardRegion::GetCardStack()
+{
+ //return reference to our internal stack
+ return cardstack;
+}
+
+//
+// Update specified card-stack using THIS stack's
+// face direction rules!
+//
+void CardRegion::UpdateFaceDir(CardStack &cards)
+{
+ int i, n, num;
+
+ num = cards.NumCards();
+
+ //Now apply the face direction rules..
+ switch(uFaceDirType)
+ {
+ case CS_FACE_UP:
+
+ for(i = 0; i < num; i++)
+ {
+ cards[i].SetFaceUp(true);
+ }
+
+ break;
+
+ case CS_FACE_DOWN:
+
+ for(i = 0; i < num; i++)
+ {
+ cards[i].SetFaceUp(false);
+ }
+
+ break;
+
+ case CS_FACE_DOWNUP:
+
+ num = cardstack.NumCards();
+ n = min(nFaceDirOption, num);
+
+ //bottom n cards..
+ for(i = 0; i < n; i++)
+ {
+ cards[num - i - 1].SetFaceUp(false);
+ }
+
+ for(i = n; i < num; i++)
+ {
+ cards[num - i - 1].SetFaceUp(true);
+ }
+
+ break;
+
+ case CS_FACE_UPDOWN:
+
+ num = cardstack.NumCards();
+ n = min(nFaceDirOption, num);
+
+ for(i = 0; i < n; i++)
+ {
+ cards[num - i - 1].SetFaceUp(true);
+ }
+
+ for(i = n; i < num; i++)
+ {
+ cards[num - i - 1].SetFaceUp(false);
+ }
+
+ break;
+
+ case CS_FACE_ANY: //cards can be any orientation
+ default:
+ break;
+ }
+}
+
+bool CardRegion::MoveCard(CardRegion *pDestStack, int nNumCards, bool fAnimate)
+{
+ HDC hdc;
+
+ int x, y;
+
+ if(pDestStack == 0) return false; //{ forcedfacedir = -1 ;return 0; }
+
+ if(nNumCards < 0 || nNumCards > cardstack.NumCards())
+ return false;
+
+ x = xpos + xoffset * (nNumApparentCards - nNumCards);
+ y = ypos + yoffset * (nNumApparentCards - nNumCards);
+
+ oldx = x;
+ oldy = y;
+
+ dragstack = cardstack.Pop(nNumCards);
+
+ //Alter the drag-stack so that it's cards are the same way up
+ //as the destination. Use the destination's drag-rules
+ //instead of this ones!!
+ CardStack temp;
+ temp.Push(pDestStack->GetCardStack());
+ temp.Push(dragstack);
+
+ pDestStack->UpdateFaceDir(temp);
+
+ dragstack = temp.Pop(nNumCards);
+
+ if(fAnimate)
+ {
+ iNumDragCards = nNumCards;
+ PrepareDragBitmaps(nNumCards);
+ }
+
+ Update(); //Update this stack's size+card count
+
+ if(fAnimate)
+ {
+ hdc = GetDC((HWND)parentWnd);
+
+ ZoomCard(hdc, x, y, pDestStack);
+
+ ReleaseDC((HWND)parentWnd, hdc);
+ ReleaseDragBitmaps();
+ }
+
+ // Get a copy of the cardstack
+ CardStack cs = pDestStack->GetCardStack();
+ cs.Push(dragstack);
+
+ pDestStack->SetCardStack(cs);
+
+ //cs = pDestStack->GetCardStack();
+ //pDestStack->Update();
+ //pDestStack->UpdateFaceDir(cs);
+
+ RedrawIfNotDim(pDestStack, false);
+
+ //forcedfacedir = -1;
+ return true;
+}
+
+//
+// Simple wrappers
+//
+int CardRegion::NumCards() const
+{
+ if(fMouseDragging)
+ return cardstack.NumCards() + dragstack.NumCards();
+ else
+ return cardstack.NumCards();
+}
+
+bool CardRegion::Lock()
+{
+ DWORD dw = WaitForSingleObject(mxlock, 0);
+
+ if(dw == WAIT_OBJECT_0)
+ {
+ //TRACE("LockStack succeeded\n");
+ return true;
+ }
+ else
+ {
+ //TRACE("LockStack failed\n");
+ return false;
+ }
+ return false;
+}
+
+bool CardRegion::UnLock()
+{
+ if(ReleaseMutex(mxlock))
+ {
+ //TRACE("Unlocking stack\n");
+ return true;
+ }
+ else
+ {
+ //TRACE("Unlocking stack failed\n");
+ return false;
+ }
+}
+
+bool CardRegion::PlayCard(CardRegion *pDestStack, int value, int num)
+{
+ //search the stack for the specified card value...
+ while(num--)
+ {
+ for(int i = 0; i < cardstack.NumCards(); i++)
+ {
+ if(cardstack[i].HiVal() == value)
+ {
+ //swap the card with one at top pos...
+ Card card = cardstack.RemoveCard(i);
+ cardstack.Push(card);
+
+ Redraw();
+
+ MoveCard(pDestStack, 1, true);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// Redraw the current stack if it has a different
+// layout than the comparison stack.
+//
+void CardRegion::RedrawIfNotDim(CardRegion *pCompare, bool fFullRedraw)
+{
+ //
+ //
+ //
+ if( pCompare->xoffset != xoffset ||
+ pCompare->yoffset != yoffset ||
+ pCompare->nThreedCount != nThreedCount ||
+ pCompare->uFaceDirType != uFaceDirType ||
+ pCompare->uFaceDirType != CS_FACE_ANY
+ )
+ {
+ if(fFullRedraw)
+ parentWnd.Redraw();
+ else
+ pCompare->Redraw();
+ }
+
+}
+
+//
+// SimulateDrag mimicks the complete drag+drop process.
+// It basically just a MoveCard(..), but it calls the
+// event callbacks as well.
+//
+bool CardRegion::SimulateDrag(CardRegion *pDestStack, int iNumDragCards, bool fAnimate)
+{
+ if(pDestStack == 0)
+ return false;
+
+ if(CanDragCards(iNumDragCards) != false)
+ {
+ //make a list of the cards that would be in the drag list
+ CardStack tempstack = cardstack.Top(iNumDragCards);
+
+ if(pDestStack->CanDropCards(tempstack))
+ {
+ MoveCard(pDestStack, iNumDragCards, fAnimate);
+
+ if(RemoveCallback)
+ RemoveCallback(*this, iNumDragCards);
+
+ if(pDestStack->AddCallback)
+ pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);
+
+ RedrawIfNotDim(pDestStack, true);
+ }
+
+ }
+
+ return true;
+}