imported catch-22 sol clone with authors permission

svn path=/trunk/; revision=13904
This commit is contained in:
Steven Edwards 2005-03-10 04:04:27 +00:00
parent 59b8be68dc
commit e415037205
32 changed files with 7127 additions and 0 deletions

View file

@ -0,0 +1,22 @@
Solitaire for ReactOS
/*****************************************
A complete working example of the CardLib
card-game library.
Freeware
Copyright J Brown 2001
Updates at http://www.catch22.net
******************************************/
The author has given permission to use these sources
under Public Domain. Do what thou will but please give
credit where credit is due.
If you wish to use cardlib to write another card game
for ReactOS please make cardlib a static lib.
-sedwards

View file

@ -0,0 +1,105 @@
//
// CardLib - Card class
//
// Freeware
// Copyright J Brown 2001
//
#ifndef _CARD_INCLUDED
#define _CARD_INCLUDED
enum eSuit { Clubs = 0, Diamonds = 1, Hearts = 2, Spades = 3 };
enum eValue { Ace = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6, Seven = 7,
Eight = 8, Nine = 9, Ten = 10, Jack = 11, Queen = 12, King = 13 };
inline int MAKE_CARD(int Value, int Suit)
{
if(Value < 1) Value = 1;
if(Value == 14) Value = 1;
if(Value > 13) Value = 13;
if(Suit < 0) Suit = 0;
if(Suit > 3) Suit = 3;
return ((Value - 1) * 4 + Suit);
}
class Card
{
friend class CardStack;
public:
Card()
{
nValue = 0; //ace of spades by default
fFaceUp = true;
}
Card(int value, int suit) //specify a face value [1-13] and suit [0-3]
{
nValue = MAKE_CARD(value, suit);
fFaceUp = true;
}
Card(int index) //specify a 0-51 index
{
if(index < 0) index = 0;
if(index > 51) index = 51;
nValue = index;
fFaceUp = true;
}
int Suit() const
{
return (nValue % 4);
}
int LoVal() const
{
return (nValue / 4) + 1;
}
int HiVal() const
{
return ((nValue < 4) ? 14 : (nValue / 4) + 1);
}
int Idx() const //unique value (0-51 etc)
{
return nValue;
}
bool FaceUp() const
{
return fFaceUp;
}
bool FaceDown() const
{
return !fFaceUp;
}
void SetFaceUp(bool fTrue)
{
fFaceUp = fTrue;
}
bool IsBlack() const
{
return Suit() == 0 || Suit() == 3;
}
bool IsRed() const
{
return !IsBlack();
}
private:
int nValue;
bool fFaceUp;
};
#endif

View file

@ -0,0 +1,281 @@
//
// CardLib - Card bitmap support
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include "globals.h"
#include "cardcolor.h"
#ifndef __REACTOS__
#pragma comment( lib, "..\\CardLib\\cards16.lib" )
extern "C" HINSTANCE WINAPI LoadLibrary16( PSTR );
extern "C" void WINAPI FreeLibrary16( HINSTANCE );
#endif
#define NUMCARDBITMAPS (52+16)
void PaintRect(HDC hdc, RECT *rect, COLORREF col);
void LoadCardBitmapsFromLibrary(HINSTANCE hCardDll, int *pwidth, int *pheight)
{
HBITMAP hBitmap;
HDC hdcCard;
HANDLE hOld;
int i, xpos;
int width, height;
BITMAP bmp;
for(i = 0; i < NUMCARDBITMAPS; i++)
{
//convert into the range used by the cdt_xxx functions
int val;
if(i < 52) val = (i % 4) * 13 + (i/4);
else val = i;
hBitmap = LoadBitmap(hCardDll, MAKEINTRESOURCE(val + 1));
GetObject(hBitmap, sizeof(bmp), &bmp);
width = bmp.bmWidth;
height = bmp.bmHeight;
if(i == 0) //if first time through, create BIG bitmap..
{
HDC hdc = GetDC(0);
__hdcCardBitmaps = CreateCompatibleDC(hdc);
__hbmCardBitmaps = CreateCompatibleBitmap(hdc, width * NUMCARDBITMAPS, height);
SelectObject(__hdcCardBitmaps, __hbmCardBitmaps);
hdcCard = CreateCompatibleDC(0);
ReleaseDC(0, hdc);
}
hOld = SelectObject(hdcCard, hBitmap);
BitBlt(__hdcCardBitmaps, i*width, 0, width, height, hdcCard, 0, 0, SRCCOPY);
SelectObject(hdcCard, hOld);
//Now draw a black border around each card...
xpos = i*width;
MoveToEx(__hdcCardBitmaps, xpos+2, 0, 0);
LineTo(__hdcCardBitmaps, xpos+width - 3, 0);
LineTo(__hdcCardBitmaps, xpos+width - 1, 2);
LineTo(__hdcCardBitmaps, xpos+width - 1, height - 3); //vertical
LineTo(__hdcCardBitmaps, xpos+width - 3, height - 1);
LineTo(__hdcCardBitmaps, xpos+2, height - 1);
LineTo(__hdcCardBitmaps, xpos+0, height - 3);
LineTo(__hdcCardBitmaps, xpos+0, 2);
LineTo(__hdcCardBitmaps, xpos+2, 0);
DeleteObject(hBitmap);
}
DeleteDC(hdcCard);
*pwidth = width;
*pheight = height;
}
void LoadCardBitmaps(void)
{
HINSTANCE hCardDll;
//If Windows NT/2000/XP
if(GetVersion() < 0x80000000)
{
hCardDll = LoadLibrary("cards.dll");
if(hCardDll == 0)
{
MessageBox(0, "Error loading cards.dll (32bit)", "Shed", MB_OK | MB_ICONEXCLAMATION);
PostQuitMessage(0);
return;
}
LoadCardBitmapsFromLibrary(hCardDll, &__cardwidth, &__cardheight);
FreeLibrary(hCardDll);
}
#ifndef __REACTOS__
//Else, Win9X
else
{
hCardDll = LoadLibrary16("cards.dll");
if(hCardDll == 0)
{
MessageBox(0, "Error loading cards.dll (16bit)", "Shed", MB_OK | MB_ICONEXCLAMATION);
PostQuitMessage(0);
return;
}
LoadCardBitmapsFromLibrary(hCardDll, &__cardwidth, &__cardheight);
FreeLibrary16(hCardDll);
}
#endif
}
void FreeCardBitmaps()
{
DeleteObject (__hbmCardBitmaps);
DeleteDC (__hdcCardBitmaps);
}
//
// Paint a checkered rectangle, with each alternate
// pixel being assigned a different colour
//
static void DrawCheckedRect(HDC hdc, RECT *rect, COLORREF fg, COLORREF bg)
{
static WORD wCheckPat[8] =
{
0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555
};
HBITMAP hbmp;
HBRUSH hbr, hbrold;
COLORREF fgold, bgold;
hbmp = CreateBitmap(8, 8, 1, 1, wCheckPat);
hbr = CreatePatternBrush(hbmp);
//UnrealizeObject(hbr);
SetBrushOrgEx(hdc, rect->left, rect->top, 0);
hbrold = (HBRUSH)SelectObject(hdc, hbr);
fgold = SetTextColor(hdc, fg);
bgold = SetBkColor(hdc, bg);
PatBlt(hdc, rect->left, rect->top,
rect->right - rect->left,
rect->bottom - rect->top,
PATCOPY);
SetBkColor(hdc, bgold);
SetTextColor(hdc, fgold);
SelectObject(hdc, hbrold);
DeleteObject(hbr);
DeleteObject(hbmp);
}
void GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2)
{
if(bg) *bg = crBase;
if(fg) *fg = ColorScaleRGB(crBase, RGB(255,255,255), 0.2);//RGB(49, 99, 140);
if(sh1) *sh1 = ColorScaleRGB(crBase, RGB(0,0,0), 0.4);
if(sh2) *sh2 = ColorScaleRGB(crBase, RGB(0,0,0), 0.2);
}
HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height)
{
HANDLE hold, hpold;
HBITMAP hbm = CreateCompatibleBitmap(hdcCompat, width, height);
HPEN hpfg, hpbg, hpsh, hpsh2;
RECT rect;
COLORREF fg, bg, shadow, shadow2;
GetSinkCols(col, &fg, &bg, &shadow, &shadow2);
hold = SelectObject(hdc, hbm);
//fill with a solid base colour
SetRect(&rect, 0,0,width,height);
PaintRect(hdc, &rect, MAKE_PALETTERGB(bg));
//draw the outline
hpfg = CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(fg));
hpbg = CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(bg));
hpsh = CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(shadow));
hpsh2= CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(shadow2));
hpold = SelectObject(hdc, hpsh);
MoveToEx(hdc, 2, 0, NULL);
LineTo (hdc, width-3,0);
LineTo (hdc, width-1, 2);
SelectObject(hdc, hpold);
hpold = SelectObject(hdc, hpsh2);
LineTo (hdc, width-1, height-3); //vertical
LineTo (hdc, width-3, height-1);
LineTo (hdc, 2, height-1);
LineTo (hdc, 0, height-3);
SelectObject(hdc, hpold);
hpold = SelectObject(hdc, hpsh);
//MoveToEx( hdc, 0, height-3,0);
LineTo (hdc, 0, 2);
LineTo (hdc, 2, 0);
SelectObject(hdc, hpold);
//draw the highlight (vertical)
hpold = SelectObject(hdc, hpfg);
MoveToEx(hdc, width - 2, 3, NULL);
LineTo (hdc, width - 2, height - 2);
//(horz)
MoveToEx(hdc, width - 3, height-2, NULL);
LineTo (hdc, 3, height-2);
SelectObject(hdc, hpold);
//draw the background
InflateRect(&rect, -2, -2);
DrawCheckedRect(hdc, &rect, MAKE_PALETTERGB(bg), MAKE_PALETTERGB(fg));
//overwrite the top-left background pixel
SetPixel(hdc, 2, 2, MAKE_PALETTERGB(bg));
DeleteObject(hpsh);
DeleteObject(hpsh2);
DeleteObject(hpfg);
DeleteObject(hpbg);
return hbm;
}
void CopyColor(PALETTEENTRY *pe, COLORREF col)
{
pe->peBlue = GetBValue(col);
pe->peGreen = GetGValue(col);
pe->peRed = GetRValue(col);
pe->peFlags = 0;
}
HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours)
{
LOGPALETTE *lp;
HPALETTE hPalette;
// Allocate memory for the logical palette
lp = (LOGPALETTE *)HeapAlloc(
GetProcessHeap(), 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * nNumColours);
lp->palNumEntries = nNumColours;
lp->palVersion = 0x300;
//copy the colours into the logical palette format
for(int i = 0; i < nNumColours; i++)
{
CopyColor(&lp->palPalEntry[i], cols[i]);
}
// create palette!
hPalette = CreatePalette(lp);
HeapFree(GetProcessHeap(), 0, lp);
return hPalette;
}

View file

