reactos/sdk/lib/3rdparty/cardlib/cardrgndraw.cpp

627 lines
18 KiB
C++

//
// CardLib - CardRegion drawing support
//
// Freeware
// Copyright J Brown 2001
//
#include "cardlib.h"
HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette);
void PaintRect(HDC hdc, RECT *rect, COLORREF colour);
void CardBlt(HDC hdc, int x, int y, int nCardNum);
void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height);
//
// Draw specified card at position x, y
// xoff - source offset from left of card
// yoff - source offset from top of card
// width - width to draw
// height - height to draw
//
void CardBlt(HDC hdc, int x, int y, int nCardNum)//, int xoff, int yoff, int width, int height)
{
int sx = nCardNum * __cardwidth;
int sy = 0;
int width = __cardwidth;
int height = __cardheight;
//draw main center band
BitBlt(hdc, x+2, y, width - 4, height, __hdcCardBitmaps, sx+2, sy+0, SRCCOPY);
//draw the two bits to the left
BitBlt(hdc, x, y+2, 1, height - 4, __hdcCardBitmaps, sx+0, sy+2, SRCCOPY);
BitBlt(hdc, x+1, y+1, 1, height - 2, __hdcCardBitmaps, sx+1, sy+1, SRCCOPY);
//draw the two bits to the right
BitBlt(hdc, x+width-2, y+1, 1, height - 2, __hdcCardBitmaps, sx+width-2, sy+1, SRCCOPY);
BitBlt(hdc, x+width-1, y+2, 1, height - 4, __hdcCardBitmaps, sx+width-1, sy+2, SRCCOPY);
}
//
// Draw a shape this this:
//
// ++++++++++++
// ++++++++++++++
// ++ ++
//
void DrawHorzCardStrip(HDC hdc, int x, int y, int nCardNum, int height, BOOL fDrawTips)
{
int sx = nCardNum * __cardwidth;
int sy = 0;
int one = 1;
int two = 2;
BOOL tips = fDrawTips ? FALSE : TRUE;
if(height == 0) return;
if(height < 0)
{
sy = sy + __cardheight;
y -= height;
one = -one;
two = -two;
}
// draw the main vertical band
//
BitBlt(hdc, x + 2, y, __cardwidth - 4, height, __hdcCardBitmaps, sx+2, sy, SRCCOPY);
//if(height <= 1) return;
// draw the "lips" at the left and right
BitBlt(hdc, x+1, y+one, 1, height-one*tips, __hdcCardBitmaps, sx+1, sy+one, SRCCOPY);
BitBlt(hdc, x+__cardwidth-2, y+one, 1, height-one*tips, __hdcCardBitmaps, sx+__cardwidth-2, sy+one, SRCCOPY);
//if(height <= 2) return;
// draw the outer-most lips
BitBlt(hdc, x, y+two, 1, height-two*tips, __hdcCardBitmaps, sx, sy+two, SRCCOPY);
BitBlt(hdc, x+__cardwidth-1, y+two, 1, height-two*tips, __hdcCardBitmaps, sx+__cardwidth-1, sy+two, SRCCOPY);
}
//
// Draw a shape like this:
//
// +++
// +++
// +++
// +++
// +++
// +++
// +++
// +++
// +++
// +++
//
//
void DrawVertCardStrip(HDC hdc, int x, int y, int nCardNum, int width, BOOL fDrawTips)
{
int sx = nCardNum * __cardwidth;
int sy = 0;
int one = 1;
int two = 2;
BOOL tips = fDrawTips ? FALSE : TRUE;
if(width == 0) return;
if(width < 0)
{
sx = sx + __cardwidth;
x -= width;
one = -1;
two = -2;
}
// draw the main vertical band
//
BitBlt(hdc, x, y + 2, width, __cardheight - 4, __hdcCardBitmaps, sx, sy+2, SRCCOPY);
//if(width <= 1) return;
// draw the "lips" at the top and bottom
BitBlt(hdc, x+one, y+1, width-one*tips, 1, __hdcCardBitmaps, sx+one, sy + 1, SRCCOPY);
BitBlt(hdc, x+one, y+__cardheight-2, width-one*tips, 1, __hdcCardBitmaps, sx+one, sy + __cardheight-2, SRCCOPY);
//if(width <= 2) return;
// draw the outer-most lips
BitBlt(hdc, x+two, y, width-two*tips, 1, __hdcCardBitmaps, sx+two, sy, SRCCOPY);
BitBlt(hdc, x+two, y+__cardheight-1, width-two*tips, 1, __hdcCardBitmaps, sx+two, sy + __cardheight-1, SRCCOPY);
}
//
// xdir - <0 or >0
// ydir - <0 or >0
//
void DrawCardCorner(HDC hdc, int x, int y, int cardval, int xdir, int ydir)
{
int sx = cardval * __cardwidth;
int sy = 0;
HDC hdcSource = __hdcCardBitmaps;
if(xdir < 0)
{
x += __cardwidth + xdir - 1;
sx += __cardwidth + xdir - 1;
}
else
{
x += xdir;
sx += xdir;
}
if(ydir < 0)
{
y += __cardheight + ydir - 1;
sy += __cardheight + ydir - 1;
}
else
{
y += ydir;
sy += ydir;
}
//convert x,y directions to -1, +1
xdir = xdir < 0 ? -1 : 1;
ydir = ydir < 0 ? -1 : 1;
SetPixel(hdc, x+xdir, y , GetPixel(hdcSource, sx+xdir, sy));
SetPixel(hdc, x, y, GetPixel(hdcSource, sx, sy));
SetPixel(hdc, x, y+ydir, GetPixel(hdcSource, sx, sy+ydir));
}
//
// Draw a card (i.e. miss out the corners)
//
void DrawCard(HDC hdc, int x, int y, HDC hdcDragCard, int width, int height)
{
//draw main center band
BitBlt(hdc, x+2, y, width - 4, height, hdcDragCard, 2, 0, SRCCOPY);
//draw the two bits to the left
BitBlt(hdc, x, y+2, 1, height - 4, hdcDragCard, 0, 2, SRCCOPY);
BitBlt(hdc, x+1, y+1, 1, height - 2, hdcDragCard, 1, 1, SRCCOPY);
//draw the two bits to the right
BitBlt(hdc, x+width-2, y+1, 1, height - 2, hdcDragCard, width-2, 1, SRCCOPY);
BitBlt(hdc, x+width-1, y+2, 1, height - 4, hdcDragCard, width-1, 2, SRCCOPY);
}
//
// Clip a card SHAPE - basically any rectangle
// with rounded corners
//
int ClipCard(HDC hdc, int x, int y, int width, int height)
{
ExcludeClipRect(hdc, x+2, y, x+2+width-4, y+ height);
ExcludeClipRect(hdc, x, y+2, x+1, y+2+height-4);
ExcludeClipRect(hdc, x+1, y+1, x+2, y+1+height-2);
ExcludeClipRect(hdc, x+width-2, y+1, x+width-2+1, y+1+height-2);
ExcludeClipRect(hdc, x+width-1, y+2, x+width-1+1, y+2+height-4);
return 0;
}
void CardRegion::Clip(HDC hdc)
{
int numtoclip;
if(fVisible == false)
return;
Update(); //Update this stack's size+card count
numtoclip = nNumApparentCards;
//if we are making this stack flash on/off, then only
//clip the stack for drawing if the flash is in its ON state
if(nFlashCount != 0)
{
if(fFlashVisible == FALSE)
numtoclip = 0;
}
//if offset along a diagonal
if(xoffset != 0 && yoffset != 0 && cardstack.NumCards() != 0)
{
for(int j = 0; j < numtoclip; j ++)
{
ClipCard(hdc, xpos + xoffset * j, ypos + yoffset * j, __cardwidth, __cardheight);
}
}
//otherwise if just offset along a horizontal/vertical axis
else
{
if(yoffset < 0 && numtoclip > 0)
{
ClipCard(hdc, xpos, ypos-((numtoclip-1)*-yoffset), width, height);
}
else if(xoffset < 0 && numtoclip > 0)
{
ClipCard(hdc, xpos-((numtoclip-1)*-xoffset), ypos, width, height);
}
else
{
ClipCard(hdc, xpos, ypos, width, height);
}
}
}
void CardRegion::Render(HDC hdc)
{
int cardnum = 0;
int numtodraw;
BOOL fDrawTips;
Update(); //Update this stack's card count + size
numtodraw = nNumApparentCards;
if(nFlashCount != 0)
{
if(fFlashVisible == false)
numtodraw = 0;
}
if(fVisible == 0) return;
cardnum = cardstack.NumCards() - numtodraw;
int counter;
for(counter = 0; counter < numtodraw; counter++)
{
int cardval;
int x = xoffset * counter + xpos;
int y = yoffset * counter + ypos;
//if about to draw last card, then actually draw the top card
if(counter == numtodraw - 1) cardnum = cardstack.NumCards() - 1;
Card card = cardstack.cardlist[cardnum];
cardval = card.Idx();
if(card.FaceDown())
cardval = nBackCardIdx; //card-back
//only draw the visible part of the card
if(counter < numtodraw - 1)
{
if(yoffset != 0 && xoffset != 0)
fDrawTips = FALSE;
else
fDrawTips = TRUE;
if((yoffset != 0 && abs(xoffset) == 1) || (xoffset != 0 && abs(yoffset) == 1))
fDrawTips = TRUE;
//draw horizontal strips
if(yoffset > 0)
{
DrawHorzCardStrip(hdc, x, y, cardval, yoffset, fDrawTips);
}
else if(yoffset < 0)
{
DrawHorzCardStrip(hdc, x, y+__cardheight+yoffset, cardval, yoffset, fDrawTips);
}
//draw some vertical bars
if(xoffset > 0)
{
DrawVertCardStrip(hdc, x, y, cardval, xoffset, fDrawTips);
}
else if(xoffset < 0)
{
DrawVertCardStrip(hdc, x+__cardwidth+xoffset, y, cardval, xoffset, fDrawTips);
}
if(yoffset != 0 && xoffset != 0)//fDrawTips == FALSE)
{
//if we didn't draw any tips, then this is a 2-dim stack
//(i.e, it goes at a diagonal).
//in this case, we need to fill in the small triangle in
//each corner!
DrawCardCorner(hdc, x, y, cardval, xoffset, yoffset);
}
}
//if the top card, draw the whole thing
else
{
CardBlt(hdc, x, y, cardval);
}
cardnum ++;
} //end of index
if(counter == 0) //if the cardstack is empty, then draw it that way
{
int x = xpos;
int y = ypos;
switch(uEmptyImage)
{
default:
case CS_EI_NONE:
//this wipes the RECT variable, so watch out!
//SetRect(&rect, x, y, x+__cardwidth, y+__cardheight);
//PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));
parentWnd.PaintCardRgn(hdc, x, y, __cardwidth, __cardheight, x, y);
break;
case CS_EI_SUNK:
DrawCard(hdc, x, y, __hdcPlaceHolder, __cardwidth, __cardheight);
break;
case CS_EI_CIRC:
case CS_EI_X:
CardBlt(hdc, x, y, uEmptyImage);
break;
}
}
return;
}
int calc_offset(int offset, int numcards, int numtodrag, int realvisible)
{
if(offset >= 0)
return -offset * numcards;
else
return -offset * (numtodrag) +
-offset * (realvisible - 1);
}
void CardRegion::PrepareDragBitmaps(int numtodrag)
{
RECT rect;
HDC hdc;
int icard;
int numcards = cardstack.NumCards();
int xoff, yoff;
if(nThreedCount > 1)
{
PrepareDragBitmapsThreed(numtodrag);
return;
}
//work out how big the bitmaps need to be
nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth;
nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight;
//Create bitmap for the back-buffer
hdc = GetDC(NULL);
hdcBackGnd = CreateCompatibleDC(hdc);
hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcBackGnd, hbmBackGnd);
//Create bitmap for the drag-image
hdcDragCard = CreateCompatibleDC(hdc);
hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcDragCard, hbmDragCard);
ReleaseDC(NULL, hdc);
UseNicePalette(hdcBackGnd, __hPalette);
UseNicePalette(hdcDragCard, __hPalette);
int realvisible = numcards / nThreedCount;
//if(numcards > 0 && realvisible == 0) realvisible = 1;
int iwhichcard = numcards - 1;
if(nThreedCount == 1) iwhichcard = 0;
//grab the first bit of background so we can prep the back buffer; do this by
//rendering the card stack (minus the card we are dragging) to the temporary
//background buffer, so it appears if we have lifted the card from the stack
//PaintRect(hdcBackGnd, &rect, crBackgnd);
SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight);
xoff = calc_offset(xoffset, numcards, numtodrag, realvisible);
yoff = calc_offset(yoffset, numcards, numtodrag, realvisible);
parentWnd.PaintCardRgn(hdcBackGnd, 0, 0, nDragCardWidth, nDragCardHeight, xpos - xoff, ypos - yoff);
//
// Render the cardstack into the back-buffer. The stack
// has already had the dragcards removed, so just draw
// what is left
//
for(icard = 0; icard < realvisible; icard++)
{
Card card = cardstack.cardlist[iwhichcard];
int nCardVal;
nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
xoff = xoffset * icard + calc_offset(xoffset, numcards, numtodrag, realvisible);//- xoffset * ((numcards+numtodrag) / nThreedCount - numtodrag);
yoff = yoffset * icard + calc_offset(yoffset, numcards, numtodrag, realvisible);//- yoffset * ((numcards+numtodrag) / nThreedCount - numtodrag);
CardBlt(hdcBackGnd, xoff, yoff, nCardVal);
iwhichcard++;
}
//
// If there are no cards under this one, just draw the place holder
//
if(numcards == 0)
{
int xoff = 0, yoff = 0;
if(xoffset < 0) xoff = nDragCardWidth - __cardwidth;
if(yoffset < 0) yoff = nDragCardHeight - __cardheight;
switch(uEmptyImage)
{
case CS_EI_NONE:
//No need to draw anything: We already cleared the
//back-buffer before the main loop..
//SetRect(&rc, xoff, yoff, xoff+ __cardwidth, yoff + __cardheight);
//PaintRect(hdcBackGnd, &rc, MAKE_PALETTERGB(crBackgnd));
//parentWnd.PaintCardRgn(hdcBackGnd, xoff, yoff, __cardwidth, __cardheight, xpos, ypos);// + xoff, ypos + yoff);
break;
case CS_EI_SUNK:
DrawCard(hdcBackGnd, xoff, yoff, __hdcPlaceHolder, __cardwidth, __cardheight);
break;
case CS_EI_CIRC:
case CS_EI_X:
CardBlt(hdc, xoff, yoff, uEmptyImage);
break;
}
}
//
// now render the drag-cards into the dragcard image
//
PaintRect(hdcDragCard, &rect, crBackgnd);
for(icard = 0; icard < numtodrag; icard++)
{
int nCardVal;
if(xoffset >= 0) xoff = xoffset * icard;
else xoff = -xoffset * (numtodrag - icard - 1);
if(yoffset >= 0) yoff = yoffset * icard;
else yoff = -yoffset * (numtodrag - icard - 1);
Card card = dragstack.cardlist[icard];
nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
CardBlt(hdcDragCard, xoff, yoff, nCardVal);
}
}
void CardRegion::PrepareDragBitmapsThreed(int numtodrag)
{
RECT rect;
HDC hdc;
int icard;
int numunder = 0;
int iwhichcard;
int numcards = cardstack.NumCards();
//work out how big the bitmaps need to be
nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth;
nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight;
//Create bitmap for the back-buffer
hdc = GetDC(NULL);
hdcBackGnd = CreateCompatibleDC(hdc);
hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcBackGnd, hbmBackGnd);
//create bitmap for the drag-image
hdcDragCard = CreateCompatibleDC(hdc);
hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcDragCard, hbmDragCard);
ReleaseDC(NULL, hdc);
UseNicePalette(hdcBackGnd, __hPalette);
UseNicePalette(hdcDragCard, __hPalette);
//grab the first bit of background so we can prep the back buffer; do this by
//rendering the card stack (minus the card we are dragging) to the temporary
//background buffer, so it appears if we have lifted the card from the stack
//--SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight);
//--PaintRect(hdcBackGnd, &rect, crBackgnd);
int threedadjust = numcards % nThreedCount == 0;
numunder = CalcApparentCards(numcards);
iwhichcard = (numcards+numtodrag) - numunder - 1;
if(nThreedCount == 1) iwhichcard = 0;
int xoff = calc_offset(xoffset, numunder, numtodrag, numunder);
int yoff = calc_offset(yoffset, numunder, numtodrag, numunder);
parentWnd.PaintCardRgn(hdcBackGnd, 0,0, nDragCardWidth,nDragCardHeight, xpos - xoff,ypos - yoff);
//
// Render the cardstack into the back-buffer. The stack
// has already had the dragcards removed, so just draw
// what is left
//
for(icard = 0; icard < numunder; icard++)
{
Card card = cardstack.cardlist[iwhichcard];
int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
CardBlt(hdcBackGnd,
xoffset * icard - xoffset*(numunder-numtodrag+threedadjust),
yoffset * icard - yoffset*(numunder-numtodrag+threedadjust),
nCardVal);
iwhichcard++;
}
//
// If there are no cards under this one, just draw the place holder
//
if(numcards == 0)
{
switch(uEmptyImage)
{
case CS_EI_NONE:
//no need! we've already cleared the whole
//back-buffer before the main loop!
//SetRect(&rect, 0, 0, __cardwidth, __cardheight);
//PaintRect(hdcBackGnd, &rect, MAKE_PALETTERGB(crBackgnd));
break;
case CS_EI_SUNK:
DrawCard(hdcBackGnd, 0, 0, __hdcPlaceHolder, __cardwidth, __cardheight);
break;
case CS_EI_CIRC:
case CS_EI_X:
CardBlt(hdc, 0, 0, uEmptyImage);
break;
}
}
//
// now render the drag-cards into the dragcard image
//
PaintRect(hdcDragCard, &rect, crBackgnd);
for(icard = 0; icard < numtodrag; icard++)
{
Card card = dragstack.cardlist[icard];
int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
CardBlt(hdcDragCard, xoffset * icard, yoffset * icard, nCardVal);
}
}
void CardRegion::ReleaseDragBitmaps(void)
{
//SelectObject(hdcBackGnd, hOld1);
DeleteObject(hbmBackGnd);
DeleteDC(hdcBackGnd);
//SelectObject(hdcDragCard, hOld2);
DeleteObject(hbmDragCard);
DeleteDC(hdcDragCard);
}
void CardRegion::Redraw()
{
HDC hdc = GetDC((HWND)parentWnd);
Update();
Render(hdc);
ReleaseDC((HWND)parentWnd, hdc);
}