mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 10:53:15 +00:00
648 lines
16 KiB
C++
648 lines
16 KiB
C++
//
|
|
// CardLib - CardRegion mouse-related stuff
|
|
//
|
|
// Freeware
|
|
// Copyright J Brown 2001
|
|
//
|
|
|
|
#include "cardlib.h"
|
|
|
|
#include <math.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;
|
|
}
|
|
|
|
void CardRegion::ClickRelease(int x, int y)
|
|
{
|
|
iNumDragCards = GetNumDragCards(x, y);
|
|
|
|
if (ClickReleaseCallback)
|
|
ClickReleaseCallback(*this, iNumDragCards);
|
|
}
|
|
|
|
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
|