-//\r
-// CardLib - CardRegion mouse-related stuff\r
-//\r
-// Freeware\r
-// Copyright J Brown 2001\r
-//\r
-#include <windows.h>\r
-#include <math.h>\r
-#include <stdio.h>\r
-\r
-#include "cardlib.h"\r
-#include "cardwindow.h"\r
-#include "cardregion.h"\r
-\r
-#if 1\r
-#define TRACE(s)\r
-#else\r
-#define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)\r
-#endif\r
-\r
-double __CARDZOOMSPEED = 32;\r
-\r
-int ClipCard(HDC hdc, int x, int y, int width, int height);\r
-void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height);\r
-\r
-#ifdef _DEBUG\r
-\r
-static pDebugClickProc DebugStackClickProc = 0;\r
-\r
-void CardLib_SetStackClickProc(pDebugClickProc proc)\r
-{\r
- DebugStackClickProc = proc;\r
-}\r
-\r
-#endif\r
-\r
-CardRegion *CardWindow::GetBestStack(int x, int y, int w, int h)\r
-{\r
- int maxoverlap = 0;\r
- int maxoverlapidx = -1;\r
-\r
- //find the stack which is most covered by the dropped\r
- //cards. Only include those which allow drops.\r
- //\r
- for(int i = 0; i < nNumCardRegions; i++)\r
- {\r
- int percent = Regions[i]->GetOverlapRatio(x, y, w, h);\r
-\r
- //if this stack has the biggest coverage yet\r
- if(percent > maxoverlap && Regions[i]->IsVisible())\r
- {\r
- maxoverlap = percent;\r
- maxoverlapidx = i;\r
- }\r
- }\r
- \r
- //if we found a stack to drop onto\r
- if(maxoverlapidx != -1)\r
- {\r
- return Regions[maxoverlapidx];\r
- }\r
- else\r
- {\r
- return 0;\r
- }\r
-}\r
-\r
-bool CardRegion::IsPointInStack(int x, int y)\r
-{\r
- int axpos = xoffset < 0 ? xpos + (nNumApparentCards-1)*xoffset : xpos;\r
- int aypos = yoffset < 0 ? ypos + (nNumApparentCards-1)*yoffset : ypos;\r
- \r
- if(x >= axpos && x < axpos + width && y >= aypos && y < aypos + height && fVisible)\r
- return true;\r
- else\r
- return false;\r
-}\r
-\r
-int CardRegion::GetNumDragCards(int x, int y)\r
-{\r
- int cardindex = 0; //index from stack start\r
- int maxidx;\r
-\r
- //make x,y relative to the stack's upper left corner\r
- x -= xpos + (xoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * xoffset : 0);\r
- y -= ypos + (yoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * yoffset : 0);\r
- \r
- //if stack is empty, cannot drag any cards from it\r
- if(cardstack.NumCards() <= 0)\r
- return 0;\r
-\r
- //see which card in the stack has been clicked on\r
- //top-bottom ordering\r
- if(yoffset > 0)\r
- {\r
- if(y < height - __cardheight)\r
- cardindex = y / yoffset;\r
- else\r
- cardindex = cardstack.NumCards() - 1;\r
- }\r
- else if(yoffset < 0)\r
- {\r
- if(y < __cardheight)\r
- cardindex = cardstack.NumCards() - 1;\r
- else\r
- cardindex = cardstack.NumCards() - ((y - __cardheight) / -yoffset) - 2;\r
- }\r
- else //yoffset == 0\r
- {\r
- cardindex = cardstack.NumCards() - 1;\r
- }\r
-\r
- maxidx = cardindex;\r
-\r
- //if left-right\r
- if(xoffset > 0)\r
- {\r
- if(x < width - __cardwidth)\r
- cardindex = x / xoffset;\r
- else\r
- cardindex = cardstack.NumCards() - 1;\r
- }\r
- else if(xoffset < 0)\r
- {\r
- if(x < __cardwidth)\r
- cardindex = cardstack.NumCards() - 1;\r
- else\r
- cardindex = cardstack.NumCards() - ((x - __cardwidth) / -xoffset) - 2;\r
- }\r
- else\r
- {\r
- cardindex = cardstack.NumCards() - 1;\r
- }\r
-\r
- if(cardindex > maxidx) cardindex = maxidx;\r
-\r
- if(cardindex > cardstack.NumCards())\r
- cardindex = 1;\r
-\r
- //if are trying to drag too many cards at once\r
- return cardstack.NumCards() - cardindex;\r
-}\r
-\r
-bool CardRegion::CanDragCards(int iNumCards)\r
-{\r
- if(iNumCards <= 0) return false;\r
- if(nThreedCount > 1 && iNumCards > 1) return false;\r
-\r
- if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)\r
- {\r
-// TRACE("Failed to gain access to card stack\n");\r
- return false;\r
- }\r
-\r
- ReleaseMutex(mxlock);\r
-\r
- switch(uDragRule)\r
- {\r
- case CS_DRAG_ALL:\r
- return true;\r
- \r
- case CS_DRAG_TOP:\r
-\r
- if(iNumCards == 1)\r
- return true;\r
- else\r
- return false;\r
- \r
- case CS_DRAG_NONE:\r
- return false;\r
- \r
- case CS_DRAG_CALLBACK:\r
- \r
- if(CanDragCallback)\r
- {\r
- return CanDragCallback(*this, iNumCards);\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
- \r
- default:\r
- return false;\r
- }\r
-}\r
-\r
-bool CardRegion::CanDropCards(CardStack &cards)\r
-{\r
- if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)\r
- {\r
- return false;\r
- }\r
-\r
- ReleaseMutex(mxlock);\r
-\r
- switch(uDropRule)\r
- {\r
- case CS_DROP_ALL:\r
- return true;\r
-\r
- case CS_DROP_NONE:\r
- return false;\r
-\r
- case CS_DROP_CALLBACK:\r
- \r
- if(CanDropCallback)\r
- {\r
- return CanDropCallback(*this, cards);\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-\r
- default:\r
- return false;\r
- }\r
-}\r
-\r
-bool CardRegion::OnLButtonDblClk(int x, int y)\r
-{\r
- iNumDragCards = GetNumDragCards(x, y); \r
-\r
- if(DblClickCallback)\r
- DblClickCallback(*this, iNumDragCards);\r
-\r
- return true;\r
-}\r
-\r
-bool CardRegion::OnLButtonDown(int x, int y)\r
-{\r
- iNumDragCards = GetNumDragCards(x, y); \r
-\r
-#ifdef _DEBUG\r
- if(DebugStackClickProc)\r
- {\r
- if(!DebugStackClickProc(*this))\r
- return false;\r
- }\r
-#endif\r
-\r
- if(ClickCallback)\r
- ClickCallback(*this, iNumDragCards);\r
-\r
- if(CanDragCards(iNumDragCards) != false)\r
- {\r
-\r
- //offset of the mouse cursor relative to the top-left corner\r
- //of the cards that are being dragged\r
- mousexoffset = x - xpos - xoffset * (nNumApparentCards - iNumDragCards);\r
- mouseyoffset = y - ypos - yoffset * (nNumApparentCards - iNumDragCards);\r
- \r
- if(xoffset < 0)\r
- mousexoffset += -xoffset * (iNumDragCards - 1);\r
-\r
- if(yoffset < 0)\r
- mouseyoffset += -yoffset * (iNumDragCards - 1);\r
- \r
- //remove the cards from the source stack\r
- dragstack = cardstack.Pop(iNumDragCards);\r
-\r
- //prepare the back buffer, and the drag image\r
- PrepareDragBitmaps(iNumDragCards);\r
-\r
- oldx = x - mousexoffset;\r
- oldy = y - mouseyoffset;\r
- \r
- Update(); //Update this stack's card count + size\r
-\r
- SetCapture((HWND)parentWnd);\r
-\r
- //set AFTER settings the dragstack...\r
- fMouseDragging = true;\r
-\r
- return true;\r
- }\r
-\r
- return false;\r
-}\r
-\r
-bool CardRegion::OnLButtonUp(int x, int y)\r
-{\r
- CardRegion *pDestStack = 0;\r
- HDC hdc;\r
- int dropstackid = CS_DROPZONE_NODROP;\r
- \r
- RECT dragrect;\r
- DropZone *dropzone;\r
-\r
- fMouseDragging = false;\r
-\r
- //first of all, see if any drop zones have been registered\r
- SetRect(&dragrect, x-mousexoffset, y-mouseyoffset, x-mousexoffset+nDragCardWidth, y-mouseyoffset+nDragCardHeight);\r
-\r
- dropzone = parentWnd.GetDropZoneFromRect(&dragrect);\r
-\r
- if(dropzone)\r
- {\r
- dropstackid = dropzone->DropCards(dragstack);\r
- \r
- if(dropstackid != CS_DROPZONE_NODROP)\r
- pDestStack = parentWnd.CardRegionFromId(dropstackid);\r
- else\r
- pDestStack = 0;\r
- }\r
- else\r
- {\r
- pDestStack = parentWnd.GetBestStack(x - mousexoffset, y - mouseyoffset, nDragCardWidth, nDragCardHeight);\r
- }\r
- \r
- // If have found a stack to drop onto\r
- //\r
- TRACE ( "can I drop card?\n" );\r
- if(pDestStack && pDestStack->CanDropCards(dragstack)) \r
- {\r
- TRACE ( "yes, dropping card\n" );\r
- hdc = GetDC((HWND)parentWnd);\r
- // UseNicePalette(hdc);\r
- ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, pDestStack);\r
- ReleaseDC((HWND)parentWnd, hdc);\r
- \r
- //\r
- //add the cards to the destination stack\r
- //\r
- CardStack temp = pDestStack->GetCardStack();\r
- temp.Push(dragstack);\r
- \r
- pDestStack->SetCardStack(temp);\r
-// pDestStack->Update(); //Update this stack's card count + size\r
-// pDestStack->UpdateFaceDir(temp);\r
- \r
- // Call the remove callback on THIS stack, if one is specified\r
- //\r
- if(RemoveCallback)\r
- RemoveCallback(*this, iNumDragCards);\r
-\r
- // Call the add callback, if one is specified\r
- //\r
- if(pDestStack->AddCallback)\r
- pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);//index, deststack->numcards);\r
- \r
- RedrawIfNotDim(pDestStack, true);\r
- TRACE ( "done dropping card\n" );\r
- }\r
-\r
- //\r
- // Otherwise, let the cards snap back onto this stack\r
- //\r
- else\r
- {\r
- TRACE ( "no, putting card back\n" );\r
- hdc = GetDC((HWND)parentWnd);\r
- TRACE ( "calling ZoomCard()\n" );\r
- ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this);\r
- TRACE ( "cardstack += dragstack\n" );\r
- cardstack += dragstack;\r
- TRACE ( "calling ReleaseDC()\n" );\r
- ReleaseDC((HWND)parentWnd, hdc);\r
-\r
- TRACE ( "calling Update()\n" );\r
- Update(); //Update this stack's card count + size\r
- TRACE ( "done putting card back\n" );\r
- }\r
- \r
- ReleaseDragBitmaps();\r
- ReleaseCapture();\r
- \r
- TRACE ( "OnLButtonUp() done\n" );\r
- return true;\r
-}\r
-\r
-bool CardRegion::OnMouseMove(int x, int y)\r
-{\r
- HDC hdc;\r
-\r
- hdc = GetDC((HWND)parentWnd);\r
- \r
- x -= mousexoffset;\r
- y -= mouseyoffset;\r
- \r
- MoveDragCardTo(hdc, x, y);\r
-\r
- //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);\r
- //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY);\r
- \r
- ReleaseDC((HWND)parentWnd, hdc);\r
- \r
- oldx = x;\r
- oldy = y;\r
- \r
- return true;\r
-}\r
-\r
-//\r
-// There is a bug in BitBlt when the source x,y\r
-// become < 0. So this wrapper function simply adjusts\r
-// the coords so that we never try to blt in from this range\r
-//\r
-BOOL ClippedBitBlt(HDC hdcDest, int x, int y, int width, int height, HDC hdcSrc, int srcx, int srcy, DWORD dwROP)\r
-{\r
- if(srcx < 0)\r
- {\r
- x = 0 - srcx;\r
- width = width + srcx;\r
- srcx = 0;\r
- }\r
-\r
- if(srcy < 0)\r
- {\r
- y = 0 - srcy;\r
- height = height + srcy;\r
- srcy = 0;\r
- }\r
-\r
- return BitBlt(hdcDest, x, y, width, height, hdcSrc, srcx, srcy, dwROP);\r
-}\r
-\r
-void CardRegion::MoveDragCardTo(HDC hdc, int x, int y)\r
-{\r
- RECT inter, rect1, rect2;\r
-\r
- //mask off the new position of the drag-card, so\r
- //that it will not be painted over\r
- ClipCard(hdc, x, y, nDragCardWidth, nDragCardHeight);\r
- \r
- //restore the area covered by the card at its previous position\r
- BitBlt(hdc, oldx, oldy, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);\r
-\r
- //remove clipping so we can draw the card at its new place\r
- SelectClipRgn(hdc, NULL);\r
- \r
- //if the card's old and new positions overlap, then we\r
- //need some funky code to update the "saved background" image,\r
- SetRect(&rect1, oldx, oldy, oldx+nDragCardWidth, oldy+nDragCardHeight);\r
- SetRect(&rect2, x, y, x+nDragCardWidth, y+nDragCardHeight);\r
- \r
- if(IntersectRect(&inter, &rect1, &rect2))\r
- {\r
- int interwidth = inter.right-inter.left;\r
- int interheight = inter.bottom-inter.top;\r
- int destx, desty, srcx, srcy;\r
- \r
- if(rect2.left > rect1.left) \r
- { \r
- destx = 0; srcx = nDragCardWidth - interwidth; \r
- }\r
- else\r
- {\r
- destx = nDragCardWidth - interwidth; srcx = 0;\r
- }\r
- \r
- if(rect2.top > rect1.top) \r
- {\r
- desty = 0; srcy = nDragCardHeight - interheight;\r
- }\r
- else \r
- {\r
- desty = nDragCardHeight - interheight; srcy = 0;\r
- }\r
- \r
- //shift the bit we didn't use for the restore (due to the clipping)\r
- //into the opposite corner\r
- BitBlt(hdcBackGnd, destx,desty, interwidth, interheight, hdcBackGnd, srcx, srcy, SRCCOPY);\r
- \r
- ExcludeClipRect(hdcBackGnd, destx, desty, destx+interwidth, desty+interheight);\r
- \r
- //this bit requires us to clip the BitBlt (from screen to background)\r
- //as BitBlt is a bit buggy it seems\r
- ClippedBitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY);\r
- SelectClipRgn(hdcBackGnd, NULL);\r
- }\r
- else\r
- {\r
- BitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY);\r
- }\r
- \r
- //finally draw the card to the screen\r
- DrawCard(hdc, x, y, hdcDragCard, nDragCardWidth, nDragCardHeight);\r
-}\r
-\r
-\r
-//extern "C" int _fltused(void) { return 0; }\r
-//extern "C" int _ftol(void) { return 0; }\r
-\r
-//\r
-// Better do this in fixed-point, to stop\r
-// VC from linking in floatingpoint-long conversions\r
-//\r
-//#define FIXED_PREC_MOVE\r
-#ifdef FIXED_PREC_MOVE\r
-#define PRECISION 12\r
-void ZoomCard(HDC hdc, int xpos, int ypos, CARDSTACK *dest)\r
-{\r
- long dx, dy, x , y;\r
-\r
- \r
- int apparentcards;\r
- x = xpos << PRECISION; y = ypos << PRECISION;\r
-\r
- oldx = (int)xpos;\r
- oldy = (int)ypos;\r
-\r
- apparentcards=dest->numcards/dest->threedcount;\r
-\r
- int idestx = dest->xpos + dest->xoffset * (apparentcards);// - iNumDragCards); \r
- int idesty = dest->ypos + dest->yoffset * (apparentcards);// - iNumDragCards);\r
-\r
- //normalise the motion vector\r
- dx = (idestx<<PRECISION) - x;\r
- dy = (idesty<<PRECISION) - y;\r
- long recip = (1 << PRECISION) / 1;//sqrt(dx*dx + dy*dy);\r
-\r
- dx *= recip * 16;//CARDZOOMSPEED; \r
- dy *= recip * 16;//CARDZOOMSPEED;\r
-\r
- //if(dx < 0) dxinc = 1.001; else\r
-\r
- for(;;)\r
- {\r
- int ix, iy;\r
- x += dx;\r
- y += dy;\r
-\r
- ix = (int)x>>PRECISION;\r
- iy = (int)y>>PRECISION;\r
- if(dx < 0 && ix < idestx) ix = idestx;\r
- else if(dx > 0 && ix > idestx) ix = idestx;\r
-\r
- if(dy < 0 && iy < idesty) iy = idesty;\r
- else if(dy > 0 && iy > idesty) iy = idesty;\r
-\r
- MoveDragCardTo(hdc, ix, iy);\r
-\r
- if(ix == idestx && iy == idesty)\r
- break;\r
-\r
- oldx = (int)x >> PRECISION;\r
- oldy = (int)y >> PRECISION;\r
-\r
- //dx *= 1.2;\r
- //dy *= 1.2;\r
-\r
- Sleep(10);\r
- }\r
-}\r
-#else\r
-void CardRegion::ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *pDestStack)\r
-{\r
- TRACE ( "ENTER ZoomCard()\n" );\r
- double dx, dy, x ,y;\r
- int apparentcards;\r
- x = (double)xpos; y = (double)ypos;\r
-\r
- oldx = (int)x;\r
- oldy = (int)y;\r
-\r
- apparentcards = pDestStack->cardstack.NumCards() / pDestStack->nThreedCount;\r
-\r
- int idestx = pDestStack->xpos + pDestStack->xoffset * (apparentcards);\r
- int idesty = pDestStack->ypos + pDestStack->yoffset * (apparentcards);\r
-\r
- if(pDestStack->yoffset < 0)\r
- idesty += pDestStack->yoffset * (iNumDragCards-1);\r
-\r
- if(pDestStack->xoffset < 0)\r
- idestx += pDestStack->xoffset * (iNumDragCards-1);\r
-\r
- //normalise the motion vector\r
- dx = idestx - x;\r
- dy = idesty - y;\r
- if ( fabs(dx) + fabs(dy) < 0.001f )\r
- {\r
- MoveDragCardTo(hdc, idestx, idesty);\r
- return;\r
- }\r
- double recip = 1.0 / sqrt(dx*dx + dy*dy);\r
- dx *= recip * __CARDZOOMSPEED; dy *= recip * __CARDZOOMSPEED;\r
-\r
- //if(dx < 0) dxinc = 1.001; else\r
-\r
- for(;;)\r
- {\r
- bool attarget = true;\r
- int ix, iy;\r
- x += dx;\r
- y += dy;\r
-\r
- ix = (int)x;\r
- iy = (int)y;\r
-\r
- if(dx < 0.0 && ix < idestx) ix = idestx;\r
- else if(dx > 0.0 && ix > idestx) ix = idestx;\r
- else attarget = false;\r
-\r
- if(dy < 0.0 && iy < idesty) iy = idesty;\r
- else if(dy > 0.0 && iy > idesty) iy = idesty;\r
- else attarget = false;\r
-\r
- //if the target stack wants the drag cards drawn differently\r
- //to how they are, then redraw the drag card image just before\r
- //the cards land\r
- /*if(attarget == true)\r
- {\r
- for(int i = 0; i < iNumDragCards; i++)\r
- {\r
- int xdraw = pDestStack->xoffset*i;\r
- int ydraw = pDestStack->yoffset*i;\r
-\r
- if(pDestStack->yoffset < 0)\r
- ydraw = -pDestStack->yoffset * (iNumDragCards-i-1);\r
- if(pDestStack->xoffset < 0)\r
- xdraw = -pDestStack->xoffset * (iNumDragCards-i-1);\r
-\r
- if(pDestStack->facedirection == CS_FACEUP && \r
- pDestStack->numcards+i >= dest->numfacedown)\r
- {\r
- //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0);\r
- }\r
- else\r
- {\r
- //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0);\r
- }\r
- }\r
- }*/\r
-\r
- MoveDragCardTo(hdc, ix, iy);\r
-\r
- if(attarget || ix == idestx && iy == idesty)\r
- break;\r
-\r
- oldx = (int)x;\r
- oldy = (int)y;\r
-\r
- //dx *= 1.2;\r
- //dy *= 1.2;\r
-\r
- Sleep(10);\r
- }\r
- TRACE ( "EXIT ZoomCard()\n" );\r
-}\r
-#endif\r
+//
+// CardLib - CardRegion mouse-related stuff
+//
+// Freeware
+// Copyright J Brown 2001
+//
+#include <windows.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "cardlib.h"
+#include "cardwindow.h"
+#include "cardregion.h"
+
+#if 1
+#define TRACE(s)
+#else
+#define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
+#endif
+
+double __CARDZOOMSPEED = 32;
+
+int ClipCard(HDC hdc, int x, int y, int width, int height);
+void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height);
+
+#ifdef _DEBUG
+
+static pDebugClickProc DebugStackClickProc = 0;
+
+void CardLib_SetStackClickProc(pDebugClickProc proc)
+{
+ DebugStackClickProc = proc;
+}
+
+#endif
+
+CardRegion *CardWindow::GetBestStack(int x, int y, int w, int h)
+{
+ int maxoverlap = 0;
+ int maxoverlapidx = -1;
+
+ //find the stack which is most covered by the dropped
+ //cards. Only include those which allow drops.
+ //
+ for(int i = 0; i < nNumCardRegions; i++)
+ {
+ int percent = Regions[i]->GetOverlapRatio(x, y, w, h);
+
+ //if this stack has the biggest coverage yet
+ if(percent > maxoverlap && Regions[i]->IsVisible())
+ {
+ maxoverlap = percent;
+ maxoverlapidx = i;
+ }
+ }
+
+ //if we found a stack to drop onto
+ if(maxoverlapidx != -1)
+ {
+ return Regions[maxoverlapidx];
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+bool CardRegion::IsPointInStack(int x, int y)
+{
+ int axpos = xoffset < 0 ? xpos + (nNumApparentCards-1)*xoffset : xpos;
+ int aypos = yoffset < 0 ? ypos + (nNumApparentCards-1)*yoffset : ypos;
+
+ if(x >= axpos && x < axpos + width && y >= aypos && y < aypos + height && fVisible)
+ return true;
+ else
+ return false;
+}
+
+int CardRegion::GetNumDragCards(int x, int y)
+{
+ int cardindex = 0; //index from stack start
+ int maxidx;
+
+ //make x,y relative to the stack's upper left corner
+ x -= xpos + (xoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * xoffset : 0);
+ y -= ypos + (yoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * yoffset : 0);
+
+ //if stack is empty, cannot drag any cards from it
+ if(cardstack.NumCards() <= 0)
+ return 0;
+
+ //see which card in the stack has been clicked on
+ //top-bottom ordering
+ if(yoffset > 0)
+ {
+ if(y < height - __cardheight)
+ cardindex = y / yoffset;
+ else
+ cardindex = cardstack.NumCards() - 1;
+ }
+ else if(yoffset < 0)
+ {
+ if(y < __cardheight)
+ cardindex = cardstack.NumCards() - 1;
+ else
+ cardindex = cardstack.NumCards() - ((y - __cardheight) / -yoffset) - 2;
+ }
+ else //yoffset == 0
+ {
+ cardindex = cardstack.NumCards() - 1;
+ }
+
+ maxidx = cardindex;
+
+ //if left-right
+ if(xoffset > 0)
+ {
+ if(x < width - __cardwidth)
+ cardindex = x / xoffset;
+ else
+ cardindex = cardstack.NumCards() - 1;
+ }
+ else if(xoffset < 0)
+ {
+ if(x < __cardwidth)
+ cardindex = cardstack.NumCards() - 1;
+ else
+ cardindex = cardstack.NumCards() - ((x - __cardwidth) / -xoffset) - 2;
+ }
+ else
+ {
+ cardindex = cardstack.NumCards() - 1;
+ }
+
+ if(cardindex > maxidx) cardindex = maxidx;
+
+ if(cardindex > cardstack.NumCards())
+ cardindex = 1;
+
+ //if are trying to drag too many cards at once
+ return cardstack.NumCards() - cardindex;
+}
+
+bool CardRegion::CanDragCards(int iNumCards)
+{
+ if(iNumCards <= 0) return false;
+ if(nThreedCount > 1 && iNumCards > 1) return false;
+
+ if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)
+ {
+// TRACE("Failed to gain access to card stack\n");
+ return false;
+ }
+
+ ReleaseMutex(mxlock);
+
+ switch(uDragRule)
+ {
+ case CS_DRAG_ALL:
+ return true;
+
+ case CS_DRAG_TOP:
+
+ if(iNumCards == 1)
+ return true;
+ else
+ return false;
+
+ case CS_DRAG_NONE:
+ return false;
+
+ case CS_DRAG_CALLBACK:
+
+ if(CanDragCallback)
+ {
+ return CanDragCallback(*this, iNumCards);
+ }
+ else
+ {
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+bool CardRegion::CanDropCards(CardStack &cards)
+{
+ if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)
+ {
+ return false;
+ }
+
+ ReleaseMutex(mxlock);
+
+ switch(uDropRule)
+ {
+ case CS_DROP_ALL:
+ return true;
+
+ case CS_DROP_NONE:
+ return false;
+
+ case CS_DROP_CALLBACK:
+
+ if(CanDropCallback)
+ {
+ return CanDropCallback(*this, cards);
+ }
+ else
+ {
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+bool CardRegion::OnLButtonDblClk(int x, int y)
+{
+ iNumDragCards = GetNumDragCards(x, y);
+
+ if(DblClickCallback)
+ DblClickCallback(*this, iNumDragCards);
+
+ return true;
+}
+
+bool CardRegion::OnLButtonDown(int x, int y)
+{
+ iNumDragCards = GetNumDragCards(x, y);
+
+#ifdef _DEBUG
+ if(DebugStackClickProc)
+ {
+ if(!DebugStackClickProc(*this))
+ return false;
+ }
+#endif
+
+ if(ClickCallback)
+ ClickCallback(*this, iNumDragCards);
+
+ if(CanDragCards(iNumDragCards) != false)
+ {
+
+ //offset of the mouse cursor relative to the top-left corner
+ //of the cards that are being dragged
+ mousexoffset = x - xpos - xoffset * (nNumApparentCards - iNumDragCards);
+ mouseyoffset = y - ypos - yoffset * (nNumApparentCards - iNumDragCards);
+
+ if(xoffset < 0)
+ mousexoffset += -xoffset * (iNumDragCards - 1);
+
+ if(yoffset < 0)
+ mouseyoffset += -yoffset * (iNumDragCards - 1);
+
+ //remove the cards from the source stack
+ dragstack = cardstack.Pop(iNumDragCards);
+
+ //prepare the back buffer, and the drag image
+ PrepareDragBitmaps(iNumDragCards);
+
+ oldx = x - mousexoffset;
+ oldy = y - mouseyoffset;
+
+ Update(); //Update this stack's card count + size
+
+ SetCapture((HWND)parentWnd);
+
+ //set AFTER settings the dragstack...
+ fMouseDragging = true;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool CardRegion::OnLButtonUp(int x, int y)
+{
+ CardRegion *pDestStack = 0;
+ HDC hdc;
+ int dropstackid = CS_DROPZONE_NODROP;
+
+ RECT dragrect;
+ DropZone *dropzone;
+
+ fMouseDragging = false;
+
+ //first of all, see if any drop zones have been registered
+ SetRect(&dragrect, x-mousexoffset, y-mouseyoffset, x-mousexoffset+nDragCardWidth, y-mouseyoffset+nDragCardHeight);
+
+ dropzone = parentWnd.GetDropZoneFromRect(&dragrect);
+
+ if(dropzone)
+ {
+ dropstackid = dropzone->DropCards(dragstack);
+
+ if(dropstackid != CS_DROPZONE_NODROP)
+ pDestStack = parentWnd.CardRegionFromId(dropstackid);
+ else
+ pDestStack = 0;
+ }
+ else
+ {
+ pDestStack = parentWnd.GetBestStack(x - mousexoffset, y - mouseyoffset, nDragCardWidth, nDragCardHeight);
+ }
+
+ // If have found a stack to drop onto
+ //
+ TRACE ( "can I drop card?\n" );
+ if(pDestStack && pDestStack->CanDropCards(dragstack))
+ {
+ TRACE ( "yes, dropping card\n" );
+ hdc = GetDC((HWND)parentWnd);
+ // UseNicePalette(hdc);
+ ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, pDestStack);
+ ReleaseDC((HWND)parentWnd, hdc);
+
+ //
+ //add the cards to the destination stack
+ //
+ CardStack temp = pDestStack->GetCardStack();
+ temp.Push(dragstack);
+
+ pDestStack->SetCardStack(temp);
+// pDestStack->Update(); //Update this stack's card count + size
+// pDestStack->UpdateFaceDir(temp);
+
+ // Call the remove callback on THIS stack, if one is specified
+ //
+ if(RemoveCallback)
+ RemoveCallback(*this, iNumDragCards);
+
+ // Call the add callback, if one is specified
+ //
+ if(pDestStack->AddCallback)
+ pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);//index, deststack->numcards);
+
+ RedrawIfNotDim(pDestStack, true);
+ TRACE ( "done dropping card\n" );
+ }
+
+ //
+ // Otherwise, let the cards snap back onto this stack
+ //
+ else
+ {
+ TRACE ( "no, putting card back\n" );
+ hdc = GetDC((HWND)parentWnd);
+ TRACE ( "calling ZoomCard()\n" );
+ ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this);
+ TRACE ( "cardstack += dragstack\n" );
+ cardstack += dragstack;
+ TRACE ( "calling ReleaseDC()\n" );
+ ReleaseDC((HWND)parentWnd, hdc);
+
+ TRACE ( "calling Update()\n" );
+ Update(); //Update this stack's card count + size
+ TRACE ( "done putting card back\n" );
+ }
+
+ ReleaseDragBitmaps();
+ ReleaseCapture();
+
+ TRACE ( "OnLButtonUp() done\n" );
+ return true;
+}
+
+bool CardRegion::OnMouseMove(int x, int y)
+{
+ HDC hdc;
+
+ hdc = GetDC((HWND)parentWnd);
+
+ x -= mousexoffset;
+ y -= mouseyoffset;
+
+ MoveDragCardTo(hdc, x, y);
+
+ //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);
+ //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY);
+
+ ReleaseDC((HWND)parentWnd, hdc);
+
+ oldx = x;
+ oldy = y;
+
+ return true;
+}
+
+//
+// There is a bug in BitBlt when the source x,y
+// become < 0. So this wrapper function simply adjusts
+// the coords so that we never try to blt in from this range
+//
+BOOL ClippedBitBlt(HDC hdcDest, int x, int y, int width, int height, HDC hdcSrc, int srcx, int srcy, DWORD dwROP)
+{
+ if(srcx < 0)
+ {
+ x = 0 - srcx;
+ width = width + srcx;
+ srcx = 0;
+ }
+
+ if(srcy < 0)
+ {
+ y = 0 - srcy;
+ height = height + srcy;
+ srcy = 0;
+ }
+
+ return BitBlt(hdcDest, x, y, width, height, hdcSrc, srcx, srcy, dwROP);
+}
+
+void CardRegion::MoveDragCardTo(HDC hdc, int x, int y)
+{
+ RECT inter, rect1, rect2;
+
+ //mask off the new position of the drag-card, so
+ //that it will not be painted over
+ ClipCard(hdc, x, y, nDragCardWidth, nDragCardHeight);
+
+ //restore the area covered by the card at its previous position
+ BitBlt(hdc, oldx, oldy, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);
+
+ //remove clipping so we can draw the card at its new place
+ SelectClipRgn(hdc, NULL);
+
+ //if the card's old and new positions overlap, then we
+ //need some funky code to update the "saved background" image,
+ SetRect(&rect1, oldx, oldy, oldx+nDragCardWidth, oldy+nDragCardHeight);
+ SetRect(&rect2, x, y, x+nDragCardWidth, y+nDragCardHeight);
+
+ if(IntersectRect(&inter, &rect1, &rect2))
+ {
+ int interwidth = inter.right-inter.left;
+ int interheight = inter.bottom-inter.top;
+ int destx, desty, srcx, srcy;
+
+ if(rect2.left > rect1.left)
+ {
+ destx = 0; srcx = nDragCardWidth - interwidth;
+ }
+ else
+ {
+ destx = nDragCardWidth - interwidth; srcx = 0;
+ }
+
+ if(rect2.top > rect1.top)
+ {
+ desty = 0; srcy = nDragCardHeight - interheight;
+ }
+ else
+ {
+ desty = nDragCardHeight - interheight; srcy = 0;
+ }
+
+ //shift the bit we didn't use for the restore (due to the clipping)
+ //into the opposite corner
+ BitBlt(hdcBackGnd, destx,desty, interwidth, interheight, hdcBackGnd, srcx, srcy, SRCCOPY);
+
+ ExcludeClipRect(hdcBackGnd, destx, desty, destx+interwidth, desty+interheight);
+
+ //this bit requires us to clip the BitBlt (from screen to background)
+ //as BitBlt is a bit buggy it seems
+ ClippedBitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY);
+ SelectClipRgn(hdcBackGnd, NULL);
+ }
+ else
+ {
+ BitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY);
+ }
+
+ //finally draw the card to the screen
+ DrawCard(hdc, x, y, hdcDragCard, nDragCardWidth, nDragCardHeight);
+}
+
+
+//extern "C" int _fltused(void) { return 0; }
+//extern "C" int _ftol(void) { return 0; }
+
+//
+// Better do this in fixed-point, to stop
+// VC from linking in floatingpoint-long conversions
+//
+//#define FIXED_PREC_MOVE
+#ifdef FIXED_PREC_MOVE
+#define PRECISION 12
+void ZoomCard(HDC hdc, int xpos, int ypos, CARDSTACK *dest)
+{
+ long dx, dy, x , y;
+
+
+ int apparentcards;
+ x = xpos << PRECISION; y = ypos << PRECISION;
+
+ oldx = (int)xpos;
+ oldy = (int)ypos;
+
+ apparentcards=dest->numcards/dest->threedcount;
+
+ int idestx = dest->xpos + dest->xoffset * (apparentcards);// - iNumDragCards);
+ int idesty = dest->ypos + dest->yoffset * (apparentcards);// - iNumDragCards);
+
+ //normalise the motion vector
+ dx = (idestx<<PRECISION) - x;
+ dy = (idesty<<PRECISION) - y;
+ long recip = (1 << PRECISION) / 1;//sqrt(dx*dx + dy*dy);
+
+ dx *= recip * 16;//CARDZOOMSPEED;
+ dy *= recip * 16;//CARDZOOMSPEED;
+
+ //if(dx < 0) dxinc = 1.001; else
+
+ for(;;)
+ {
+ int ix, iy;
+ x += dx;
+ y += dy;
+
+ ix = (int)x>>PRECISION;
+ iy = (int)y>>PRECISION;
+ if(dx < 0 && ix < idestx) ix = idestx;
+ else if(dx > 0 && ix > idestx) ix = idestx;
+
+ if(dy < 0 && iy < idesty) iy = idesty;
+ else if(dy > 0 && iy > idesty) iy = idesty;
+
+ MoveDragCardTo(hdc, ix, iy);
+
+ if(ix == idestx && iy == idesty)
+ break;
+
+ oldx = (int)x >> PRECISION;
+ oldy = (int)y >> PRECISION;
+
+ //dx *= 1.2;
+ //dy *= 1.2;
+
+ Sleep(10);
+ }
+}
+#else
+void CardRegion::ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *pDestStack)
+{
+ TRACE ( "ENTER ZoomCard()\n" );
+ double dx, dy, x ,y;
+ int apparentcards;
+ x = (double)xpos; y = (double)ypos;
+
+ oldx = (int)x;
+ oldy = (int)y;
+
+ apparentcards = pDestStack->cardstack.NumCards() / pDestStack->nThreedCount;
+
+ int idestx = pDestStack->xpos + pDestStack->xoffset * (apparentcards);
+ int idesty = pDestStack->ypos + pDestStack->yoffset * (apparentcards);
+
+ if(pDestStack->yoffset < 0)
+ idesty += pDestStack->yoffset * (iNumDragCards-1);
+
+ if(pDestStack->xoffset < 0)
+ idestx += pDestStack->xoffset * (iNumDragCards-1);
+
+ //normalise the motion vector
+ dx = idestx - x;
+ dy = idesty - y;
+ if ( fabs(dx) + fabs(dy) < 0.001f )
+ {
+ MoveDragCardTo(hdc, idestx, idesty);
+ return;
+ }
+ double recip = 1.0 / sqrt(dx*dx + dy*dy);
+ dx *= recip * __CARDZOOMSPEED; dy *= recip * __CARDZOOMSPEED;
+
+ //if(dx < 0) dxinc = 1.001; else
+
+ for(;;)
+ {
+ bool attarget = true;
+ int ix, iy;
+ x += dx;
+ y += dy;
+
+ ix = (int)x;
+ iy = (int)y;
+
+ if(dx < 0.0 && ix < idestx) ix = idestx;
+ else if(dx > 0.0 && ix > idestx) ix = idestx;
+ else attarget = false;
+
+ if(dy < 0.0 && iy < idesty) iy = idesty;
+ else if(dy > 0.0 && iy > idesty) iy = idesty;
+ else attarget = false;
+
+ //if the target stack wants the drag cards drawn differently
+ //to how they are, then redraw the drag card image just before
+ //the cards land
+ /*if(attarget == true)
+ {
+ for(int i = 0; i < iNumDragCards; i++)
+ {
+ int xdraw = pDestStack->xoffset*i;
+ int ydraw = pDestStack->yoffset*i;
+
+ if(pDestStack->yoffset < 0)
+ ydraw = -pDestStack->yoffset * (iNumDragCards-i-1);
+ if(pDestStack->xoffset < 0)
+ xdraw = -pDestStack->xoffset * (iNumDragCards-i-1);
+
+ if(pDestStack->facedirection == CS_FACEUP &&
+ pDestStack->numcards+i >= dest->numfacedown)
+ {
+ //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0);
+ }
+ else
+ {
+ //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0);
+ }
+ }
+ }*/
+
+ MoveDragCardTo(hdc, ix, iy);
+
+ if(attarget || ix == idestx && iy == idesty)
+ break;
+
+ oldx = (int)x;
+ oldy = (int)y;
+
+ //dx *= 1.2;
+ //dy *= 1.2;
+
+ Sleep(10);
+ }
+ TRACE ( "EXIT ZoomCard()\n" );
+}
+#endif