@ -0,0 +1,489 @@
//
// CardLib - CardButton class
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <tchar.h>
#include "cardlib.h"
#include "cardwindow.h"
#include "cardbutton.h"
#include "cardcolor.h"
HPALETTE UseNicePalette(HDC, HPALETTE);
void RestorePalette(HDC, HPALETTE);
void PaintRect(HDC hdc, RECT *rect, COLORREF colour);
CardButton::CardButton(CardWindow &parent, int Id, TCHAR *szText, UINT Style, bool visible,
int x, int y, int width, int height)
: parentWnd(parent), id(Id), fVisible(visible), uStyle(Style), ButtonCallback(0)
{
crText = RGB(255,255,255);
crBack = RGB(0, 128, 0);
xadjust = 0;
yadjust = 0;
xjustify = 0;
yjustify = 0;
fMouseDown = false;
fButtonDown = false;
hIcon = 0;
SetText(szText);
Move(x, y, width, height);
mxlock = CreateMutex(0, FALSE, 0);
hFont = 0;
}
CardButton::~CardButton()
{
CloseHandle(mxlock);
}
void CardButton::DrawRect(HDC hdc, RECT *rect, bool fNormal)
{
RECT fill;
HANDLE hOld;
HPEN hhi = CreatePen(0, 0, MAKE_PALETTERGB(crHighlight));
HPEN hsh = CreatePen(0, 0, MAKE_PALETTERGB(crShadow));
HPEN hbl = (HPEN)GetStockObject(BLACK_PEN);
int x = rect->left;
int y = rect->top;
int width = rect->right-rect->left - 1;
int height = rect->bottom-rect->top - 1;
SetRect(&fill, x+1, y+1, x+width-1, y+height-1);
int one = 1;
if(!fNormal)
{
x += width;
y += height;
width = -width;
height = -height;
one = -1;
OffsetRect(&fill, 1, 1);
}
if(fNormal)
hOld = SelectObject(hdc, hhi);
else
hOld = SelectObject(hdc, hhi);
MoveToEx(hdc, x, y+height, 0);
LineTo(hdc, x, y);
LineTo(hdc, x+width, y);
SelectObject(hdc, hOld);
hOld = SelectObject(hdc, hbl);
LineTo(hdc, x+width, y+height);
LineTo(hdc, x-one, y+height);
SelectObject(hdc, hOld);
hOld = SelectObject(hdc, hsh);
MoveToEx(hdc, x+one, y+height-one, 0);
LineTo(hdc, x+width-one, y+height-one);
LineTo(hdc, x+width-one, y);
SelectObject(hdc, hOld);
PaintRect(hdc, &fill, MAKE_PALETTERGB(crBack));
DeleteObject(hhi);
DeleteObject(hsh);
}
void CardButton::Clip(HDC hdc)
{
if(fVisible == false) return;
ExcludeClipRect(hdc, rect.left, rect.top, rect.right, rect.bottom);
}
void CardButton::Draw(HDC hdc, bool fNormal)
{
SIZE textsize;
int x, y; //text x, y
int ix, iy; //icon x, y
int iconwidth = 0;
RECT cliprect;
if(fVisible == 0) return;
if(hFont == 0)
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
else
SelectObject(hdc, hFont);
GetTextExtentPoint32(hdc, szText, lstrlen(szText), &textsize);
if(hIcon)
{
x = rect.left + 32 + 8;
}
else
{
if(uStyle & CB_ALIGN_LEFT)
{
x = rect.left + iconwidth;
}
else if(uStyle & CB_ALIGN_RIGHT)
{
x = rect.left + (rect.right-rect.left-iconwidth-textsize.cx);
}
else //centered
{
x = rect.right - rect.left - iconwidth;
x = (x - textsize.cx) / 2;
x += rect.left + iconwidth;
}
}
y = rect.bottom - rect.top;
y = (y - textsize.cy) / 2;
y += rect.top;
//calc icon position..
ix = rect.left + 4;
iy = rect.top + (rect.bottom-rect.top-32) / 2;
//if button is pressed, then shift text
if(fNormal == false && (uStyle & CB_PUSHBUTTON))
{
x += 1;
y += 1;
ix += 1;
iy += 1;
}
SetRect(&cliprect, x, y, x+textsize.cx, y+textsize.cy);
ExcludeClipRect(hdc, x, y, x+textsize.cx, y+textsize.cy);
//
// Calc icon pos
//
if(hIcon)
{
ExcludeClipRect(hdc, ix, iy, ix + 32, iy + 32);
}
if(uStyle & CB_PUSHBUTTON)
{
DrawRect(hdc, &rect, fNormal);
SetBkColor(hdc, MAKE_PALETTERGB(crBack));
SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText));
SelectClipRgn(hdc, 0);
ExtTextOut(hdc, x, y, ETO_OPAQUE, &cliprect, szText, lstrlen(szText), 0);
}
else
{
SetBkColor(hdc, MAKE_PALETTERGB(crBack));
SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText));
SelectClipRgn(hdc, 0);
ExtTextOut(hdc, x, y, ETO_OPAQUE, &rect, szText, lstrlen(szText), 0);
}
if(hIcon)
{
HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBack));
DrawIconEx(hdc, ix, iy, hIcon, 32, 32, 0, hbr, 0);
DeleteObject(hbr);
}
}
void CardButton::AdjustPosition(int winwidth, int winheight)
{
int width = rect.right-rect.left;
int height = rect.bottom-rect.top;
width = width & ~0x1;
switch(xjustify)
{
case CS_XJUST_NONE:
break;
case CS_XJUST_CENTER: //centered
rect.left = (winwidth - (width)) / 2;
rect.left += xadjust;
rect.right = rect.left+width;
break;
case CS_XJUST_RIGHT: //right-aligned
rect.left = winwidth - width;
rect.left += xadjust;
rect.right = rect.left+width;
break;
}
switch(yjustify)
{
case CS_YJUST_NONE:
break;
case CS_YJUST_CENTER: //centered
rect.top = (winheight - (height)) / 2;
rect.top += yadjust;
rect.bottom = rect.top+height;
break;
case CS_YJUST_BOTTOM: //right-aligned
rect.top = winheight - height;
rect.top += yadjust;
rect.bottom = rect.top+height;
break;
}
}
int CardButton::OnLButtonDown(HWND hwnd, int x, int y)
{
if((uStyle & CB_PUSHBUTTON) == 0)
return 0;
//make sure that the user is allowed to do something
if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)
{
return 0;
}
else
{
ReleaseMutex(mxlock);
}
fMouseDown = true;
fButtonDown = true;
Redraw();
SetCapture(hwnd);
return 1;
}
int CardButton::OnMouseMove(HWND hwnd, int x, int y)
{
if(fMouseDown)
{
bool fOldButtonDown = fButtonDown;
POINT pt;
pt.x = x;
pt.y = y;
if(PtInRect(&rect, pt))
fButtonDown = true;
else
fButtonDown = false;
if(fButtonDown != fOldButtonDown)
Redraw();
}
return 0;
}
int CardButton::OnLButtonUp(HWND hwnd, int x, int y)
{
if(fMouseDown)
{
fMouseDown = false;
fButtonDown = false;
if(uStyle & CB_PUSHBUTTON)
{
Redraw();
ReleaseCapture();
}
//if have clicked the button
if(parentWnd.CardButtonFromPoint(x, y) == this)
{
if(ButtonCallback)
{
ButtonCallback(*this);
}
else
{
HWND hwnd = (HWND)parentWnd;
SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(id, BN_CLICKED), (LONG)hwnd);
}
}
}
return 0;
}
#define _countof(array) (sizeof(array)/sizeof(array[0]))
CardButton *CardWindow::CreateButton(int id, TCHAR *szText, UINT uStyle, bool fVisible, int x, int y, int width, int height)
{
CardButton *cb;
if(nNumButtons == MAXBUTTONS)
return 0;
cb = new CardButton(*this, id, szText, uStyle, fVisible, x, y, width, height);
Buttons[nNumButtons++] = cb;
if(uStyle & CB_PUSHBUTTON)
{
cb->SetBackColor(CardButton::GetFace(crBackgnd));
//cb->SetBackColor(ScaleLumRGB(crBackgnd, 0.1));
cb->SetForeColor(RGB(255,255,255));
}
else
{
cb->SetBackColor(crBackgnd);
cb->SetForeColor(RGB(255,255,255));
}
return cb;
}
void CardButton::SetText(TCHAR *lpszFormat, ...)
{
int count;
va_list args;
va_start(args, lpszFormat);
count = wvsprintf(szText, lpszFormat, args);
va_end(args);
}
int CardButton::Id()
{
return id;
}
void CardButton::Show(bool fShow)
{
fVisible = fShow;
}
void CardButton::Move(int x, int y, int width, int height)
{
SetRect(&rect, x, y, x+width, y+height);
}
void CardButton::Redraw()
{
HDC hdc = GetDC((HWND)parentWnd);
HPALETTE hOldPal = UseNicePalette(hdc, __hPalette);
Draw(hdc, !fButtonDown);
RestorePalette(hdc, hOldPal);
ReleaseDC((HWND)parentWnd, hdc);
}
void CardButton::SetForeColor(COLORREF cr)
{
crText = cr;
}
void CardButton::SetBackColor(COLORREF cr)
{
crBack = cr;
crHighlight = GetHighlight(cr);
crShadow = GetShadow(cr);
//crHighlight = ScaleLumRGB(cr, +0.25);
//crShadow = ScaleLumRGB(cr, -0.25);
}
// Static member
COLORREF CardButton::GetHighlight(COLORREF crBase)
{
return ColorScaleRGB(crBase, RGB(255,255,255), 0.25);
}
// Static member
COLORREF CardButton::GetShadow(COLORREF crBase)
{
return ColorScaleRGB(crBase, RGB(0, 0, 0), 0.25);
}
COLORREF CardButton::GetFace(COLORREF crBase)
{
return ColorScaleRGB(crBase, RGB(255,255,255), 0.1);
}
void CardButton::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust)
{
xadjust = xAdjust;
yadjust = yAdjust;
xjustify = xJustify;
yjustify = yJustify;
}
void CardButton::SetIcon(HICON hicon, bool fRedraw)
{
hIcon = hicon;
if(fRedraw)
Redraw();
}
void CardButton::SetFont(HFONT font)
{
//don't delete the existing font..
hFont = font;
}
void CardButton::SetButtonProc(pButtonProc proc)
{
ButtonCallback = proc;
}
bool CardButton::Lock()
{
DWORD dw = WaitForSingleObject(mxlock, 0);
if(dw == WAIT_OBJECT_0)
return true;
else
return false;
}
bool CardButton::UnLock()
{
if(ReleaseMutex(mxlock))
return true;
else
return false;
}
void CardButton::SetStyle(UINT style)
{
uStyle = style;
}
UINT CardButton::GetStyle()
{
return uStyle;
}

View file

