- Add a spider solitaire clone
- Relies on the Catch22 cardlib
- Supports all three playing modes and full game play
- English and German resources included, own work
- Icon origin: tango solitaire icon with a self drawn spider on top
[cardlib]
- Convert to a static library as suggested in the comments, move to 3rdparty directory
- Allow to modify dragged card stacks (needed for spider)
[solitaire]
- Adapt to cardlib changes, delete local cardlib copy

svn path=/trunk/; revision=43372
This commit is contained in:
Gregor Schneider 2009-10-11 12:07:11 +00:00
parent be31446a2e
commit 84e271496c
40 changed files with 6211 additions and 31 deletions

View file

@ -4,7 +4,9 @@
<directory name="solitaire">
<xi:include href="solitaire/solitaire.rbuild" />
</directory>
<directory name="spider">
<xi:include href="spider/spider.rbuild" />
</directory>
<directory name="winemine">
<xi:include href="winemine/winemine.rbuild" />
</directory>

View file

@ -15,8 +15,5 @@ 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

@ -2,7 +2,7 @@
#include <commctrl.h>
#include <tchar.h>
#include "resource.h"
#include "cardlib/cardlib.h"
#include "cardlib.h"
#include "solitaire.h"

View file

@ -3,8 +3,7 @@
#include <tchar.h>
#include <stdio.h>
#include "resource.h"
#include "cardlib/cardlib.h"
//#include "../catch22lib/trace.h"
#include "cardlib.h"
#include "solitaire.h"
#if 1
@ -92,7 +91,7 @@ bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards)
// Row a row-stack, we can only drop cards
// that are lower / different colour
//
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards)
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards)
{
TRACE("ENTER RowStackDropProc()\n");
Card dragcard = dragcards[dragcards.NumCards() - 1];
@ -172,7 +171,7 @@ bool CanDrop(CardRegion &stackobj, Card card)
//
// Can only drop a card onto suit stack if it is same suit, and 1 higher
//
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, const CardStack &dragcards)
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards)
{
TRACE("ENTER SuitStackDropProc()\n");
//only drop 1 card at a time

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include "resource.h"
#include "cardlib/cardlib.h"
#include "cardlib.h"
#include "solitaire.h"

View file

@ -41,9 +41,9 @@ extern CardRegion *pRowStack[];
bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumCards);
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards);
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards);
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, const CardStack &dragcards);
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards);
void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added);
void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked);

View file

@ -2,27 +2,10 @@
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="sol" type="win32gui" installbase="system32" installname="sol.exe" unicode="yes">
<include base="sol">.</include>
<include base="sol">cardlib</include>
<library>advapi32</library>
<library>kernel32</library>
<library>user32</library>
<library>gdi32</library>
<library>comctl32</library>
<include base="cardlib">.</include>
<library>cardlib</library>
<file>solcreate.cpp</file>
<file>solgame.cpp</file>
<file>solitaire.cpp</file>
<directory name="cardlib">
<file>cardbitmaps.cpp</file>
<file>cardbutton.cpp</file>
<file>cardcolor.cpp</file>
<file>cardcount.cpp</file>
<file>cardlib.cpp</file>
<file>cardregion.cpp</file>
<file>cardrgndraw.cpp</file>
<file>cardrgnmouse.cpp</file>
<file>cardstack.cpp</file>
<file>cardwindow.cpp</file>
<file>dropzone.cpp</file>
</directory>
<file>rsrc.rc</file>
</module>

View file

@ -0,0 +1,81 @@
/*
* PROJECT: Spider Solitaire
* LICENSE: See COPYING in top level directory
* FILE: base/applications/games/spider/lang/en-US.rc
* PURPOSE: German Language File for Spider Solitaire
* PROGRAMMER: Gregor Schneider
*/
#include "resource.h"
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
/* Dialogs */
IDD_CARDBACK DIALOGEX 6, 6, 221, 96
CAPTION "Kartenhintergrund wählen"
FONT 8, "MS Shell Dlg"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SHELLFONT
BEGIN
CONTROL "", IDC_CARDBACK1, "Static", SS_NOTIFY, 4, 7, 50, 61
CONTROL "", IDC_CARDBACK2, "Static", SS_NOTIFY, 58, 7, 50, 61
CONTROL "", IDC_CARDBACK3, "Static", SS_NOTIFY, 112, 7, 50, 61
CONTROL "", IDC_CARDBACK4, "Static", SS_NOTIFY, 166, 7, 50, 61
DEFPUSHBUTTON "OK", IDOK, 104, 77, 54, 13
PUSHBUTTON "Abbrechen", IDCANCEL, 162, 77, 54, 13
END
IDD_DIFFICULTY DIALOGEX DISCARDABLE 100, 100, 106, 80
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SHELLFONT
CAPTION "Schwierigkeitsgrad wählen"
FONT 8, "MS Shell Dlg"
BEGIN
AUTORADIOBUTTON "Einfach: &Eine Farbe", IDC_DIF_ONECOLOR, 8, 10, 80, 10, WS_GROUP | WS_TABSTOP
AUTORADIOBUTTON "Mittel: &Zwei Farben", IDC_DIF_TWOCOLORS, 8, 23, 80, 10
AUTORADIOBUTTON "Schwer: &Vier Farben", IDC_DIF_FOURCOLORS, 8, 36, 80, 10
DEFPUSHBUTTON "OK", IDOK, 8, 58, 40, 14
PUSHBUTTON "Abbrechen", IDCANCEL, 58, 58, 40, 14
END
/* Strings */
STRINGTABLE
BEGIN
IDS_SPI_NAME "Spider"
IDS_SPI_ABOUT "Spider Solitaire von Gregor Schneider\n\nCardLib Version 1.0"
IDS_SPI_QUIT "Laufendes Spiel beenden?"
IDS_SPI_WIN "Gratulation, Sie haben gewonnen!"
IDS_SPI_DEAL "Neu geben?"
END
/* Menus */
IDR_MENU1 MENU DISCARDABLE
BEGIN
POPUP "&Spiel"
BEGIN
MENUITEM "&Neues Spiel\tF2", IDM_GAME_NEW
MENUITEM SEPARATOR
MENUITEM "&Deckblatt...", IDM_GAME_DECK
MENUITEM SEPARATOR
MENUITEM "&Beenden", IDM_GAME_EXIT
END
POPUP "&?"
BEGIN
MENUITEM "&Inhalt\tF1", IDM_HELP_CONTENTS
MENUITEM "Inf&o", 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

View file

@ -0,0 +1,81 @@
/*
* PROJECT: Spider Solitaire
* LICENSE: See COPYING in top level directory
* FILE: base/applications/games/spider/lang/en-US.rc
* PURPOSE: English Language File for Spider Solitaire
* PROGRAMMER: Gregor Schneider
*/
#include "resource.h"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
/* Dialogs */
IDD_CARDBACK DIALOGEX 6, 6, 221, 96
CAPTION "Select Card Back"
FONT 8, "MS Shell Dlg"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SHELLFONT
BEGIN
CONTROL "", IDC_CARDBACK1, "Static", SS_NOTIFY, 4, 7, 50, 61
CONTROL "", IDC_CARDBACK2, "Static", SS_NOTIFY, 58, 7, 50, 61
CONTROL "", IDC_CARDBACK3, "Static", SS_NOTIFY, 112, 7, 50, 61
CONTROL "", IDC_CARDBACK4, "Static", SS_NOTIFY, 166, 7, 50, 61
DEFPUSHBUTTON "OK", IDOK, 104, 77, 54, 13
PUSHBUTTON "Cancel", IDCANCEL, 162, 77, 54, 13
END
IDD_DIFFICULTY DIALOGEX DISCARDABLE 100, 100, 106, 80
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SHELLFONT
CAPTION "Difficulty"
FONT 8, "MS Shell Dlg"
BEGIN
AUTORADIOBUTTON "Easy: &One Color", IDC_DIF_ONECOLOR, 8, 10, 80, 10, WS_GROUP | WS_TABSTOP
AUTORADIOBUTTON "Medium: &Two Colors", IDC_DIF_TWOCOLORS, 8, 23, 80, 10
AUTORADIOBUTTON "Hard: &Four Colors", IDC_DIF_FOURCOLORS, 8, 36, 80, 10
DEFPUSHBUTTON "OK", IDOK, 8, 58, 40, 14
PUSHBUTTON "Cancel", IDCANCEL, 58, 58, 40, 14
END
/* Strings */
STRINGTABLE
BEGIN
IDS_SPI_NAME "Spider"
IDS_SPI_ABOUT "Spider Solitaire by Gregor Schneider\n\nCardLib version 1.0"
IDS_SPI_QUIT "Quit the current game?"
IDS_SPI_WIN "Congratulations, you win!"
IDS_SPI_DEAL "Deal again?"
END
/* Menus */
IDR_MENU1 MENU DISCARDABLE
BEGIN
POPUP "&Game"
BEGIN
MENUITEM "&New Game\tF2", IDM_GAME_NEW
MENUITEM SEPARATOR
MENUITEM "&Deck...", IDM_GAME_DECK
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

View file

@ -0,0 +1,31 @@
/* Icon */
#define IDI_SPIDER 100
#define IDR_MENU1 102
#define IDR_ACCELERATOR1 103
/* Menu */
#define IDM_GAME_NEW 1001
#define IDM_GAME_DECK 1002
#define IDM_GAME_EXIT 1003
#define IDM_HELP_CONTENTS 1004
#define IDM_HELP_ABOUT 1005
/* Dialogs */
#define IDD_CARDBACK 1250
#define IDC_CARDBACK1 1251
#define IDC_CARDBACK2 1252
#define IDC_CARDBACK3 1253
#define IDC_CARDBACK4 1254
#define IDD_DIFFICULTY 1260
#define IDC_DIF_ONECOLOR 1261
#define IDC_DIF_TWOCOLORS 1262
#define IDC_DIF_FOURCOLORS 1263
/* Strings */
#define IDS_SPI_NAME 1300
#define IDS_SPI_ABOUT 1301
#define IDS_SPI_QUIT 1302
#define IDS_SPI_WIN 1303
#define IDS_SPI_DEAL 1304

View file

@ -0,0 +1,10 @@
#include <windows.h>
#include "resource.h"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDI_SPIDER ICON DISCARDABLE "spider.ico"
#include "lang/de-DE.rc"
#include "lang/en-US.rc"

View file