@ -0,0 +1,489 @@
//
// CardLib - CardButton class
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <tchar.h>
#include "cardlib.h"
#include "cardwindow.h"
#include "cardbutton.h"
#include "cardcolor.h"
HPALETTE UseNicePalette(HDC, HPALETTE);
void RestorePalette(HDC, HPALETTE);
void PaintRect(HDC hdc, RECT *rect, COLORREF colour);
CardButton::CardButton(CardWindow &parent, int Id, TCHAR *szText, UINT Style, bool visible,
int x, int y, int width, int height)
: parentWnd(parent), id(Id), fVisible(visible), uStyle(Style), ButtonCallback(0)
{
crText = RGB(255,255,255);
crBack = RGB(0, 128, 0);
xadjust = 0;
yadjust = 0;
xjustify = 0;
yjustify = 0;
fMouseDown = false;
fButtonDown = false;
hIcon = 0;
SetText(szText);
Move(x, y, width, height);
mxlock = CreateMutex(0, FALSE, 0);
hFont = 0;
}
CardButton::~CardButton()
{
CloseHandle(mxlock);
}
void CardButton::DrawRect(HDC hdc, RECT *rect, bool fNormal)
{
RECT fill;
HANDLE hOld;
HPEN hhi = CreatePen(0, 0, MAKE_PALETTERGB(crHighlight));
HPEN hsh = CreatePen(0, 0, MAKE_PALETTERGB(crShadow));
HPEN hbl = (HPEN)GetStockObject(BLACK_PEN);
int x = rect->left;
int y = rect->top;
int width = rect->right-rect->left - 1;
int height = rect->bottom-rect->top - 1;
SetRect(&fill, x+1, y+1, x+width-1, y+height-1);
int one = 1;
if(!fNormal)
{
x += width;
y += height;
width = -width;
height = -height;
one = -1;
OffsetRect(&fill, 1, 1);
}
if(fNormal)
hOld = SelectObject(hdc, hhi);
else
hOld = SelectObject(hdc, hhi);
MoveToEx(hdc, x, y+height, 0);
LineTo(hdc, x, y);
LineTo(hdc, x+width, y);
SelectObject(hdc, hOld);
hOld = SelectObject(hdc, hbl);
LineTo(hdc, x+width, y+height);
LineTo(hdc, x-one, y+height);
SelectObject(hdc, hOld);
hOld = SelectObject(hdc, hsh);
MoveToEx(hdc, x+one, y+height-one, 0);
LineTo(hdc, x+width-one, y+height-one);
LineTo(hdc, x+width-one, y);
SelectObject(hdc, hOld);
PaintRect(hdc, &fill, MAKE_PALETTERGB(crBack));
DeleteObject(hhi);
DeleteObject(hsh);
}
void CardButton::Clip(HDC hdc)
{
if(fVisible == false) return;
ExcludeClipRect(hdc, rect.left, rect.top, rect.right, rect.bottom);
}
void CardButton::Draw(HDC hdc, bool fNormal)
{
SIZE textsize;
int x, y; //text x, y
int ix, iy; //icon x, y
int iconwidth = 0;
RECT cliprect;
if(fVisible == 0) return;
if(hFont == 0)
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
else
SelectObject(hdc, hFont);
GetTextExtentPoint32(hdc, szText, lstrlen(szText), &textsize);
if(hIcon)
{
x = rect.left + 32 + 8;
}
else
{
if(uStyle & CB_ALIGN_LEFT)
{
x = rect.left + iconwidth;
}
else if(uStyle & CB_ALIGN_RIGHT)
{
x = rect.left + (rect.right-rect.left-iconwidth-textsize.cx);
}
else //centered
{
x = rect.right - rect.left - iconwidth;
x = (x - textsize.cx) / 2;
x += rect.left + iconwidth;
}
}
y = rect.bottom - rect.top;
y = (y - textsize.cy) / 2;
y += rect.top;
//calc icon position..
ix = rect.left + 4;
iy = rect.top + (rect.bottom-rect.top-32) / 2;
//if button is pressed, then shift text
if(fNormal == false && (uStyle & CB_PUSHBUTTON))
{
x += 1;
y += 1;
ix += 1;
iy += 1;
}
SetRect(&cliprect, x, y, x+textsize.cx, y+textsize.cy);
ExcludeClipRect(hdc, x, y, x+textsize.cx, y+textsize.cy);
//
// Calc icon pos
//
if(hIcon)
{
ExcludeClipRect(hdc, ix, iy, ix + 32, iy + 32);
}
if(uStyle & CB_PUSHBUTTON)
{
DrawRect(hdc, &rect, fNormal);
SetBkColor(hdc, MAKE_PALETTERGB(crBack));
SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText));
SelectClipRgn(hdc, 0);
ExtTextOut(hdc, x, y, ETO_OPAQUE, &cliprect, szText, lstrlen(szText), 0);
}
else
{
SetBkColor(hdc, MAKE_PALETTERGB(crBack));
SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText));
SelectClipRgn(hdc, 0);
ExtTextOut(hdc, x, y, ETO_OPAQUE, &rect, szText, lstrlen(szText), 0);
}
if(hIcon)
{
HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBack));
DrawIconEx(hdc, ix, iy, hIcon, 32, 32, 0, hbr, 0);
DeleteObject(hbr);
}
}
void CardButton::AdjustPosition(int winwidth, int winheight)
{
int width = rect.right-rect.left;
int height = rect.bottom-rect.top;
width = width & ~0x1;
switch(xjustify)
{
case CS_XJUST_NONE:
break;
case CS_XJUST_CENTER: //centered
rect.left = (winwidth - (width)) / 2;
rect.left += xadjust;
rect.right = rect.left+width;
break;
case CS_XJUST_RIGHT: //right-aligned
rect.left = winwidth - width;
rect.left += xadjust;
rect.right = rect.left+width;
break;
}
switch(yjustify)
{
case CS_YJUST_NONE:
break;
case CS_YJUST_CENTER: //centered
rect.top = (winheight - (height)) / 2;
rect.top += yadjust;
rect.bottom = rect.top+height;
break;
case CS_YJUST_BOTTOM: //right-aligned
rect.top = winheight - height;
rect.top += yadjust;
rect.bottom = rect.top+height;
break;
}
}
int CardButton::OnLButtonDown(HWND hwnd, int x, int y)
{
if((uStyle & CB_PUSHBUTTON) == 0)
return 0;
//make sure that the user is allowed to do something
if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)
{
return 0;
}
else
{
ReleaseMutex(mxlock);
}
fMouseDown = true;
fButtonDown = true;
Redraw();
SetCapture(hwnd);
return 1;
}
int CardButton::OnMouseMove(HWND hwnd, int x, int y)
{
if(fMouseDown)
{
bool fOldButtonDown = fButtonDown;
POINT pt;
pt.x = x;
pt.y = y;
if(PtInRect(&rect, pt))
fButtonDown = true;
else
fButtonDown = false;
if(fButtonDown != fOldButtonDown)
Redraw();
}
return 0;
}
int CardButton::OnLButtonUp(HWND hwnd, int x, int y)
{
if(fMouseDown)
{
fMouseDown = false;
fButtonDown = false;
if(uStyle & CB_PUSHBUTTON)
{
Redraw();
ReleaseCapture();
}
//if have clicked the button
if(parentWnd.CardButtonFromPoint(x, y) == this)
{
if(ButtonCallback)
{
ButtonCallback(*this);
}
else
{
HWND hwnd = (HWND)parentWnd;
SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(id, BN_CLICKED), (LONG)hwnd);
}
}
}
return 0;
}
#define _countof(array) (sizeof(array)/sizeof(array[0]))
CardButton *CardWindow::CreateButton(int id, TCHAR *szText, UINT uStyle, bool fVisible, int x, int y, int width, int height)
{
CardButton *cb;
if(nNumButtons == MAXBUTTONS)
return 0;
cb = new CardButton(*this, id, szText, uStyle, fVisible, x, y, width, height);
Buttons[nNumButtons++] = cb;
if(uStyle & CB_PUSHBUTTON)
{
cb->SetBackColor(CardButton::GetFace(crBackgnd));
//cb->SetBackColor(ScaleLumRGB(crBackgnd, 0.1));
cb->SetForeColor(RGB(255,255,255));
}
else
{
cb->SetBackColor(crBackgnd);
cb->SetForeColor(RGB(255,255,255));
}
return cb;
}
void CardButton::SetText(TCHAR *lpszFormat, ...)
{
int count;
va_list args;
va_start(args, lpszFormat);
count = wvsprintf(szText, lpszFormat, args);
va_end(args);
}
int CardButton::Id()
{
return id;
}
void CardButton::Show(bool fShow)
{
fVisible = fShow;
}
void CardButton::Move(int x, int y, int width, int height)
{
SetRect(&rect, x, y, x+width, y+height);
}
void CardButton::Redraw()
{
HDC hdc = GetDC((HWND)parentWnd);
HPALETTE hOldPal = UseNicePalette(hdc, __hPalette);
Draw(hdc, !fButtonDown);
RestorePalette(hdc, hOldPal);
ReleaseDC((HWND)parentWnd, hdc);
}
void CardButton::SetForeColor(COLORREF cr)
{
crText = cr;
}
void CardButton::SetBackColor(COLORREF cr)
{
crBack = cr;
crHighlight = GetHighlight(cr);
crShadow = GetShadow(cr);
//crHighlight = ScaleLumRGB(cr, +0.25);
//crShadow = ScaleLumRGB(cr, -0.25);
}
// Static member
COLORREF CardButton::GetHighlight(COLORREF crBase)
{
return ColorScaleRGB(crBase, RGB(255,255,255), 0.25);
}
// Static member
COLORREF CardButton::GetShadow(COLORREF crBase)
{
return ColorScaleRGB(crBase, RGB(0, 0, 0), 0.25);
}
COLORREF CardButton::GetFace(COLORREF crBase)
{
return ColorScaleRGB(crBase, RGB(255,255,255), 0.1);
}
void CardButton::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust)
{
xadjust = xAdjust;
yadjust = yAdjust;
xjustify = xJustify;
yjustify = yJustify;
}
void CardButton::SetIcon(HICON hicon, bool fRedraw)
{
hIcon = hicon;
if(fRedraw)
Redraw();
}
void CardButton::SetFont(HFONT font)
{
//don't delete the existing font..
hFont = font;
}
void CardButton::SetButtonProc(pButtonProc proc)
{
ButtonCallback = proc;
}
bool CardButton::Lock()
{
DWORD dw = WaitForSingleObject(mxlock, 0);
if(dw == WAIT_OBJECT_0)
return true;
else
return false;
}
bool CardButton::UnLock()
{
if(ReleaseMutex(mxlock))
return true;
else
return false;
}
void CardButton::SetStyle(UINT style)
{
uStyle = style;
}
UINT CardButton::GetStyle()
{
return uStyle;
}

View file

@ -0,0 +1,101 @@
#ifndef CARDBUTTON_INCLUDED
#define CARDBUTTON_INCLUDED
#define MAXBUTTONTEXT 64
#include "cardlib.h"
class CardButton
{
friend class CardWindow;
//
// Constructor is PRIVATE - only a
// CardWindow can create buttons!
//
CardButton(CardWindow &parent, int id, TCHAR *szText, UINT style, bool visible,
int x, int y, int width, int height);
~CardButton();
public:
void SetStyle(UINT uStyle);
UINT GetStyle();
void SetText(TCHAR *fmt, ...);
void SetFont(HFONT font);
void SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust);
void SetForeColor(COLORREF cr);
void SetBackColor(COLORREF cr);
void Move(int x, int y, int width, int height);
void Show(bool fShow);
void Redraw();
int Id();
void SetIcon(HICON hicon, bool fRedraw);
void SetButtonProc(pButtonProc proc);
CardWindow &GetCardWindow() { return parentWnd; }
bool Lock();
bool UnLock();
static COLORREF GetHighlight(COLORREF crBase);
static COLORREF GetShadow(COLORREF crBase);
static COLORREF GetFace(COLORREF crBase);
private:
//
// Private member functions
//
void AdjustPosition(int winwidth, int winheight);
void DrawRect(HDC hdc, RECT *rect, bool fNormal);
void Draw(HDC hdc, bool fNormal);
void Clip(HDC hdc);
int OnLButtonDown(HWND hwnd, int x, int y);
int OnMouseMove(HWND hwnd, int x, int y);
int OnLButtonUp(HWND hwnd, int x, int y);
//
// Private members
//
CardWindow &parentWnd;
RECT rect;
int id;
UINT uStyle;
bool fVisible;
int xadjust;
int xjustify;
int yadjust;
int yjustify;
HICON hIcon;
HFONT hFont;
TCHAR szText[MAXBUTTONTEXT];
COLORREF crBack;
COLORREF crText;
COLORREF crHighlight;
COLORREF crShadow;
COLORREF crShadow2;
bool fMouseDown;
bool fButtonDown;
HANDLE mxlock;
pButtonProc ButtonCallback;
};
#endif