@ -0,0 +1,422 @@
/*
* PROJECT: Spider Solitaire
* LICENSE: See COPYING in top level directory
* FILE: base/applications/games/spider/spider.cpp
* PURPOSE: Window and message queue for Spider Solitaire
* PROGRAMMER: Gregor Schneider
*/
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include <stdlib.h>
#include "resource.h"
#include "cardlib.h"
#include "spider.h"
TCHAR szHelpPath[MAX_PATH];
DWORD dwAppStartTime;
HWND hwndMain;
HINSTANCE hInstance;
TCHAR szAppName[128];
TCHAR MsgQuit[128];
TCHAR MsgAbout[128];
TCHAR MsgWin[128];
TCHAR MsgDeal[128];
DWORD dwDifficulty;
CardWindow SpiderWnd;
typedef struct _CardBack
{
HWND hSelf;
WNDPROC hOldProc;
INT hdcNum;
INT imgNum;
BOOL bSelected;
} CARDBACK, *PCARDBACK;
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
void MakePath(TCHAR *szDest, UINT nDestLen, const TCHAR *szExt)
{
TCHAR *ptr;
ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1;
while(*ptr-- != '.');
lstrcpy(ptr + 1, szExt);
}
BOOL CALLBACK DifficultyDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
CheckRadioButton(hDlg, IDC_DIF_ONECOLOR, IDC_DIF_FOURCOLORS, IDC_DIF_ONECOLOR);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
if (IsDlgButtonChecked(hDlg, IDC_DIF_ONECOLOR) == BST_CHECKED)
dwDifficulty = IDC_DIF_ONECOLOR;
else if (IsDlgButtonChecked(hDlg, IDC_DIF_TWOCOLORS) == BST_CHECKED)
dwDifficulty = IDC_DIF_TWOCOLORS;
else if (IsDlgButtonChecked(hDlg, IDC_DIF_FOURCOLORS) == BST_CHECKED)
dwDifficulty = IDC_DIF_FOURCOLORS;
NewGame();
EndDialog(hDlg, TRUE);
return TRUE;
case IDCANCEL:
EndDialog(hDlg, FALSE);
return TRUE;
}
break;
}
return FALSE;
}
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
INITCOMMONCONTROLSEX ice;
HACCEL hAccelTable;
hInstance = hInst;
/* Load application title */
LoadString(hInst, IDS_SPI_NAME, szAppName, sizeof(szAppName) / sizeof(szAppName[0]));
/* Load MsgBox() texts here to avoid loading them many times later */
LoadString(hInst, IDS_SPI_ABOUT, MsgAbout, sizeof(MsgAbout) / sizeof(MsgAbout[0]));
LoadString(hInst, IDS_SPI_QUIT, MsgQuit, sizeof(MsgQuit) / sizeof(MsgQuit[0]));
LoadString(hInst, IDS_SPI_WIN, MsgWin, sizeof(MsgWin) / sizeof(MsgWin[0]));
LoadString(hInst, IDS_SPI_DEAL, MsgDeal, sizeof(MsgDeal) / sizeof(MsgDeal[0]));
/* Window class for the main application parent window */
wndclass.style = 0;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_SPIDER));
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)NULL;
wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
ice.dwSize = sizeof(ice);
ice.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&ice);
srand((unsigned)GetTickCount());
/* InitCardLib(); */
/* Construct the path to our help file */
MakePath(szHelpPath, MAX_PATH, _T(".hlp"));
hwnd = CreateWindow(szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
0, /*The real size will be computed in WndProc through WM_GETMINMAXINFO */
0, /* The real size will be computed in WndProc through WM_GETMINMAXINFO */
NULL,
NULL,
hInst,
NULL);
hwndMain = hwnd;
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIFFICULTY), hwnd, DifficultyDlgProc);
while(GetMessage(&msg, NULL,0,0))
{
if(!TranslateAccelerator(hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK
CardImageWndProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
PCARDBACK pCardBack = (PCARDBACK)GetWindowLongPtr(hwnd,
GWL_USERDATA);
static WNDPROC hOldProc = NULL;
if (!hOldProc && pCardBack)
hOldProc = pCardBack->hOldProc;
switch (msg)
{
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
HPEN hPen, hOldPen;
HBRUSH hBrush, hOldBrush;
RECT rc;
hdc = BeginPaint(hwnd, &ps);
if (pCardBack->bSelected)
{
hPen = CreatePen(PS_SOLID, 2, RGB(0,0,0));
}
else
{
DWORD Face = GetSysColor(COLOR_3DFACE);
hPen = CreatePen(PS_SOLID, 2, Face);
}
GetClientRect(hwnd, &rc);
hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
hOldPen = (HPEN)SelectObject(hdc, hPen);
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Rectangle(hdc,
rc.left+1,
rc.top+1,
rc.right,
rc.bottom);
StretchBlt(hdc,
2,
2,
CARDBACK_OPTIONS_WIDTH,
CARDBACK_OPTIONS_HEIGHT,
__hdcCardBitmaps,
pCardBack->hdcNum * __cardwidth,
0,
__cardwidth,
__cardheight,
SRCCOPY);
SelectObject(hdc, hOldPen);
SelectObject(hdc, hOldBrush);
EndPaint(hwnd, &ps);
break;
}
case WM_LBUTTONDOWN:
pCardBack->bSelected = pCardBack->bSelected ? FALSE : TRUE;
break;
}
return CallWindowProc(hOldProc,
hwnd,
msg,
wParam,
lParam);
}
BOOL CALLBACK CardBackDlgProc(HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
static PCARDBACK pCardBacks = NULL;
switch (uMsg)
{
case WM_INITDIALOG:
{
INT i, c;
SIZE_T size = sizeof(CARDBACK) * NUM_CARDBACKS;
pCardBacks = (PCARDBACK)HeapAlloc(GetProcessHeap(),
0,
size);
for (i = 0, c = CARDBACK_START; c <= CARDBACK_END; i++, c++)
{
pCardBacks[i].hSelf = GetDlgItem(hDlg, c);
pCardBacks[i].bSelected = FALSE;
pCardBacks[i].hdcNum = CARDBACK_RES_START + i;
pCardBacks[i].imgNum = i + 1;
pCardBacks[i].hOldProc = (WNDPROC)SetWindowLongPtr(pCardBacks[i].hSelf,
GWLP_WNDPROC,
(LONG_PTR)CardImageWndProc);
SetWindowLongPtr(pCardBacks[i].hSelf,
GWL_USERDATA,
(LONG_PTR)&pCardBacks[i]);
}
return TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
INT i, num = 0;
for (i = 0; i < NUM_CARDBACKS; i++)
{
if (pCardBacks[i].bSelected)
{
num = pCardBacks[i].imgNum;
}
}
EndDialog(hDlg, LOWORD(wParam) == IDOK ? num : FALSE);
HeapFree(GetProcessHeap(), 0, pCardBacks);
return TRUE;
}
if (HIWORD(wParam) == STN_CLICKED)
{
INT i;
RECT rc;
for (i = 0; i < NUM_CARDBACKS; i++)
{
if (pCardBacks[i].hSelf == (HWND)lParam)
{
pCardBacks[i].bSelected = TRUE;
}
else
pCardBacks[i].bSelected = FALSE;
GetClientRect(pCardBacks[i].hSelf, &rc);
InvalidateRect(pCardBacks[i].hSelf, &rc, TRUE);
}
break;
}
}
return FALSE;
}
VOID ShowDeckOptionsDlg(HWND hwnd)
{
INT cardBack;
if ((cardBack = DialogBox(hInstance,
MAKEINTRESOURCE(IDD_CARDBACK),
hwnd,
CardBackDlgProc)))
{
SpiderWnd.SetBackCardIdx(CARDBACK_RES_START + (cardBack - 1));
SpiderWnd.Redraw();
}
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static int nWidth, nHeight;
switch(iMsg)
{
case WM_CREATE:
{
SpiderWnd.Create(hwnd, WS_EX_CLIENTEDGE, WS_CHILD|WS_VISIBLE, 0, 0, 0, 0);
dwDifficulty = IDC_DIF_ONECOLOR;
CreateSpider();
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER);
dwAppStartTime = GetTickCount();
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SIZE:
nWidth = LOWORD(lParam);
nHeight = HIWORD(lParam);
MoveWindow(SpiderWnd, 0, 0, nWidth, nHeight, TRUE);
return 0;
case WM_GETMINMAXINFO:
{
MINMAXINFO *mmi;
mmi = (MINMAXINFO *)lParam;
mmi->ptMinTrackSize.x = NUM_STACKS * __cardwidth + (NUM_STACKS + 3) * X_BORDER;
mmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION) +
GetSystemMetrics(SM_CYMENU) +
2 * Y_BORDER +
3 * __cardheight +
6 * yRowStackCardOffset;
return 0;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_GAME_NEW:
NewGame();
return 0;
case IDM_GAME_DECK:
ShowDeckOptionsDlg(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, MsgAbout, szAppName, MB_OK|MB_ICONINFORMATION);
return 0;
case IDM_GAME_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
}
return 0;
case WM_CLOSE:
if (fGameStarted == false)
{
DestroyWindow(hwnd);
return 0;
}
else
{
int ret;
ret = MessageBox(hwnd, MsgQuit, 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,41 @@
#ifndef SOLITAIRE_INCLUDED
#define SOLITAIRE_INCLUDED
#define DIFFICULTY_ONE_COLOR 1
#define DIFFICULTY_TWO_COLORS 2
#define DIFFICULTY_FOUR_COLORS 3
#define CARDBACK_START IDC_CARDBACK1
#define CARDBACK_END IDC_CARDBACK4
#define NUM_CARDBACKS (CARDBACK_END - CARDBACK_START + 1)
#define CARDBACK_RES_START 53
#define CARDBACK_OPTIONS_WIDTH 72
#define CARDBACK_OPTIONS_HEIGHT 96
#define X_BORDER 6
#define Y_BORDER 12
#define NUM_STACKS 10
extern HWND hwndMain;
extern CardWindow SpiderWnd;
extern TCHAR szAppName[];
extern bool fGameStarted;
extern int yRowStackCardOffset;
extern DWORD dwDifficulty;
extern TCHAR MsgDeal[];
extern TCHAR MsgWin[];
void CreateSpider();
void NewGame(void);
bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumCards);
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards);
void CARDLIBPROC RowStackClickProc(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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
<module name="spider" type="win32gui" installbase="system32" installname="spider.exe" unicode="no">
<include base="spider">.</include>
<include base="cardlib">.</include>
<library>cardlib</library>
<file>spigame.cpp</file>
<file>spider.cpp</file>
<file>rsrc.rc</file>
</module>

View file

@ -0,0 +1,327 @@
/*
* PROJECT: Spider Solitaire
* LICENSE: See COPYING in top level directory
* FILE: base/applications/games/spider/lang/spigame.cpp
* PURPOSE: Spider Solitaire game functions
* PROGRAMMER: Gregor Schneider
*/
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include <stdio.h>
#include "resource.h"
#include "cardlib.h"
#include "spider.h"
#define NUM_DECK_CARDS 5
#define NUM_SMALLER_STACKS 4
#define NUM_CARD_COLORS 4
#define NUM_ONECOLOR_CARDS 13
#define NUM_STD_CARDS 52
#define NUM_SPIDER_CARDS 104
CardStack deck;
CardRegion *from;
CardRegion *pDeck;
CardRegion *pStack[NUM_STACKS];
bool fGameStarted = false;
int yRowStackCardOffset;
int cardsFinished;
extern TCHAR MsgDeal[];
extern TCHAR MsgWin[];
CardStack CreatePlayDeck()
{
CardStack newStack;
int i, colors = 1, num = 0;
switch (dwDifficulty)
{
case IDC_DIF_ONECOLOR:
colors = 1;
break;
case IDC_DIF_TWOCOLORS:
colors = 2;
break;
case IDC_DIF_FOURCOLORS:
colors = 4;
break;
}
for (i = 0; i < NUM_SPIDER_CARDS; i++)
{
num += NUM_CARD_COLORS / colors;
Card newCard(num % NUM_STD_CARDS);
newStack.Push(newCard);
}
return newStack;
}
void NewGame(void)
{
int i, j;
/* First four stack with five, all other with 4 */
int covCards = 5;
CardStack fakeDeck, temp;
SpiderWnd.EmptyStacks();
/* Create a new card-deck, fake deck */
deck = CreatePlayDeck();
deck.Shuffle();
fakeDeck.NewDeck();
fakeDeck.Shuffle();
/* Reset progress value */
cardsFinished = 0;
/* Deal to each stack */
for (i = 0; i < NUM_STACKS; i++)
{
temp.Clear();
if (i == NUM_SMALLER_STACKS)
{
covCards--;
}
for (j = 0; j <= covCards; j++)
{
temp.Push(deck.Pop(1));
}
pStack[i]->SetFaceDirection(CS_FACE_DOWNUP, covCards);
pStack[i]->SetCardStack(temp);
}
/* Deal five fake cards to the deck */
pDeck->SetCardStack(fakeDeck.Pop(5));
SpiderWnd.Redraw();
fGameStarted = false;
}
/* Click on the deck */
void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int NumDragCards)
{
CardStack temp, fakeDeck = pDeck->GetCardStack();
fGameStarted = true;
int i;
if (fakeDeck.NumCards() != 0 && deck.NumCards() != 0)
{
/* Add one card to every stack */
for (i = 0; i < NUM_STACKS; i++)
{
temp = pStack[i]->GetCardStack();
temp.Push(deck.Pop());
pStack[i]->SetCardStack(temp);
}
/* Remove one card from the fake ones */
pDeck->SetCardStack(fakeDeck.Pop(fakeDeck.NumCards() - 1));
}
pDeck->Update();
SpiderWnd.Redraw();
}
/* Cards dragged friom a stack */
bool CARDLIBPROC StackDragProc(CardRegion &stackobj, int numDragCards)
{
int numfacedown, numcards, i;
stackobj.GetFaceDirection(&numfacedown);
numcards = stackobj.NumCards();
/* Only cards facing up */
if (numDragCards <= numcards - numfacedown)
{
const CardStack &mystack = stackobj.GetCardStack();
/* Don't allow to drag unsuited cards */
for (i = 0; i < numDragCards - 1; i++)
{
if (mystack[i].LoVal() != mystack[i + 1].LoVal() - 1)
{
return false;
}
switch (dwDifficulty)
{
case IDC_DIF_ONECOLOR:
break;
case IDC_DIF_TWOCOLORS:
if (mystack[i].IsBlack() && mystack[i + 1].IsBlack() ||
mystack[i].IsRed() && mystack[i + 1].IsRed())
{
return false;
}
break;
case IDC_DIF_FOURCOLORS:
if (mystack[i].Suit() != mystack[i + 1].Suit())
{
return false;
}
break;
}
}
/* Remember where the cards come from */
from = &stackobj;
return true;
}
else
{
return false;
}
}
/* Game finished successfully */
void GameFinished()
{
MessageBox(SpiderWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
if( IDYES == MessageBox(SpiderWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
{
NewGame();
}
else
{
SpiderWnd.EmptyStacks();
fGameStarted = false;
}
}
/* Card added, check for win situation */
void CARDLIBPROC StackAddProc(CardRegion &stackobj, const CardStack &added)
{
if (cardsFinished == NUM_SPIDER_CARDS)
{
GameFinished();
}
}
/* Card to be turned from a stack */
void TurnStackCard(CardRegion &stackobj)
{
int numfacedown;
stackobj.GetFaceDirection(&numfacedown);
if (stackobj.NumCards() <= numfacedown)
{
if (numfacedown > 0) numfacedown--;
stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
stackobj.Redraw();
}
}
/* Cards dropped to a stack */
bool CARDLIBPROC StackDropProc(CardRegion &stackobj, CardStack &dragcards)
{
Card dragcard = dragcards[dragcards.NumCards() - 1];
int faceup, facedown;
/* Only drop our cards on other stacks */
if (stackobj.Id() == from->Id())
{
return false;
}
/* If stack is empty, everything can be dropped */
if (stackobj.NumCards() != 0)
{
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 matches colour rule */
switch (dwDifficulty)
{
case IDC_DIF_ONECOLOR:
break;
case IDC_DIF_TWOCOLORS:
if (mystack[0].IsBlack() && dragcard.IsRed() ||
mystack[0].IsRed() && dragcard.IsBlack())
{
return false;
}
break;
case IDC_DIF_FOURCOLORS:
if (mystack[0].Suit() != dragcard.Suit())
{
return false;
}
break;
}
/* Check if stack complete */
stackobj.GetFaceDirection(&facedown);
faceup = stackobj.NumCards() - facedown;
if (faceup + dragcards.NumCards() >= NUM_ONECOLOR_CARDS)
{
int i, max = NUM_ONECOLOR_CARDS - dragcards.NumCards() - 1;
BOOL remove = true;
/* Dragged cards have been checked to be in order, start with the first stack card */
for (i = 0; i < max; i++)
{
if (mystack[i].Suit() != mystack[i + 1].Suit() ||
mystack[i].LoVal() != mystack[i + 1].LoVal() - 1)
{
remove = false;
break;
}
}
if (remove)
{
CardStack s = stackobj.GetCardStack();
CardStack f;
/* Remove from card stack */
for (i = 0; i < max + 1; i++)
{
s.RemoveCard(0);
}
/* Remove dragged cards */
dragcards = f;
stackobj.SetCardStack(s);
cardsFinished += NUM_ONECOLOR_CARDS;
/* Flip top card of the dest stack */
TurnStackCard(stackobj);
}
}
}
/* Flip the top card of the source stack */
TurnStackCard(*from);
fGameStarted = true;
return true;
}
/* Create card regions */
void CreateSpider()
{
int i, pos;
/* Compute the value for yRowStackCardOffset based on the height of the card, so the card number isn't hidden on larger cards */
yRowStackCardOffset = (int)(__cardheight / 6.7);
pDeck = SpiderWnd.CreateRegion(0, true, 0, 0, -15, 0);
pDeck->SetFaceDirection(CS_FACE_DOWN, 0);
pDeck->SetEmptyImage(CS_EI_CIRC);
pDeck->SetPlacement(CS_XJUST_RIGHT, CS_YJUST_BOTTOM, - X_BORDER, - Y_BORDER);
pDeck->SetDragRule(CS_DRAG_NONE, 0);
pDeck->SetDropRule(CS_DROP_NONE, 0);
pDeck->SetClickProc(DeckClickProc);
pDeck->SetDblClickProc(DeckClickProc);
/* Create the row stacks */
for (i = 0; i < NUM_STACKS; i++)
{
pStack[i] = SpiderWnd.CreateRegion(NUM_STACKS+i, true, 0, Y_BORDER, 0, yRowStackCardOffset);
pStack[i]->SetFaceDirection(CS_FACE_DOWN, 0);
pos = i - NUM_STACKS/2;
pStack[i]->SetPlacement(CS_XJUST_CENTER, 0,
pos * (__cardwidth + X_BORDER) + 6 * X_BORDER, 0);
pStack[i]->SetEmptyImage(CS_EI_SUNK);
pStack[i]->SetDragRule(CS_DRAG_CALLBACK, StackDragProc);
pStack[i]->SetDropRule(CS_DROP_CALLBACK, StackDropProc);
pStack[i]->SetAddCardProc(StackAddProc);
}
}

View file

@ -7,6 +7,9 @@
<directory name="bzip2">
<xi:include href="bzip2/bzip2.rbuild" />
</directory>
<directory name="cardlib">
<xi:include href="cardlib/cardlib.rbuild" />
</directory>
<directory name="expat">
<xi:include href="expat/expat.rbuild" />
</directory>

View file

@ -0,0 +1,6 @@
The author has given permission to use these sources
under Public Domain. Do what thou will but please give
credit where credit is due.
-sedwards

105
reactos/lib/3rdparty/cardlib/card.h vendored Normal file
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 = NULL;
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(TEXT("cards.dll"));
if(hCardDll == 0)
{
MessageBox(0, TEXT("Error loading cards.dll (32bit)"), TEXT("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 = (WORD)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), uStyle(Style), fVisible(visible), 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,337 @@
//
// 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)
{
return ColorScaleHSL(col, RGB(0,0,0), ratio);
}
COLORREF ColorLighter(COLORREF col, double ratio)
{
return ColorScaleHSL(col, RGB(255,255,255), ratio);
}
//
// 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

122
reactos/lib/3rdparty/cardlib/cardlib.cpp vendored Normal file
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, TEXT(""), 0, 0);
SetBkColor(hdc, oldcr);
}

101
reactos/lib/3rdparty/cardlib/cardlib.h vendored Normal file
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_EI_CIRC 67
#define CS_EI_X 66
#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_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;
class CardWindow;
typedef bool (CARDLIBPROC *pCanDragProc) (CardRegion &stackobj, int iNumDragging);
typedef bool (CARDLIBPROC *pCanDropProc) (CardRegion &stackobj, 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,20 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
<module name="cardlib" type="staticlibrary">
<library>advapi32</library>
<library>kernel32</library>
<library>user32</library>
<library>gdi32</library>
<library>comctl32</library>
<file>cardbitmaps.cpp</file>
<file>cardbutton.cpp</file>
<file>cardcolor.cpp</file>
<file>cardcount.cpp</file>
<file>cardlib.cpp</file>
<file>cardregion.cpp</file>
<file>cardrgndraw.cpp</file>
<file>cardrgnmouse.cpp</file>
<file>cardstack.cpp</file>
<file>cardwindow.cpp</file>
<file>dropzone.cpp</file>
</module>

View file

@ -0,0 +1,657 @@
//
// CardLib - CardRegion class
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include "cardlib.h"
#include "cardregion.h"
#include "cardwindow.h"
#include "cardcolor.h"
HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, int width, int height);
void PaintRect(HDC hdc, RECT *rect, COLORREF colour);
CardRegion::CardRegion(CardWindow &parent, int Id, bool visible, int x, int y, int xOffset, int yOffset)
: id(Id), parentWnd(parent), xpos(x), ypos(y), xoffset(xOffset), yoffset(yOffset), fVisible(visible)
{
width = __cardwidth;
height = __cardheight;
crBackgnd = RGB(0, 64, 100);
uFaceDirType = CS_FACE_UP;
nFaceDirOption = 0;
uEmptyImage = CS_EI_SUNK;
fVisible = visible;
nThreedCount = 1;
Update(); //Update this stack's size+card count
hdcBackGnd = 0;
hbmBackGnd = 0;
hdcDragCard = 0;
hbmDragCard = 0;
nDragCardWidth = 0;
nDragCardHeight = 0;
CanDragCallback = 0;
CanDropCallback = 0;
AddCallback = 0;
RemoveCallback = 0;
ClickCallback = 0;
DblClickCallback = 0;
uDragRule = CS_DRAG_ALL;
uDropRule = CS_DROP_ALL;
xjustify = yjustify = xadjust = yadjust = 0;
nFlashCount = 0;
fFlashVisible = false;
uFlashTimer = (UINT)-1;
fMouseDragging = false;
mxlock = CreateMutex(0, FALSE, 0);
}
CardRegion::~CardRegion()
{
CloseHandle(mxlock);
}
void CardRegion::SetBackColor(COLORREF cr)
{
crBackgnd = cr;
}
int CardRegion::CalcApparentCards(int realnum)
{
return ((realnum + nThreedCount - 1) - (realnum + nThreedCount - 1) % nThreedCount) / nThreedCount;
}
void CardRegion::CalcApparentCards()
{
nNumApparentCards = CalcApparentCards(cardstack.NumCards());
}
void CardRegion::UpdateSize(void)
{
if(cardstack.NumCards() > 0)
{
if(xoffset > 0)
width = (nNumApparentCards - 1) * xoffset + __cardwidth;
else
width = (nNumApparentCards - 1) * -xoffset + __cardwidth;
if(yoffset > 0)
height = (nNumApparentCards - 1) * yoffset + __cardheight;
else
height = (nNumApparentCards - 1) * -yoffset + __cardheight;
}
else
{
width = __cardwidth;
height = __cardheight;
}
}
CardRegion *CardWindow::CreateRegion(int id, bool fVisible, int x, int y, int xoffset, int yoffset)
{
CardRegion *cr;
if(nNumCardRegions == MAXCARDSTACKS)
return FALSE;
cr = new CardRegion(*this, id, fVisible, x, y, xoffset, yoffset);
cr->SetBackColor(crBackgnd);
cr->SetBackCardIdx(nBackCardIdx);
Regions[nNumCardRegions++] = cr;
return cr;
}
int CardRegion::GetOverlapRatio(int x, int y, int w, int h)
{
RECT me, him;
RECT inter;
SetRect(&him, x, y, x+w, y+h);
SetRect(&me, xpos, ypos, xpos+width, ypos+height);
//see if the specified rectangle overlaps us
if(IntersectRect(&inter, &me, &him))
{
int wi = inter.right - inter.left;
int hi = inter.bottom - inter.top;
int overlap = wi * hi;
int total = width * height;
int percent = (overlap << 16) / total;
return (percent * 100) >> 16;
}
//do not overlap
else
{
return 0;
}
}
bool CardRegion::SetDragRule(UINT uDragType, pCanDragProc proc)
{
switch(uDragType)
{
case CS_DRAG_NONE: case CS_DRAG_ALL: case CS_DRAG_TOP:
uDragRule = uDragType;
return true;
case CS_DRAG_CALLBACK:
uDragRule = uDragType;
CanDragCallback = proc;
return true;
default:
return false;
}
}
bool CardRegion::SetDropRule(UINT uDropType, pCanDropProc proc)
{
switch(uDropType)
{
case CS_DROP_NONE: case CS_DROP_ALL:
uDropRule = uDropType;
return true;
case CS_DROP_CALLBACK:
uDropRule = uDropType;
CanDropCallback = proc;
return true;
default:
return false;
}
}
void CardRegion::SetClickProc(pClickProc proc)
{
ClickCallback = proc;
}
void CardRegion::SetDblClickProc(pClickProc proc)
{
DblClickCallback = proc;
}
void CardRegion::SetAddCardProc(pAddProc proc)
{
AddCallback = proc;
}
void CardRegion::SetRemoveCardProc(pRemoveProc proc)
{
RemoveCallback = proc;
}
void CardRegion::Update()
{
CalcApparentCards();
UpdateSize();
UpdateFaceDir(cardstack);
}
bool CardRegion::SetThreedCount(int count)
{
if(count < 1)
{
return false;
}
else
{
nThreedCount = count;
return true;
}
}
void CardRegion::SetOffsets(int x, int y)
{
xoffset = x;
yoffset = y;
}
void CardRegion::SetPos(int x, int y)
{
xpos = x;
ypos = y;
}
void CardRegion::Show(bool fShow)
{
fVisible = fShow;
}
bool CardRegion::IsVisible()
{
return fVisible;
}
void CardRegion::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust)
{
xjustify = xJustify;
yjustify = yJustify;
xadjust = xAdjust;
yadjust = yAdjust;
}
void CardRegion::SetFaceDirection(UINT uDirType, int nOption)
{
switch(uDirType)
{
case CS_FACE_UP: case CS_FACE_DOWN: case CS_FACE_DOWNUP:
case CS_FACE_UPDOWN: case CS_FACE_ANY:
uFaceDirType = uDirType;
nFaceDirOption = nOption;
UpdateFaceDir(cardstack);
break;
}
}
UINT CardRegion::GetFaceDirection(int *pnOption)
{
if(pnOption)
*pnOption = nFaceDirOption;
return uFaceDirType;
}
void CardRegion::AdjustPosition(int winwidth, int winheight)
{
Update(); //Update this stack's card count + size
switch(xjustify)
{
default: case CS_XJUST_NONE: break;
case CS_XJUST_CENTER: //centered
xpos = (winwidth - (width & ~0x1)) / 2;
xpos += xadjust;
if(xoffset < 0) xpos += (width - __cardwidth);
break;
case CS_XJUST_RIGHT: //right-aligned
xpos = winwidth - __cardwidth;//width - 20;
xpos += xadjust;
break;
}
switch(yjustify)
{
default: case CS_YJUST_NONE: break;
case CS_YJUST_CENTER: //centered
ypos = (winheight - height) / 2;
ypos += yadjust;
if(yoffset < 0) ypos += (height - __cardheight);
break;
case CS_YJUST_BOTTOM: //bottom-aligned
ypos = winheight - __cardheight;//height - 20;
ypos += yadjust;
break;
}
}
void CardRegion::Flash(int count, int milliseconds)
{
if(count <= 0) return;
nFlashCount = count;
fFlashVisible = false;
uFlashTimer = SetTimer((HWND)parentWnd, (WPARAM)this, milliseconds, 0);
parentWnd.Redraw();
}
void CardRegion::StopFlash()
{
if(uFlashTimer != (UINT)-1)
{
KillTimer((HWND)parentWnd, uFlashTimer);
nFlashCount = 0;
uFlashTimer = (UINT)-1;
fFlashVisible = true;
}
}
void CardRegion::DoFlash()
{
if(uFlashTimer != (UINT)-1)
{
fFlashVisible = !fFlashVisible;
if(--nFlashCount == 0)
{
KillTimer((HWND)parentWnd, uFlashTimer);
uFlashTimer = (UINT)-1;
fFlashVisible = true;
}
parentWnd.Redraw();
}
}
int CardRegion::Id()
{
return id;
}
void CardRegion::SetEmptyImage(UINT uImage)
{
switch(uImage)
{
case CS_EI_NONE:
case CS_EI_SUNK:
case CS_EI_CIRC:
case CS_EI_X:
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)
{
if(pDestStack->CanDropCards(cardstack))
{
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 xpos; //coordinates of stack
int ypos;
int xoffset; //direction that cards take
int yoffset;
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,629 @@
//
// CardLib - CardRegion drawing support
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <stdlib.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:
DrawCard(hdc, x, y, __hdcPlaceHolder, __cardwidth, __cardheight);
break;
case CS_EI_CIRC:
case CS_EI_X:
CardBlt(hdc, x, y, uEmptyImage);
break;
}
}
return;
}
int calc_offset(int offset, int numcards, int numtodrag, int realvisible)
{
if(offset >= 0)
return -offset * numcards;
else
return -offset * (numtodrag) +
-offset * (realvisible - 1);
}
void CardRegion::PrepareDragBitmaps(int numtodrag)
{
RECT rect;
HDC hdc;
int icard;
int numcards = cardstack.NumCards();
int xoff, yoff;
if(nThreedCount > 1)
{
PrepareDragBitmapsThreed(numtodrag);
return;
}
//work out how big the bitmaps need to be
nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth;
nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight;
//Create bitmap for the back-buffer
hdc = GetDC(NULL);
hdcBackGnd = CreateCompatibleDC(hdc);
hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcBackGnd, hbmBackGnd);
//Create bitmap for the drag-image
hdcDragCard = CreateCompatibleDC(hdc);
hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcDragCard, hbmDragCard);
ReleaseDC(NULL, hdc);
UseNicePalette(hdcBackGnd, __hPalette);
UseNicePalette(hdcDragCard, __hPalette);
int realvisible = numcards / nThreedCount;
//if(numcards > 0 && realvisible == 0) realvisible = 1;
int iwhichcard = numcards - 1;
if(nThreedCount == 1) iwhichcard = 0;
//grab the first bit of background so we can prep the back buffer; do this by
//rendering the card stack (minus the card we are dragging) to the temporary
//background buffer, so it appears if we have lifted the card from the stack
//PaintRect(hdcBackGnd, &rect, crBackgnd);
SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight);
xoff = calc_offset(xoffset, numcards, numtodrag, realvisible);
yoff = calc_offset(yoffset, numcards, numtodrag, realvisible);
parentWnd.PaintCardRgn(hdcBackGnd, 0, 0, nDragCardWidth, nDragCardHeight, xpos - xoff, ypos - yoff);
//
// Render the cardstack into the back-buffer. The stack
// has already had the dragcards removed, so just draw
// what is left
//
for(icard = 0; icard < realvisible; icard++)
{
Card card = cardstack.cardlist[iwhichcard];
int nCardVal;
nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
xoff = xoffset * icard + calc_offset(xoffset, numcards, numtodrag, realvisible);//- xoffset * ((numcards+numtodrag) / nThreedCount - numtodrag);
yoff = yoffset * icard + calc_offset(yoffset, numcards, numtodrag, realvisible);//- yoffset * ((numcards+numtodrag) / nThreedCount - numtodrag);
CardBlt(hdcBackGnd, xoff, yoff, nCardVal);
iwhichcard++;
}
//
// If there are no cards under this one, just draw the place holder
//
if(numcards == 0)
{
int xoff = 0, yoff = 0;
if(xoffset < 0) xoff = nDragCardWidth - __cardwidth;
if(yoffset < 0) yoff = nDragCardHeight - __cardheight;
switch(uEmptyImage)
{
case CS_EI_NONE:
//No need to draw anything: We already cleared the
//back-buffer before the main loop..
//SetRect(&rc, xoff, yoff, xoff+ __cardwidth, yoff + __cardheight);
//PaintRect(hdcBackGnd, &rc, MAKE_PALETTERGB(crBackgnd));
//parentWnd.PaintCardRgn(hdcBackGnd, xoff, yoff, __cardwidth, __cardheight, xpos, ypos);// + xoff, ypos + yoff);
break;
case CS_EI_SUNK:
DrawCard(hdcBackGnd, xoff, yoff, __hdcPlaceHolder, __cardwidth, __cardheight);
break;
case CS_EI_CIRC:
case CS_EI_X:
CardBlt(hdc, xoff, yoff, uEmptyImage);
break;
}
}
//
// now render the drag-cards into the dragcard image
//
PaintRect(hdcDragCard, &rect, crBackgnd);
for(icard = 0; icard < numtodrag; icard++)
{
int nCardVal;
if(xoffset >= 0) xoff = xoffset * icard;
else xoff = -xoffset * (numtodrag - icard - 1);
if(yoffset >= 0) yoff = yoffset * icard;
else yoff = -yoffset * (numtodrag - icard - 1);
Card card = dragstack.cardlist[icard];
nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
CardBlt(hdcDragCard, xoff, yoff, nCardVal);
}
}
void CardRegion::PrepareDragBitmapsThreed(int numtodrag)
{
RECT rect;
HDC hdc;
int icard;
int numunder = 0;
int iwhichcard;
int numcards = cardstack.NumCards();
//work out how big the bitmaps need to be
nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth;
nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight;
//Create bitmap for the back-buffer
hdc = GetDC(NULL);
hdcBackGnd = CreateCompatibleDC(hdc);
hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcBackGnd, hbmBackGnd);
//create bitmap for the drag-image
hdcDragCard = CreateCompatibleDC(hdc);
hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight);
SelectObject(hdcDragCard, hbmDragCard);
ReleaseDC(NULL, hdc);
UseNicePalette(hdcBackGnd, __hPalette);
UseNicePalette(hdcDragCard, __hPalette);
//grab the first bit of background so we can prep the back buffer; do this by
//rendering the card stack (minus the card we are dragging) to the temporary
//background buffer, so it appears if we have lifted the card from the stack
//--SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight);
//--PaintRect(hdcBackGnd, &rect, crBackgnd);
int threedadjust = numcards % nThreedCount == 0;
numunder = CalcApparentCards(numcards);
iwhichcard = (numcards+numtodrag) - numunder - 1;
if(nThreedCount == 1) iwhichcard = 0;
int xoff = calc_offset(xoffset, numunder, numtodrag, numunder);
int yoff = calc_offset(yoffset, numunder, numtodrag, numunder);
parentWnd.PaintCardRgn(hdcBackGnd, 0,0, nDragCardWidth,nDragCardHeight, xpos - xoff,ypos - yoff);
//
// Render the cardstack into the back-buffer. The stack
// has already had the dragcards removed, so just draw
// what is left
//
for(icard = 0; icard < numunder; icard++)
{
Card card = cardstack.cardlist[iwhichcard];
int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
CardBlt(hdcBackGnd,
xoffset * icard - xoffset*(numunder-numtodrag+threedadjust),
yoffset * icard - yoffset*(numunder-numtodrag+threedadjust),
nCardVal);
iwhichcard++;
}
//
// If there are no cards under this one, just draw the place holder
//
if(numcards == 0)
{
switch(uEmptyImage)
{
case CS_EI_NONE:
//no need! we've already cleared the whole
//back-buffer before the main loop!
//SetRect(&rect, 0, 0, __cardwidth, __cardheight);
//PaintRect(hdcBackGnd, &rect, MAKE_PALETTERGB(crBackgnd));
break;
case CS_EI_SUNK:
DrawCard(hdcBackGnd, 0, 0, __hdcPlaceHolder, __cardwidth, __cardheight);
break;
case CS_EI_CIRC:
case CS_EI_X:
CardBlt(hdc, 0, 0, uEmptyImage);
break;
}
}
//
// now render the drag-cards into the dragcard image
//
PaintRect(hdcDragCard, &rect, crBackgnd);
for(icard = 0; icard < numtodrag; icard++)
{
Card card = dragstack.cardlist[icard];
int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx;
CardBlt(hdcDragCard, xoffset * icard, yoffset * icard, nCardVal);
}
}
void CardRegion::ReleaseDragBitmaps(void)
{
//SelectObject(hdcBackGnd, hOld1);
DeleteObject(hbmBackGnd);
DeleteDC(hdcBackGnd);
//SelectObject(hdcDragCard, hOld2);
DeleteObject(hbmDragCard);
DeleteDC(hdcDragCard);
}
void CardRegion::Redraw()
{
HDC hdc = GetDC((HWND)parentWnd);
Update();
Render(hdc);
ReleaseDC((HWND)parentWnd, hdc);
}

View file

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

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,817 @@
//
// CardLib - CardWindow class
//
// Freeware
// Copyright J Brown 2001
//
#include <windows.h>
#include <tchar.h>
#include <stdlib.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;
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);
}
UINT CardWindow::GetBackCardIdx()
{
return nBackCardIdx;
}
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,120 @@
#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);
UINT GetBackCardIdx();
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;
}

39
reactos/lib/3rdparty/cardlib/dropzone.h vendored Normal file
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

15
reactos/lib/3rdparty/cardlib/globals.h vendored Normal file
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