View file

@ -0,0 +1,353 @@
//
// Colour support
//
#include <windows.h>
#define MakeRGB RGB
#define MIN3(a,b,c) ( (a)<=(b) ? (a)<=(c)?(a):(c) : (b)<=(c)?(b):(c) )
#define MAX3(a,b,c) ( (a)>=(b) ? (a)>=(c)?(a):(c) : (b)>=(c)?(b):(c) )
inline double fMax(double a, double b)
{
return a < b ? b : a;
}
inline double fMin(double a, double b)
{
return a < b ? a : b;
}
/******************************************************************************
FUNCTION: RGBtoHLS
PURPOSE: Convert from RGB to HLS
IN: RGB color (0xBBGGRR)
OUT: Hue, Saturation, Luminance from 0 to 1
COPYRIGHT:1995-1997 Robert Mashlan
Modified for LabWindows/CVI, 1999 Guillaume Dargaud
******************************************************************************/
void RGBtoHLS(const COLORREF rgb, double *H, double *L, double *S )
{
double delta;
double r = (double)((rgb )&0xFF)/255;
double g = (double)((rgb>> 8)&0xFF)/255;
double b = (double)((rgb>>16)&0xFF)/255;
double cmax = MAX3(r,g,b);
double cmin = MIN3(r,g,b);
*L=(cmax+cmin)/2.0;
if(cmax == cmin)
{
*S = *H = 0; // it's really undefined
}
else
{
if(*L < 0.5) *S = (cmax-cmin)/(cmax+cmin);
else *S = (cmax-cmin)/(2.0-cmax-cmin);
delta = cmax - cmin;
if(r == cmax)
{
*H = (g - b) / delta;
}
else
{
if(g == cmax) *H = 2.0 + (b-r) / delta;
else *H = 4.0 + (r-g) / delta;
}
*H /= 6.0;
if (*H < 0.0) *H += 1;
}
}
/******************************************************************************
FUNCTION: HueToRGB
PURPOSE: Convert a hue (color) to RGB
COPYRIGHT:1995-1997 Robert Mashlan
Modified for LabWindows/CVI, 1999 Guillaume Dargaud
******************************************************************************/
double HueToRGB(const double m1, const double m2, double h )
{
if (h<0) h+=1.0;
if (h>1) h-=1.0;
if (6.0*h < 1 ) return (m1+(m2-m1)*h*6.0);
if (2.0*h < 1 ) return m2;
if (3.0*h < 2.0) return (m1+(m2-m1)*((2.0/3.0)-h)*6.0);
return m1;
}
/******************************************************************************
FUNCTION: HLStoRGB
PURPOSE: Convert from HSL to RGB
IN: Hue, Saturation, Luminance from 0 to 1
RETURN: RGB color (0xBBGGRR)
COPYRIGHT:1995-1997 Robert Mashlan
Modified for LabWindows/CVI, 1999 Guillaume Dargaud
******************************************************************************/
COLORREF HLStoRGB(const double H, const double L, const double S )
{
double r,g,b;
double m1, m2;
if(S == 0)
{
r = g = b = L;
}
else
{
if (L <= 0.5)
m2 = L * (1.0 + S);
else
m2 = L + S - L * S;
m1 = 2.0 * L - m2;
r = HueToRGB(m1,m2,H+1.0/3.0);
g = HueToRGB(m1,m2,H);
b = HueToRGB(m1,m2,H-1.0/3.0);
}
return RGB(r*255, g*255, b*255);
}
/******************************************************************************
FUNCTION: ColorScaleHSL
PURPOSE: Returns the HSL linear interpolated color between 2 colors
(more natural looking than RGB interpolation)
For instance if the luminance is the same in Col1 and Col2,
then the luminance of the result will be the same
If Ratio=0, you get Col1,
If Ratio=1, you get Col2
IN: Col1: low color in hex 0xBBGGRR format
Col2: high color in hex 0xBBGGRR format
Ratio: 0 for low color, 1 for high color, or in between
EXAMPLE: Col1=0, Col2=0xFF00FF, Ratio=0.5 returns 0x1F5F3F
******************************************************************************/
COLORREF ColorScaleHSL( const COLORREF Col1, const COLORREF Col2, const double Ratio)
{
static double H1, H2, S1, S2, L1, L2;
if (Ratio<=0) return Col1; // Ratio parameter must be between 0 and 1
else if (Ratio>=1) return Col2;
RGBtoHLS( Col1, &H1, &L1, &S1);
RGBtoHLS( Col2, &H2, &L2, &S2);
return HLStoRGB( H1+(H2-H1)*Ratio, L1+(L2-L1)*Ratio, S1+(S2-S1)*Ratio );
}
/******************************************************************************
FUNCTION: ColorScaleRGB
PURPOSE: Returns the RGB linear interpolated color between 2 colors
If Ratio=0, you get Col1,
If Ratio=1, you get Col2
IN: Col1: low color in hex 0xBBGGRR format
Col2: high color in hex 0xBBGGRR format
Ratio: 0 for low color, 1 for high color, or in between
EXAMPLE: Col1=0, Col2=0xFF00FF, Ratio=0.5 returns 0x800080
******************************************************************************/
COLORREF ColorScaleRGB( const COLORREF Col1,
const COLORREF Col2,
const double Ratio) {
int R1=(Col1)&0xFF, G1=(Col1>>8)&0xFF, B1=(Col1>>16)&0xFF;
int R2=(Col2)&0xFF, G2=(Col2>>8)&0xFF, B2=(Col2>>16)&0xFF;
if (Ratio<=0) return Col1; // Ratio parameter must be between 0 and 1
else if (Ratio>=1) return Col2;
/* return RGB(
(R1 + (R2 - R1) * (Ratio + 0.02) + 0.5), // rounding
(G1 + (G2 - G1) * (Ratio - 0.00) + 0.5),
(B1 + (B2 - B1) * (Ratio + 0.05) + 0.5)
);*/
/*double r = Ratio;
if(Col2 == 0)
r = 1-Ratio;
else
r = 1+Ratio;
R1 = (int)(double(R1) * r + 0.5);
G1 = (int)(double(G1) * r + 0.5);
B1 = (int)(double(B1) * r + 0.5);
return RGB(R1,G1,B1);*/
return RGB(
(R1 + (R2 - R1) * (Ratio + 0.02) + 0.5), // rounding
(G1 + (G2 - G1) * (Ratio - 0.00) + 0.5),
(B1 + (B2 - B1) * (Ratio + 0.05) + 0.5)
);
}
COLORREF ColorDarker(COLORREF col, double ratio)
{
static double Hue, Lum, Sat;
//RGBtoHLS(col, &Hue, &Lum, &Sat);
//col = HLStoRGB(Hue, fMax(0.0,Lum-ratio), Sat);
return ColorScaleHSL(col, RGB(0,0,0), ratio);
//return col;
}
COLORREF ColorLighter(COLORREF col, double ratio)
{
static double Hue, Lum, Sat;
//RGBtoHLS(col, &Hue, &Lum, &Sat);
//col = HLStoRGB(Hue, fMin(1.0,Lum+ratio), Sat);
return ColorScaleHSL(col, RGB(255,255,255), ratio);
//return col;
}
//
// Experimental!!!
//
#if 0
typedef enum { Red, Green, Blue };
void RGBtoHLS(COLORREF rgb, double *Hue, double *Lum, double *Sat)
{
double mn, mx;
int major;
BYTE red, green, blue;
red = GetRValue(rgb);
green = GetGValue(rgb);
blue = GetBValue(rgb);
if(red < green)
{
mn = red; mx = green; major = Green;
}
else
{
mn = green; mx = red; major = Red;
}
if(blue < mn)
{
mn = blue;
}
else if(blue > mx)
{
mx = blue; major = Blue;
}
if(mn == mx)
{
*Lum = mn / 255;
*Sat = 0;
*Hue = 0;
}
else
{
*Lum = (mx + mn) / 510;
if(*Lum <= 0.5)
*Sat = (mx-mn) / (mn+mx);
else
*Sat = (mx-mn) / (510-mn-mx);
switch(major)
{
case Red: *Hue = (green-blue) * 60.0 / (mx-mn) + 360.0;
break;
case Green: *Hue = (blue-red) * 60.0 / (mx-mn) + 120.0;
break;
case Blue: *Hue = (red-green) * 60.0 / (mx-mn) + 240.0;
break;
}
if(*Hue > 360.0)
*Hue -= 360.0;
}
}
static BYTE Value(double m1, double m2, double hue)
{
if(hue > 360) hue -= 360;
else if(hue < 0) hue += 360;
if(hue < 60)
m1 = m1 + (m2 - m1) * hue / 60;
else if(hue < 180)
m1 = m2;
else if(hue < 240)
m1 = m1 + (m2 - m1) * (240 - hue) / 60;
return (BYTE)(m1 * 255);
}
COLORREF HLStoRGB(const double Hue, const double Lum, const double Sat)
{
BYTE red, green, blue;
if(Sat == 0)
{
red = green = blue = (BYTE)(Lum * 255);
}
else
{
double m1, m2;
if(Lum <= 0.5)
m2 = Lum + Lum * Sat;
else
m2 = Lum + Sat - Lum * Sat;
m1 = 2 * Lum - m2;
red = Value(m1, m2, Hue + 120);
green = Value(m1, m2, Hue);
blue = Value(m1, m2, Hue - 120);
}
return RGB(red, green, blue);
}
COLORREF ScaleLumRGB(COLORREF col1, double ratio)
{
double H1, L1, S1;
RGBtoHLS(col1, &H1, &L1, &S1);
L1 += L1 * ratio;
return HLStoRGB(H1, L1, S1);
}
COLORREF ColorScaleHSL(const COLORREF Col1, const COLORREF Col2, const double Ratio)
{
static double H1, H2, S1, S2, L1, L2;
if(Ratio <= 0) return Col1; // Ratio parameter must be between 0 and 1
else if(Ratio >= 1) return Col2;
RGBtoHLS( Col1, &H1, &L1, &S1);
RGBtoHLS( Col2, &H2, &L2, &S2);
return HLStoRGB( H1 /*+ (H2 - H1 ) * Ratio*/, L1 + (L2 - L1) * Ratio, S1 + (S2 - S1) * Ratio * 2);
}
COLORREF ColorScaleRGB(const COLORREF Col1, const COLORREF Col2, const double Ratio)
{
return ColorScaleHSL(Col1, Col2, Ratio);
}
#endif

View file

@ -0,0 +1,16 @@
COLORREF ColorScaleRGB( const COLORREF Col1,
const COLORREF Col2,
const double Ratio);
COLORREF ColorScaleHSL( const COLORREF Col1,
const COLORREF Col2,
const double Ratio);
COLORREF ColorDarker(COLORREF col, double ratio);
COLORREF ColorLighter(COLORREF col, double ratio);
COLORREF ScaleLumRGB(COLORREF col1, double ratio);
#define MAKE_PALETTERGB(colref) (0x02000000 | colref)

View file

@ -0,0 +1,90 @@
//
// CardCount is a helper library for CardStacks.
//
// When you initialize a CardCount object with a
// cardstack, it keeps track of the number of cards
// the stack contains.
//
// e.g. CardCount count(cardstack);
//
// Then you can do:
//
// int num_fives = count[5]
//
// count.Add(cardstack2); - combine with another stack
//
// int num_aces = count[1] - aces low
// int num_aces = count[14] - aces high
//
// count.Clear();
//
#include "cardcount.h"
CardCount::CardCount()
{
Clear();
}
CardCount::CardCount(const CardStack &cs)
{
Init(cs);
}
void CardCount::Clear()
{
for(int i = 0; i < 13; i++)
count[i] = 0;
}
void CardCount::Add(const CardStack &cs)
{
for(int i = 0; i < cs.NumCards(); i++)
{
Card card = cs[i];
int val = card.LoVal();
count[val - 1]++;
}
}
void CardCount::Sub(const CardStack &cs)
{
for(int i = 0; i < cs.NumCards(); i++)
{
Card card = cs[i];
int val = card.LoVal();
if(count[val - 1] > 0)
count[val - 1]--;
}
}
void CardCount::Init(const CardStack &cs)
{
Clear();
Add(cs);
}
int CardCount::operator [] (size_t index) const
{
if(index < 1) return 0;
else if(index > 14) return 0; //if out of range
else if(index == 14) index = 1; //if a "ace-high"
return count[index - 1];
}
//
// Decrement specified item by one
//
void CardCount::Dec(size_t index)
{
if(index < 1) return;
else if(index > 14) return; //if out of range
else if(index == 14) index = 1; //if a "ace-high"
index -= 1;
if(count[index] > 0)
count[index]--;
}

View file

@ -0,0 +1,31 @@
#ifndef _CARDCOUNT_INCLUDED
#define _CARDCOUNT_INCLUDED
#include <windows.h>
#include "cardstack.h"
class CardCount
{
public:
CardCount();
CardCount(const CardStack &cs);
void Init(const CardStack &cs);
void Clear();
void Add(const CardStack &cs);
void Sub(const CardStack &cs);
void Dec(size_t index);
int operator[] (size_t index) const;
CardCount &operator = (const CardStack &cs);
CardCount &operator += (const CardStack &cs);
private:
int count[13]; //13 different card values
//(ace,2,3,4,5,6,7,8,9,10,J,Q,K)
};
#endif

View file

@ -0,0 +1,122 @@
//
// CardLib - not much of interest in here
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include "cardlib.h"
#include "globals.h"
void LoadCardBitmaps(void);
static bool __CARDLIB_ACES_HIGH = false;
extern double __CARDZOOMSPEED;
//
// Global variables!
//
HDC __hdcCardBitmaps;
HBITMAP __hbmCardBitmaps;
HDC __hdcPlaceHolder;
HBITMAP __hbmPlaceHolder;
HPALETTE __holdplacepal;
int __cardwidth;
int __cardheight;
HPALETTE __hPalette;
//
// Cardlib global functions!
//
void CardLib_SetZoomSpeed(int speed)
{
__CARDZOOMSPEED = (double)speed;
}
/*
It's dangerous to use these operators, because of all
the implicit conversions that could take place, which
would have unpredicted side-effects.
e.g. Card card(Hearts, 4);
if(card == 4) - how does 4 get converted??
It uses the Card(int uval) constructor,
which results in a 2 of clubs...
not what was expected
*/
/*
void CardLib_SetAcesHigh(bool fHigh);
bool operator != (const Card &lhs, const Card &rhs);
bool operator == (const Card &lhs, const Card &rhs);
bool operator < (const Card &lhs, const Card &rhs);
bool operator <= (const Card &lhs, const Card &rhs);
bool operator > (const Card &lhs, const Card &rhs);
bool operator >= (const Card &lhs, const Card &rhs);
*/
/*
void CardLib_SetAcesHigh(bool fHigh)
{
__CARDLIB_ACES_HIGH = fHigh;
}
bool operator == (const Card &lhs, const Card &rhs)
{
if(__CARDLIB_ACES_HIGH)
return lhs.HiVal() == rhs.HiVal();
else
return lhs.LoVal() == rhs.LoVal();
}
bool operator != (const Card &lhs, const Card &rhs)
{
if(__CARDLIB_ACES_HIGH)
return lhs.HiVal() != rhs.HiVal();
else
return lhs.LoVal() != rhs.LoVal();
}
bool operator > (const Card &lhs, const Card &rhs)
{
if(__CARDLIB_ACES_HIGH)
return lhs.HiVal() > rhs.HiVal();
else
return lhs.LoVal() > rhs.LoVal();
}
bool operator >= (const Card &lhs, const Card &rhs)
{
if(__CARDLIB_ACES_HIGH)
return lhs.HiVal() >= rhs.HiVal();
else
return lhs.LoVal() >= rhs.LoVal();
}
bool operator < (const Card &lhs, const Card &rhs)
{
if(__CARDLIB_ACES_HIGH)
return lhs.HiVal() < rhs.HiVal();
else
return lhs.LoVal() < rhs.LoVal();
}
bool operator <= (const Card &lhs, const Card &rhs)
{
if(__CARDLIB_ACES_HIGH)
return lhs.HiVal() <= rhs.HiVal();
else
return lhs.LoVal() <= rhs.LoVal();
}
*/
void PaintRect(HDC hdc, RECT *rect, COLORREF colour)
{
COLORREF oldcr = SetBkColor(hdc, colour);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, rect, "", 0, 0);
SetBkColor(hdc, oldcr);
}

View file

@ -0,0 +1,101 @@
#ifndef CARDLIB_INCLUDED
#define CARDLIB_INCLUDED
#define CARDLIBPROC __stdcall
void CardBlt(HDC hdc, int x, int y, int nCardNum);
void CardLib_SetZoomSpeed(int);
#define CS_EI_NONE 0
#define CS_EI_SUNK 1
#define CS_DEFXOFF 12 //x-offset
#define CS_DEFYOFF 18 //y-offset
#define CS_NO3D 1 //default 3d counts (recommened)
#define CS_DEF3D 10 //(best for decks)
//#define CS_EI_CIRC 2
//#define CS_EI_X 3
#define CS_DRAG_NONE 0
#define CS_DRAG_TOP 1
#define CS_DRAG_ALL 2
#define CS_DRAG_CALLBACK 3
#define CS_DROP_NONE 0
#define CS_DROP_ALL 1
#define CS_DROP_CALLBACK 2
#define CS_XJUST_NONE 0
#define CS_XJUST_RIGHT 1
#define CS_XJUST_CENTER 2
#define CS_YJUST_NONE 0
#define CS_YJUST_BOTTOM 1
#define CS_YJUST_CENTER 2
#define CB_STATIC 0 //static text label
#define CB_PUSHBUTTON 1 //normal button
#define CB_ALIGN_CENTER 0 //centered is default
#define CB_ALIGN_LEFT 2
#define CB_ALIGN_RIGHT 4
#define CS_FACE_UP 0 //all cards face-up
#define CS_FACE_DOWN 1 //all cards face-down
#define CS_FACE_DOWNUP 2 //bottom X cards down, top-most face-up
#define CS_FACE_UPDOWN 3 //bottom X cards up, top-most face-down
#define CS_FACE_ANY 4 //cards can be any orientation
#define CS_DROPZONE_NODROP -1
//
// Define the standard card-back indices
//
#define ecbCROSSHATCH 53
#define ecbWEAVE1 54
#define ecbWEAVE2 55
#define ecbROBOT 56
#define ecbFLOWERS 57
#define ecbVINE1 58
#define ecbVINE2 59
#define ecbFISH1 60
#define ecbFISH2 61
#define ecbSHELLS 62
#define ecbCASTLE 63
#define ecbISLAND 64
#define ecbCARDHAND 65
#define ecbUNUSED 66
#define ecbTHE_X 67
#define ecbTHE_O 68
class CardRegion;
class CardButton;
class CardStack;
typedef bool (CARDLIBPROC *pCanDragProc) (CardRegion &stackobj, int iNumDragging);
typedef bool (CARDLIBPROC *pCanDropProc) (CardRegion &stackobj, const CardStack &cards);
typedef void (CARDLIBPROC *pClickProc) (CardRegion &stackobj, int iNumCards);
typedef void (CARDLIBPROC *pAddProc) (CardRegion &stackobj, const CardStack &cards);
typedef void (CARDLIBPROC *pRemoveProc) (CardRegion &stackobj, int iNumRemoved);
typedef void (CARDLIBPROC *pResizeWndProc) (int width, int height);
typedef int (CARDLIBPROC *pDropZoneProc) (int dzid, const CardStack &cards);
typedef void (CARDLIBPROC *pButtonProc) (CardButton &pButton);
#include "card.h"
#include "cardbutton.h"
#include "cardstack.h"
#include "cardregion.h"
#include "cardcount.h"
#include "cardwindow.h"
#ifdef _DEBUG
typedef bool (CARDLIBPROC *pDebugClickProc) (CardRegion &stackobj);
void CardLib_SetStackClickProc(pDebugClickProc proc);
#endif
#endif

View file

@ -0,0 +1,658 @@
//
// 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)
: parentWnd(parent), id(Id), fVisible(visible), xpos(x), ypos(y), xoffset(xOffset), yoffset(yOffset)
{
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 = -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 != -1)
{
KillTimer((HWND)parentWnd, uFlashTimer);
nFlashCount = 0;
uFlashTimer = -1;
fFlashVisible = true;
}
}
void CardRegion::DoFlash()
{
if(uFlashTimer != -1)
{
fFlashVisible = !fFlashVisible;
if(--nFlashCount == 0)
{
KillTimer((HWND)parentWnd, uFlashTimer);
uFlashTimer = -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;
}

View file

@ -0,0 +1,216 @@
#ifndef CARDREGION_INCLUDED
#define CARDREGION_INCLUDED
#include "globals.h"
#include "cardstack.h"
#include "cardlib.h"
class CardWindow;
//
// This class defines a physical card-stack,
// which draws the cards, supports
//
class CardRegion
{
friend class CardWindow;
friend class CardStack;
//
// Constructor is PRIVATE - only
// a CardWindow can create cardstacks!
//
CardRegion(CardWindow &parent, int id, bool fVisible,
int x, int y, int xOffset, int yOffset);
~CardRegion();
public:
void SetBackColor(COLORREF cr);
void SetCardStack(const CardStack &cs);
const CardStack & GetCardStack();
//
// Event-callback support
//
bool SetDragRule(UINT uDragType, pCanDragProc proc = 0);
bool SetDropRule(UINT uDropType, pCanDropProc proc = 0);
void SetClickProc (pClickProc proc);
void SetDblClickProc (pClickProc proc);
void SetAddCardProc (pAddProc proc);
void SetRemoveCardProc (pRemoveProc proc);
//
// Physical attribute support
//
bool SetThreedCount (int count);
void SetOffsets (int x, int y);
void SetPos (int x, int y);
void Show (bool fShow);
bool IsVisible ();
void SetEmptyImage (UINT uImage);
void SetBackCardIdx (UINT uBackIdx);
void SetPlacement (UINT xJustify, UINT yJustify, int xAdjust, int yAdjust);
void Update();
void Redraw();
void SetFaceDirection(UINT uDirType, int nOption);
UINT GetFaceDirection(int *pnOption);
void Flash(int count, int timeout);
void StopFlash();
int Id();
CardWindow &GetCardWindow() { return parentWnd; }
bool PlayCard(CardRegion *pDestStack, int value, int num);
bool MoveCard(CardRegion *pDestStack, int nNumCards, bool fAnimate);
bool SimulateDrag(CardRegion *pDestStack, int nNumCards, bool fAnimate);
bool Lock();
bool UnLock();
//
// Common wrappers for the CardStack object
//
int NumCards() const;
void NewDeck() { cardstack.NewDeck(); }
void Shuffle() { cardstack.Shuffle(); }
void Clear() { cardstack.Clear(); }
void Reverse() { cardstack.Reverse(); }
void Push(const Card card) { cardstack.Push(card); }
void Push(const CardStack &cs) { cardstack.Push(cs); }
Card Pop() { return cardstack.Pop(); }
CardStack Pop(int items) { return cardstack.Pop(items); }
Card Top() { return cardstack.Top(); }
CardStack Top(int items) { return cardstack.Top(items); }
private:
void DoFlash();
void RedrawIfNotDim(CardRegion *compare, bool fFullRedraw);
void UpdateFaceDir(CardStack &cards);
void Clip(HDC hdc);
void Render(HDC hdc);
int GetOverlapRatio(int x, int y, int width, int height);
void MoveDragCardTo(HDC hdc, int x, int y);
void ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *dest);
void RenderBottomMost(HDC hdc, int minustopmost = 0);
void PrepareDragBitmaps(int numtodrag);
void PrepareDragBitmapsThreed(int numtodrag);
void ReleaseDragBitmaps(void);
bool CanDragCards(int iNumCards);
bool CanDropCards(CardStack &cards);
void CalcApparentCards();
int CalcApparentCards(int realnum);
void UpdateSize();
void AdjustPosition(int winwidth, int winheight);
bool IsPointInStack(int x, int y);
int GetNumDragCards(int x, int y);
bool OnLButtonDown(int x, int y);
bool OnLButtonDblClk(int x, int y);
bool OnMouseMove(int x, int y);
bool OnLButtonUp(int x, int y);
//
// Private data members
//
int id;
CardWindow &parentWnd;
CardStack cardstack; //cards in this stack
CardStack dragstack; //cards which we might be dragging
bool fMouseDragging;
int xoffset; //direction that cards take
int yoffset;
int xpos; //coordinates of stack
int ypos;
int width; //stack-size of all cards
int height;
//
// justify / placement vars
int xjustify;
int yjustify;
int xadjust;
int yadjust;
//
// Used for mouse-dragging / moving cards
//
int iNumDragCards;
int mousexoffset;
int mouseyoffset;
int oldx;
int oldy;
int nDragCardWidth;
int nDragCardHeight;
HDC hdcBackGnd;
HBITMAP hbmBackGnd;
HDC hdcDragCard;
HBITMAP hbmDragCard;
int nNumApparentCards;
int nThreedCount;
bool fVisible;
int nFlashCount;
bool fFlashVisible;
UINT uFlashTimer;
COLORREF crBackgnd;
UINT uEmptyImage;
UINT uFaceDirType;
int nFaceDirOption;
int nBackCardIdx;
UINT uDragRule;
UINT uDropRule;
//
// Stack callback support
//
pCanDragProc CanDragCallback;
pCanDropProc CanDropCallback;
pClickProc ClickCallback;
pClickProc DblClickCallback;
pAddProc AddCallback;
pRemoveProc RemoveCallback;
//locking mechanism to prevent user dragging etc
HANDLE mxlock;
};
#endif

View file

@ -0,0 +1,613 @@
//
// CardLib - CardRegion drawing support
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include "cardlib.h"
#include "cardregion.h"
#include "cardcolor.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: //case CS_EI_CIRC: case CS_EI_X:
DrawCard(hdc, x, y, __hdcPlaceHolder, __cardwidth, __cardheight);
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;
}
}
//
// 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;
}
}
//
// 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);
}

View file

@ -0,0 +1,618 @@
//
// CardLib - CardRegion mouse-related stuff
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <math.h>
#include "cardlib.h"
#include "cardwindow.h"
#include "cardregion.h"
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
//
if(pDestStack && pDestStack->CanDropCards(dragstack))
{
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);
}
//
// Otherwise, let the cards snap back onto this stack
//
else
{
hdc = GetDC((HWND)parentWnd);
ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this);
cardstack += dragstack;
ReleaseDC((HWND)parentWnd, hdc);
Update(); //Update this stack's card count + size
}
ReleaseDragBitmaps();
ReleaseCapture();
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)
{
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;
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);
}
}
#endif

View file

@ -0,0 +1,618 @@
//
// CardLib - CardRegion mouse-related stuff
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <math.h>
#include "cardlib.h"
#include "cardwindow.h"
#include "cardregion.h"
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
//
if(pDestStack && pDestStack->CanDropCards(dragstack))
{
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);
}
//
// Otherwise, let the cards snap back onto this stack
//
else
{
hdc = GetDC((HWND)parentWnd);
ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this);
cardstack += dragstack;
ReleaseDC((HWND)parentWnd, hdc);
Update(); //Update this stack's card count + size
}
ReleaseDragBitmaps();
ReleaseCapture();
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)
{
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;
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);
}
}
#endif

View file

@ -0,0 +1,237 @@
//
// CardLib - CardStack class
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <stdlib.h>
#include "cardstack.h"
Card &CardStack::operator[] (size_t index)
{
if(index >= (size_t)nNumCards) index = nNumCards - 1;
return cardlist[nNumCards - index - 1];
}
const Card &CardStack::operator[] (size_t index) const
{
if(index >= (size_t)nNumCards) index = nNumCards - 1;
return cardlist[nNumCards - index - 1];
}
// Subscripting operator for a constant sequence
//
/*Card CardStack::operator[] (size_t index) const
{
return cardlist[index];
}*/
//
// Subscripting operator for a non-const sequence
//
/*CardStack::ref CardStack::operator[] (size_t index)
{
return ref(this, index);
}*/
void CardStack::Clear()
{
nNumCards = 0;
}
void CardStack::NewDeck()
{
nNumCards = 52;
for(int i = 0; i < 52; i++)
cardlist[i].nValue = i;
}
void CardStack::Shuffle()
{
int src, dest;
Card temp;
//shuffle 8 times..
for(int i = 0; i < 8; i++)
for(dest = nNumCards - 1; dest > 0; dest--)
{
//want to do this:
// bad: src = rand() % (dest + 1)
// good: src = rand() / (RAND_MAX / (dest+1) + 1)
//positions from 0 to dest
src = rand() / (RAND_MAX / (dest+1) + 1);
//swap the cards
temp = cardlist[src];
cardlist[src] = cardlist[dest];
cardlist[dest] = temp;
}
}
void CardStack::Reverse()
{
for(int i = 0; i < nNumCards / 2; i++)
{
Card temp = cardlist[i];
cardlist[i] = cardlist[nNumCards - i - 1];
cardlist[nNumCards - i - 1] = temp;
}
}
void CardStack::Push(const Card card)
{
if(nNumCards < MAX_CARDSTACK_SIZE)
cardlist[nNumCards++] = card;
}
void CardStack::Push(const CardStack &cardstack)
{
if(nNumCards + cardstack.nNumCards < MAX_CARDSTACK_SIZE)
{
int num = cardstack.NumCards();
for(int i = 0; i < num; i++)
cardlist[nNumCards++] = cardstack.cardlist[i];
}
}
CardStack& CardStack::operator += (Card card)
{
Push(card);
return *this;
}
CardStack& CardStack::operator += (CardStack &cs)
{
Push(cs);
return *this;
}
CardStack CardStack::operator + (Card card)
{
CardStack poo = *this;
poo.Push(card);
return poo;
}
CardStack CardStack::operator + (CardStack &cs)
{
CardStack poo = *this;
poo.Push(cs);
return poo;
}
Card CardStack::Pop()
{
if(nNumCards > 0)
return cardlist[--nNumCards];
else
return 0;
}
CardStack CardStack::Pop(int items)
{
if(items <= nNumCards && nNumCards > 0)
{
CardStack cs(*this, nNumCards - items);
nNumCards -= items;
return cs;
}
else
{
return CardStack();
}
}
Card CardStack::Top()
{
if(nNumCards > 0)
return cardlist[nNumCards - 1];
else
return 0;
}
CardStack CardStack::Top(int items)
{
if(items <= nNumCards && nNumCards > 0)
{
return CardStack (*this, nNumCards - items);
}
else
{
return CardStack();
}
}
Card CardStack::RemoveCard(size_t index)
{
if(nNumCards == 0 || index >= (size_t)nNumCards)
return 0;
//put index into reverse range..
index = nNumCards - index - 1;
Card temp = cardlist[index];
nNumCards--;
for(size_t i = index; i < (size_t)nNumCards; i++)
{
cardlist[i] = cardlist[i+1];
}
return temp;
}
void CardStack::InsertCard(size_t index, Card card)
{
if(nNumCards == MAX_CARDSTACK_SIZE)
return;
if(index > (size_t)nNumCards)
return;
if((size_t)nNumCards == index)
{
cardlist[nNumCards] = card;
nNumCards++;
return;
}
//put index into reverse range..
index = nNumCards - index - 1;
nNumCards++;
//make room for the card
for(size_t i = nNumCards; i > index; i--)
{
cardlist[i] = cardlist[i - 1];
}
cardlist[index] = card;
}
void CardStack::Print()
{
// for(int i = 0; i < nNumCards; i++)
// cout << cardlist[i].HiVal() << " ";
}
CardStack::CardStack(CardStack &copythis, size_t fromindex)
{
nNumCards = copythis.nNumCards - fromindex;
for(int i = 0; i < nNumCards; i++)
cardlist[i] = copythis.cardlist[fromindex + i];
}

View file

@ -0,0 +1,53 @@
#ifndef CARDSTACK_INCLUDED
#define CARDSTACK_INCLUDED
#include "card.h"
#define MAX_CARDSTACK_SIZE 128
class CardStack
{
friend class CardRegion;
public:
CardStack() : nNumCards(0) { }
void NewDeck();
int NumCards() const { return nNumCards; }
void Shuffle();
void Clear();
void Reverse();
void Push(const Card card);
void Push(const CardStack &cardstack);
Card Pop();
CardStack Pop(int items);
Card Top();
CardStack Top(int items);
void Print();
Card RemoveCard(size_t index);
void InsertCard(size_t index, Card card);
//subscript capability!!
Card & operator[] (size_t index);
const Card & operator[] (size_t index) const;
CardStack &operator += (Card card);
CardStack &operator += (CardStack &cs);
CardStack operator + (Card card);
CardStack operator + (CardStack &cs);
private:
CardStack(CardStack &copythis, size_t fromindex);
Card cardlist[MAX_CARDSTACK_SIZE];
int nNumCards;
};
#endif

View file

@ -0,0 +1,812 @@
//
// 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;
int xpos = 10;
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);
}

View file

@ -0,0 +1,119 @@
#ifndef CARDBOARD_INCLUDED
#define CARDBOARD_INCLUDED
#define MAXBUTTONS 32
#define MAXCARDSTACKS 32
#define MAXDROPZONES 8
#include "dropzone.h"
#include "cardlib.h"
class CardRegion;
class CardButton;
LRESULT CALLBACK CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
class CardWindow
{
friend class CardRegion;
friend class CardButton;
friend void RegisterCardWindow();
public:
CardWindow();
~CardWindow();
//
// Basic windowing support
//
BOOL Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height);
BOOL Destroy();
operator HWND() { return m_hWnd; }
CardButton *CreateButton (int id, TCHAR *szText, UINT uStyle, bool fVisible, int x, int y, int width, int height);
CardRegion *CreateRegion (int id, bool fVisible, int x, int y, int xoffset, int yoffset);
CardButton *CardButtonFromId(int id);
CardRegion *CardRegionFromId(int id);
bool DeleteButton(CardButton *pButton);
bool DeleteRegion(CardRegion *pRegion);
bool DeleteAll();
void SetBackColor(COLORREF cr);
COLORREF GetBackColor();
void SetBackCardIdx(UINT uBackIdx);
void SetBackImage(HBITMAP hBitmap);
void EmptyStacks(void);
void Redraw(void);
void Update(void);
bool DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX);
void SetResizeProc(pResizeWndProc proc);
int GetWidth() { return nWidth; }
int GetHeight() { return nHeight; }
//
// Dropzone support
//
bool RegisterDropZone(int id, RECT *rect, pDropZoneProc proc);
bool DeleteDropZone(int id);
private:
int GetNumDropZones() { return nNumDropZones; }
DropZone* GetDropZoneFromRect(RECT *rect);
//
// Window procedure - don't call
//
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
//
// Private functions
//
void Paint(HDC hdc);
void PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy);
HPALETTE CreateCardPalette();
CardButton *CardButtonFromPoint(int x, int y);
CardRegion *CardRegionFromPoint(int x, int y);
CardRegion *GetBestStack(int x, int y, int w, int h);
//
// Private members
//
HWND m_hWnd; //window handle!
int nWidth, nHeight;
UINT nBackCardIdx; //all stacks share this card index by default
HBITMAP hbmBackImage;
HDC hdcBackImage;
CardButton * Buttons[MAXBUTTONS];
int nNumButtons;
CardRegion * Regions[MAXCARDSTACKS];
int nNumCardRegions;
DropZone * dropzone[MAXDROPZONES];
int nNumDropZones;
COLORREF crBackgnd;
pResizeWndProc ResizeWndCallback;
};
#endif

View file

@ -0,0 +1,69 @@
//
// CardLib - DropZone class
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include "cardlib.h"
#include "cardwindow.h"
#include "dropzone.h"
bool CardWindow::RegisterDropZone(int id, RECT *rect, pDropZoneProc proc)
{
if(nNumDropZones == MAXDROPZONES)
return false;
DropZone *dz = new DropZone(id, rect, proc);
dropzone[nNumDropZones++] = dz;
return false;
}
DropZone *CardWindow::GetDropZoneFromRect(RECT *rect)
{
for(int i = 0; i < nNumDropZones; i++)
{
RECT inter;
RECT zone;
//if any part of the drag rectangle falls within a drop zone,
//let that take priority over any other card stack.
dropzone[i]->GetZone(&zone);
if(IntersectRect(&inter, rect, &zone))
{
//see if the callback wants us to drop a card on
//a particular stack
return dropzone[i];
}
}
return 0;
}
bool CardWindow::DeleteDropZone(int id)
{
for(int i = 0; i < nNumDropZones; i++)
{
if(dropzone[i]->id == id)
{
DropZone *dz = dropzone[i];
//shift any after this one backwards
for(int j = i; j < nNumDropZones - 1; j++)
{
dropzone[j] = dropzone[j + 1];
}
delete dz;
nNumDropZones--;
return true;
}
}
return false;
}

View file

@ -0,0 +1,39 @@
#ifndef DROPZONE_INCLUDED
#define DROPZONE_INCLUDED
//
// define a drop-zone, which can be used to over-ride
// drop-behaviour for any card stacks which fall under it
//
class CardStack;
class DropZone
{
friend class CardWindow;
DropZone(int Id, RECT *rect, pDropZoneProc proc) :
id(Id), DropZoneCallback(proc) { CopyRect(&zone, rect); }
public:
void SetZone(RECT *rect) { CopyRect(&zone, rect); }
void GetZone(RECT *rect) { CopyRect(rect, &zone); }
void SetCallback(pDropZoneProc callback) { DropZoneCallback = callback; }
int DropCards(CardStack &cardstack)
{
if(DropZoneCallback)
return DropZoneCallback(id, cardstack);
else
return -1;
}
private:
int id;
RECT zone;
pDropZoneProc DropZoneCallback;
};
#endif

View file

@ -0,0 +1,15 @@
#ifndef GLOBALS_INCLUDED
#define GLOBALS_INCLUDED
extern int __cardwidth;
extern int __cardheight;
extern HDC __hdcCardBitmaps;
extern HBITMAP __hbmCardBitmaps;
extern HDC __hdcPlaceHolder;
extern HBITMAP __hbmPlaceHolder;
extern HPALETTE __hPalette;
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,42 @@
PATH_TO_TOP = ../../../reactos
TARGET_TYPE = program
TARGET_APPTYPE = windows
TARGET_INSTALLDIR = system32
TARGET_NAME = sol
TARGET_SDKLIBS = kernel32.a user32.a gdi32.a cards.a comctl32.a
TARGET_GCCLIBS = stdc++
TARGET_OBJECTS = $(SOL_OBJECTS) $(CARDLIB_OBJECTS)
SOL_OBJECTS = \
solcreate.o \
solgame.o \
solitaire.o
CARDLIB_OBJECTS = \
cardlib/cardbitmaps.o \
cardlib/cardbutton.o \
cardlib/cardcolor.o \
cardlib/cardcount.o \
cardlib/cardlib.o \
cardlib/cardregion.o \
cardlib/cardrgndraw.o \
cardlib/cardrgnmouse.o \
cardlib/cardstack.o \
cardlib/cardwindow.o \
cardlib/dropzone.o
TARGET_CPPFLAGS = -Icardlib -Wall -D__USE_W32API -D_WIN32_IE=0x0501 -D_WIN32_WINNT=0x0501 -D__REACTOS__
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk
# EOF

View file

@ -0,0 +1,25 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by Solitaire.rc
//
#define IDD_DIALOG1 101
#define IDR_MENU1 102
#define IDR_ACCELERATOR1 103
#define IDI_ICON1 104
#define IDM_GAME_NEW 40001
#define IDM_GAME_DECK 40002
#define IDM_GAME_OPTIONS 40003
#define IDM_GAME_EXIT 40004
#define IDM_HELP_CONTENTS 40005
#define IDM_HELP_ABOUT 40006
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40007
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,144 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
/* winemaker: #include "afxres.h" */
/* winemaker:warning: 'afxres.h' is an MFC specific header. Replacing it with 'winres.h' */
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.K.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 95
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,129,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_DIALOG1, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 88
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_MENU1 MENU DISCARDABLE
BEGIN
POPUP "&Game"
BEGIN
MENUITEM "&Deal\tF2", IDM_GAME_NEW
MENUITEM SEPARATOR
MENUITEM "De&ck...", IDM_GAME_DECK
MENUITEM "&Options...", IDM_GAME_OPTIONS
MENUITEM SEPARATOR
MENUITEM "&Exit", IDM_GAME_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&Contents\tF1", IDM_HELP_CONTENTS
MENUITEM "&About", IDM_HELP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE
BEGIN
VK_F1, IDM_HELP_CONTENTS, VIRTKEY, NOINVERT
VK_F2, IDM_GAME_NEW, VIRTKEY, NOINVERT
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON DISCARDABLE "icon1.ico"
#endif // English (U.K.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,87 @@
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include "resource.h"
#include "cardlib/cardlib.h"
#include "solitaire.h"
const int yBorder = 20;
const int xBorder = 20;
const int yRowStacks = yBorder + 128;
CardRegion *pDeck;
CardRegion *pPile;
CardRegion *pSuitStack[4];
CardRegion *pRowStack[NUM_ROW_STACKS];
extern CardStack activepile;
HBITMAP hbmBitmap;
HDC hdcBitmap;
void CreateSol()
{
int i;
// hbmBitmap = (HBITMAP)LoadImage(0,"test.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
// SolWnd.SetBackImage(hbmBitmap);
activepile.Clear();
pDeck = SolWnd.CreateRegion(DECK_ID, true, xBorder, yBorder, 2, 1);
pDeck->SetEmptyImage(CS_EI_SUNK);
pDeck->SetThreedCount(6);
pDeck->SetDragRule(CS_DRAG_NONE, 0);
pDeck->SetDropRule(CS_DROP_NONE, 0);
pDeck->SetClickProc(DeckClickProc);
pDeck->SetDblClickProc(DeckClickProc);
pDeck->SetFaceDirection(CS_FACE_DOWN, 0);
pPile = SolWnd.CreateRegion(PILE_ID, true, 110, yBorder, CS_DEFXOFF, 1);
pPile->SetEmptyImage(CS_EI_NONE);
pPile->SetDragRule(CS_DRAG_TOP, 0);
pPile->SetDropRule(CS_DROP_NONE, 0);
pPile->SetDblClickProc(PileDblClickProc);
pPile->SetRemoveCardProc(PileRemoveProc);
//
// Create the suit stacks
//
for(i = 0; i < 4; i++)
{
pSuitStack[i] = SolWnd.CreateRegion(SUIT_ID+i, true, 0, yBorder, 0, 0);
pSuitStack[i]->SetEmptyImage(CS_EI_SUNK);
//pSuitStack[i]->SetPlacement(CS_XJUST_RIGHT, 0, -i * (__cardwidth + 4) - xBorder, 0);
pSuitStack[i]->SetPlacement(CS_XJUST_CENTER, 0, i * (__cardwidth + 10) , 0);
pSuitStack[i]->SetDropRule(CS_DROP_CALLBACK, SuitStackDropProc);
pSuitStack[i]->SetDragRule(CS_DRAG_TOP);
pSuitStack[i]->SetAddCardProc(SuitStackAddProc);
}
//
// Create the row stacks
//
for(i = 0; i < NUM_ROW_STACKS; i++)
{
pRowStack[i] = SolWnd.CreateRegion(ROW_ID+i, true, 0, yRowStacks, 0, 14);
pRowStack[i]->SetEmptyImage(CS_EI_SUNK);
pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i);
pRowStack[i]->SetPlacement(CS_XJUST_CENTER, 0,
(i - NUM_ROW_STACKS/2) * (__cardwidth + 10), 0);
pRowStack[i]->SetEmptyImage(CS_EI_NONE);
pRowStack[i]->SetDragRule(CS_DRAG_CALLBACK, RowStackDragProc);
pRowStack[i]->SetDropRule(CS_DROP_CALLBACK, RowStackDropProc);
pRowStack[i]->SetClickProc(RowStackClickProc);
pRowStack[i]->SetDblClickProc(RowStackDblClickProc);
}
}

View file

@ -0,0 +1,308 @@
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include "resource.h"
#include "cardlib/cardlib.h"
//#include "../catch22lib/trace.h"
#include "solitaire.h"
CardStack activepile;
bool fGameStarted = false;
void NewGame(void)
{
int i, j;
SolWnd.EmptyStacks();
//create a new card-stack
CardStack deck;
deck.NewDeck();
deck.Shuffle();
activepile.Clear();
//deal to each row stack..
for(i = 0; i < NUM_ROW_STACKS; i++)
{
CardStack temp;
temp.Clear();
pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i);
for(j = 0; j <= i; j++)
{
temp.Push(deck.Pop());
}
pRowStack[i]->SetCardStack(temp);
}
//put the other cards onto the deck
pDeck->SetCardStack(deck);
pDeck->Update();
SolWnd.Redraw();
fGameStarted = false;
}
//
// Now follow the stack callback functions. This is where we
// provide the game functionality and rules
//
//
// Can only drag face-up cards
//
bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards)
{
int numfacedown;
int numcards;
stackobj.GetFaceDirection(&numfacedown);
numcards = stackobj.NumCards();
if(iNumDragCards <= numcards-numfacedown)
return true;
else
return false;
}
//
// Row a row-stack, we can only drop cards
// that are lower / different colour
//
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards)
{
Card dragcard = dragcards[dragcards.NumCards() - 1];
//if we are empty, can only drop a stack with a King at bottom
if(stackobj.NumCards() == 0)
{
if(dragcard.LoVal() != 13)
return false;
}
else
{
const CardStack &mystack = stackobj.GetCardStack();
//can only drop if card is 1 less
if(mystack[0].LoVal() != dragcard.LoVal() + 1)
return false;
//can only drop if card is different colour
if( mystack[0].IsBlack() && !dragcard.IsRed() ||
!mystack[0].IsBlack() && dragcard.IsRed() )
return false;
}
return true;
}
//
// Can only drop a card onto a suit-stack if the
// card is 1 higher, and is the same suit
//
bool CanDrop(CardRegion &stackobj, Card card)
{
int topval;
const CardStack &cardstack = stackobj.GetCardStack();
if(cardstack.NumCards() > 0)
{
if(card.Suit() != cardstack[0].Suit())
{
return false;
}
topval = cardstack[0].LoVal();
}
else
{
topval = 0;
}
//make sure 1 higher
if(card.LoVal() != (topval + 1))
return false;
return true;
}
//
// Can only drop a card onto suit stack if it is same suit, and 1 higher
//
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, const CardStack &dragcards)
{
int topval = 0;
//only drop 1 card at a time
if(dragcards.NumCards() != 1)
return false;
return CanDrop(stackobj, dragcards[0]);
}
//
// Single-click on one of the row-stacks
// Turn the top-card over if they are all face-down
//
void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked)
{
int numfacedown;
stackobj.GetFaceDirection(&numfacedown);
//if all face-down, then make top card face-up
if(stackobj.NumCards() == numfacedown)
{
if(numfacedown > 0) numfacedown--;
stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
stackobj.Redraw();
}
}
//
// Find the suit-stack that can accept the specified card
//
CardRegion *FindSuitStackFromCard(Card card)
{
for(int i = 0; i < 4; i++)
{
if(CanDrop(*pSuitStack[i], card))
return pSuitStack[i];
}
return 0;
}
//
// What happens when we add a card to one of the suit stacks?
// Well, nothing (it is already added), but we need to
// check all four stacks (not just this one) to see if
// the game has finished.
//
void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added)
{
bool fGameOver = true;
for(int i = 0; i < 4; i++)
{
if(pSuitStack[i]->NumCards() != 13)
{
fGameOver = false;
break;
}
}
if(fGameOver)
{
MessageBox(SolWnd, _T("Congratulations, you win!!"), szAppName, MB_OK | MB_ICONINFORMATION);
for(int i = 0; i < 4; i++)
{
pSuitStack[i]->Flash(11, 100);
}
}
}
//
// Double-click on one of the row stacks
// The aim is to find a suit-stack to move the
// double-clicked card to.
//
void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked)
{
//can only move 1 card at a time
if(iNumClicked != 1)
return;
//find a suit-stack to move the card to...
const CardStack &cardstack = stackobj.GetCardStack();
CardRegion *pDest = FindSuitStackFromCard(cardstack[0]);
if(pDest != 0)
{
//stackobj.MoveCards(pDest, 1, true);
//use the SimulateDrag funcion, because we get the
//AddProc callbacks called for us on the destination stacks...
stackobj.SimulateDrag(pDest, 1, true);
}
}
//
// Face-up pile double-click
//
void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked)
{
RowStackDblClickProc(stackobj, iNumClicked);
}
//
// What happens when a card is removed from face-up pile?
//
void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems)
{
//modify our "virtual" pile by removing the same card
//that was removed from the physical card stack
activepile.Pop(iItems);
//if there is just 1 card left, then modify the
//stack to contain ALL the face-up cards..the effect
//will be, the next time a card is dragged, all the
//previous card-triplets will be available underneath
if(stackobj.NumCards() == 1)
{
stackobj.SetOffsets(0,0);
stackobj.SetCardStack(activepile);
}
}
//
// Double-click on the deck
// Move 3 cards to the face-up pile
//
void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked)
{
CardStack cardstack = stackobj.GetCardStack();
CardStack pile = pPile->GetCardStack();
fGameStarted = true;
//reset the face-up pile to represent 3 cards
pPile->SetOffsets(CS_DEFXOFF, 1);
if(cardstack.NumCards() == 0)
{
pile.Clear();
activepile.Reverse();
cardstack.Push(activepile);
activepile.Clear();
}
else
{
int numcards = min(3, cardstack.NumCards());
//make a "visible" copy of these cards
CardStack temp;
temp = cardstack.Pop(numcards);
temp.Reverse();
pile.Clear();
pile.Push(temp);
//remove the top 3 from deck
activepile.Push(temp);
}
activepile.Print();
pDeck->SetCardStack(cardstack);
pPile->SetCardStack(pile);
SolWnd.Redraw();
}

View file

@ -0,0 +1,217 @@
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include "resource.h"
#include "cardlib/cardlib.h"
#include "solitaire.h"
TCHAR szHelpPath[MAX_PATH];
DWORD dwAppStartTime;
HWND hwndMain;
HWND hwndStatus;
HINSTANCE hInstance;
TCHAR szAppName[] = _T("Solitaire");
CardWindow SolWnd;
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
void MakePath(TCHAR *szDest, UINT nDestLen, TCHAR *szExt)
{
TCHAR *ptr;
ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1;
while(*ptr-- != '.');
lstrcpy(ptr + 1, szExt);
}
//
// Main entry point
//
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, PSTR szCmdLine, int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
INITCOMMONCONTROLSEX ice;
HACCEL hAccelTable;
hInstance = hInst;
//Window class for the main application parent window
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;//CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_ICON1));
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)NULL;
wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wndclass.lpszClassName = szAppName;
wndclass.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 16, 16, 0);
RegisterClassEx(&wndclass);
ice.dwSize = sizeof(ice);
ice.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&ice);
srand((unsigned)GetTickCount());//timeGetTime());
// InitCardLib();
// LoadSettings();
//Construct the path to our help file
MakePath(szHelpPath, MAX_PATH, _T(".hlp"));
hwnd = CreateWindow(szAppName, // window class name
szAppName, // window caption
WS_OVERLAPPEDWINDOW
,//|WS_CLIPCHILDREN, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // use window class menu
hInst, // program instance handle
NULL); // creation parameters
hwndMain = hwnd;
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
while(GetMessage(&msg, NULL,0,0))
{
if(!TranslateAccelerator(hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// SaveSettings();
return msg.wParam;
}
//-----------------------------------------------------------------------------
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static int nWidth, nHeight;
int nStatusHeight = 0;//20;
int parts[] = { 100, -1 };
UINT ret;
MINMAXINFO *mmi;
switch(iMsg)
{
case WM_CREATE:
hwndStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, "Ready", hwnd, 0);
//SendMessage(hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0);
SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts);
SendMessage(hwndStatus, SB_SETTEXT, 0 | SBT_NOBORDERS, (LPARAM)"");
ShowWindow(hwndStatus, SW_HIDE);
SolWnd.Create(hwnd, WS_EX_CLIENTEDGE, WS_CHILD|WS_VISIBLE, 0, 0, 0, 0);
CreateSol();
NewGame();
dwAppStartTime = GetTickCount();
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SIZE:
nWidth = LOWORD(lParam);
nHeight = HIWORD(lParam);
MoveWindow(SolWnd, 0, 0, nWidth, nHeight-nStatusHeight, TRUE);
//MoveWindow(hwndStatus, 0, nHeight-nStatusHeight, nWidth, nHeight, TRUE);
//parts[0] = nWidth - 256;
//SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts);
return 0;
case WM_GETMINMAXINFO:
mmi = (MINMAXINFO *)lParam;
mmi->ptMinTrackSize.x = 600;
mmi->ptMinTrackSize.y = 400;
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_GAME_NEW:
//simulate a button click on the new button..
NewGame();
return 0;
case IDM_GAME_DECK:
//ShowDeckOptionsDlg(hwnd);
return 0;
case IDM_GAME_OPTIONS:
//ShowGameOptionsDlg(hwnd);
return 0;
case IDM_HELP_CONTENTS:
WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play");
return 0;
case IDM_HELP_ABOUT:
MessageBox(hwnd, _T("Solitare by J Brown\r\n\r\nCardLib version 1.0."), szAppName, MB_OK|MB_ICONINFORMATION);
return 0;
case IDM_GAME_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
}
return 0;
case WM_CLOSE:
ret = IDOK;
if(fGameStarted)
{
ret = MessageBox(hwnd, _T("Quit the current game?"), szAppName, MB_OKCANCEL|MB_ICONQUESTION);
}
if(ret == IDOK)
{
WinHelp(hwnd, szHelpPath, HELP_QUIT, 0);
DestroyWindow(hwnd);
}
return 0;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

View file

@ -0,0 +1,37 @@
#ifndef SOLITAIRE_INCLUDED
#define SOLITAIRE_INCLUDED
extern CardWindow SolWnd;
extern TCHAR szAppName[];
extern bool fGameStarted;
void CreateSol();
void NewGame(void);
#define NUM_ROW_STACKS 7
#define DECK_ID 1
#define PILE_ID 2
#define SUIT_ID 4
#define ROW_ID 10
extern CardRegion *pDeck;
extern CardRegion *pPile;
extern CardRegion *pSuitStack[];
extern CardRegion *pRowStack[];
bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumCards);
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards);
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, const CardStack &dragcards);
void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added);
void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked);
void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked);
void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked);
void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked);
void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iRemoved);
#endif