diff --git a/rosapps/games/solitaire/ReadMe.txt b/rosapps/games/solitaire/ReadMe.txt new file mode 100644 index 00000000000..90bd89b225b --- /dev/null +++ b/rosapps/games/solitaire/ReadMe.txt @@ -0,0 +1,22 @@ +Solitaire for ReactOS + +/***************************************** +A complete working example of the CardLib +card-game library. + +Freeware +Copyright J Brown 2001 + +Updates at http://www.catch22.net + +******************************************/ + +The author has given permission to use these sources +under Public Domain. Do what thou will but please give +credit where credit is due. + +If you wish to use cardlib to write another card game +for ReactOS please make cardlib a static lib. + +-sedwards + diff --git a/rosapps/games/solitaire/cardlib/card.h b/rosapps/games/solitaire/cardlib/card.h new file mode 100644 index 00000000000..13dc19055c2 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/card.h @@ -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 diff --git a/rosapps/games/solitaire/cardlib/cardbitmaps.cpp b/rosapps/games/solitaire/cardlib/cardbitmaps.cpp new file mode 100644 index 00000000000..530f6517721 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardbitmaps.cpp @@ -0,0 +1,281 @@ +// +// CardLib - Card bitmap support +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include "globals.h" +#include "cardcolor.h" + +#ifndef __REACTOS__ +#pragma comment( lib, "..\\CardLib\\cards16.lib" ) + +extern "C" HINSTANCE WINAPI LoadLibrary16( PSTR ); +extern "C" void WINAPI FreeLibrary16( HINSTANCE ); +#endif + +#define NUMCARDBITMAPS (52+16) + +void PaintRect(HDC hdc, RECT *rect, COLORREF col); + +void LoadCardBitmapsFromLibrary(HINSTANCE hCardDll, int *pwidth, int *pheight) +{ + HBITMAP hBitmap; + HDC hdcCard; + HANDLE hOld; + int i, xpos; + int width, height; + BITMAP bmp; + + for(i = 0; i < NUMCARDBITMAPS; i++) + { + //convert into the range used by the cdt_xxx functions + int val; + + if(i < 52) val = (i % 4) * 13 + (i/4); + else val = i; + + hBitmap = LoadBitmap(hCardDll, MAKEINTRESOURCE(val + 1)); + GetObject(hBitmap, sizeof(bmp), &bmp); + + width = bmp.bmWidth; + height = bmp.bmHeight; + + if(i == 0) //if first time through, create BIG bitmap.. + { + HDC hdc = GetDC(0); + __hdcCardBitmaps = CreateCompatibleDC(hdc); + __hbmCardBitmaps = CreateCompatibleBitmap(hdc, width * NUMCARDBITMAPS, height); + SelectObject(__hdcCardBitmaps, __hbmCardBitmaps); + + hdcCard = CreateCompatibleDC(0); + + ReleaseDC(0, hdc); + } + + hOld = SelectObject(hdcCard, hBitmap); + BitBlt(__hdcCardBitmaps, i*width, 0, width, height, hdcCard, 0, 0, SRCCOPY); + SelectObject(hdcCard, hOld); + + //Now draw a black border around each card... + xpos = i*width; + MoveToEx(__hdcCardBitmaps, xpos+2, 0, 0); + LineTo(__hdcCardBitmaps, xpos+width - 3, 0); + LineTo(__hdcCardBitmaps, xpos+width - 1, 2); + LineTo(__hdcCardBitmaps, xpos+width - 1, height - 3); //vertical + LineTo(__hdcCardBitmaps, xpos+width - 3, height - 1); + LineTo(__hdcCardBitmaps, xpos+2, height - 1); + LineTo(__hdcCardBitmaps, xpos+0, height - 3); + LineTo(__hdcCardBitmaps, xpos+0, 2); + LineTo(__hdcCardBitmaps, xpos+2, 0); + + DeleteObject(hBitmap); + } + + DeleteDC(hdcCard); + + *pwidth = width; + *pheight = height; + +} + +void LoadCardBitmaps(void) +{ + HINSTANCE hCardDll; + + + //If Windows NT/2000/XP + if(GetVersion() < 0x80000000) + { + hCardDll = LoadLibrary("cards.dll"); + + if(hCardDll == 0) + { + MessageBox(0, "Error loading cards.dll (32bit)", "Shed", MB_OK | MB_ICONEXCLAMATION); + PostQuitMessage(0); + return; + } + + LoadCardBitmapsFromLibrary(hCardDll, &__cardwidth, &__cardheight); + + FreeLibrary(hCardDll); + } +#ifndef __REACTOS__ + //Else, Win9X + else + { + hCardDll = LoadLibrary16("cards.dll"); + + if(hCardDll == 0) + { + MessageBox(0, "Error loading cards.dll (16bit)", "Shed", MB_OK | MB_ICONEXCLAMATION); + PostQuitMessage(0); + return; + } + + LoadCardBitmapsFromLibrary(hCardDll, &__cardwidth, &__cardheight); + + FreeLibrary16(hCardDll); + } +#endif +} + +void FreeCardBitmaps() +{ + DeleteObject (__hbmCardBitmaps); + DeleteDC (__hdcCardBitmaps); +} +// +// Paint a checkered rectangle, with each alternate +// pixel being assigned a different colour +// +static void DrawCheckedRect(HDC hdc, RECT *rect, COLORREF fg, COLORREF bg) +{ + static WORD wCheckPat[8] = + { + 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555 + }; + + HBITMAP hbmp; + HBRUSH hbr, hbrold; + COLORREF fgold, bgold; + + hbmp = CreateBitmap(8, 8, 1, 1, wCheckPat); + hbr = CreatePatternBrush(hbmp); + + //UnrealizeObject(hbr); + + SetBrushOrgEx(hdc, rect->left, rect->top, 0); + + hbrold = (HBRUSH)SelectObject(hdc, hbr); + + fgold = SetTextColor(hdc, fg); + bgold = SetBkColor(hdc, bg); + + PatBlt(hdc, rect->left, rect->top, + rect->right - rect->left, + rect->bottom - rect->top, + PATCOPY); + + SetBkColor(hdc, bgold); + SetTextColor(hdc, fgold); + + SelectObject(hdc, hbrold); + DeleteObject(hbr); + DeleteObject(hbmp); +} + +void GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2) +{ + if(bg) *bg = crBase; + if(fg) *fg = ColorScaleRGB(crBase, RGB(255,255,255), 0.2);//RGB(49, 99, 140); + if(sh1) *sh1 = ColorScaleRGB(crBase, RGB(0,0,0), 0.4); + if(sh2) *sh2 = ColorScaleRGB(crBase, RGB(0,0,0), 0.2); +} + +HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height) +{ + HANDLE hold, hpold; + HBITMAP hbm = CreateCompatibleBitmap(hdcCompat, width, height); + + HPEN hpfg, hpbg, hpsh, hpsh2; + + RECT rect; + COLORREF fg, bg, shadow, shadow2; + + GetSinkCols(col, &fg, &bg, &shadow, &shadow2); + + hold = SelectObject(hdc, hbm); + + //fill with a solid base colour + SetRect(&rect, 0,0,width,height); + PaintRect(hdc, &rect, MAKE_PALETTERGB(bg)); + + //draw the outline + hpfg = CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(fg)); + hpbg = CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(bg)); + hpsh = CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(shadow)); + hpsh2= CreatePen(PS_SOLID, 0, MAKE_PALETTERGB(shadow2)); + + hpold = SelectObject(hdc, hpsh); + MoveToEx(hdc, 2, 0, NULL); + LineTo (hdc, width-3,0); + LineTo (hdc, width-1, 2); + + SelectObject(hdc, hpold); + hpold = SelectObject(hdc, hpsh2); + LineTo (hdc, width-1, height-3); //vertical + LineTo (hdc, width-3, height-1); + LineTo (hdc, 2, height-1); + LineTo (hdc, 0, height-3); + SelectObject(hdc, hpold); + hpold = SelectObject(hdc, hpsh); + + //MoveToEx( hdc, 0, height-3,0); + LineTo (hdc, 0, 2); + LineTo (hdc, 2, 0); + + SelectObject(hdc, hpold); + + //draw the highlight (vertical) + hpold = SelectObject(hdc, hpfg); + MoveToEx(hdc, width - 2, 3, NULL); + LineTo (hdc, width - 2, height - 2); + + //(horz) + MoveToEx(hdc, width - 3, height-2, NULL); + LineTo (hdc, 3, height-2); + SelectObject(hdc, hpold); + + //draw the background + InflateRect(&rect, -2, -2); + DrawCheckedRect(hdc, &rect, MAKE_PALETTERGB(bg), MAKE_PALETTERGB(fg)); + + //overwrite the top-left background pixel + SetPixel(hdc, 2, 2, MAKE_PALETTERGB(bg)); + + DeleteObject(hpsh); + DeleteObject(hpsh2); + DeleteObject(hpfg); + DeleteObject(hpbg); + + + return hbm; +} + + + +void CopyColor(PALETTEENTRY *pe, COLORREF col) +{ + pe->peBlue = GetBValue(col); + pe->peGreen = GetGValue(col); + pe->peRed = GetRValue(col); + pe->peFlags = 0; +} + +HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours) +{ + LOGPALETTE *lp; + HPALETTE hPalette; + + // Allocate memory for the logical palette + lp = (LOGPALETTE *)HeapAlloc( + GetProcessHeap(), 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * nNumColours); + + lp->palNumEntries = nNumColours; + lp->palVersion = 0x300; + + //copy the colours into the logical palette format + for(int i = 0; i < nNumColours; i++) + { + CopyColor(&lp->palPalEntry[i], cols[i]); + } + + // create palette! + hPalette = CreatePalette(lp); + + HeapFree(GetProcessHeap(), 0, lp); + + return hPalette; +} diff --git a/rosapps/games/solitaire/cardlib/cardbutton.cpp b/rosapps/games/solitaire/cardlib/cardbutton.cpp new file mode 100644 index 00000000000..a0a2b3a9f6c --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardbutton.cpp @@ -0,0 +1,489 @@ +// +// CardLib - CardButton class +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include + +#include "cardlib.h" +#include "cardwindow.h" +#include "cardbutton.h" +#include "cardcolor.h" + +HPALETTE UseNicePalette(HDC, HPALETTE); +void RestorePalette(HDC, HPALETTE); + +void PaintRect(HDC hdc, RECT *rect, COLORREF colour); + +CardButton::CardButton(CardWindow &parent, int Id, TCHAR *szText, UINT Style, bool visible, + int x, int y, int width, int height) + + : parentWnd(parent), id(Id), fVisible(visible), uStyle(Style), ButtonCallback(0) +{ + crText = RGB(255,255,255); + crBack = RGB(0, 128, 0); + + xadjust = 0; + yadjust = 0; + xjustify = 0; + yjustify = 0; + + fMouseDown = false; + fButtonDown = false; + + hIcon = 0; + + SetText(szText); + Move(x, y, width, height); + + mxlock = CreateMutex(0, FALSE, 0); + + hFont = 0; +} + +CardButton::~CardButton() +{ + CloseHandle(mxlock); +} + +void CardButton::DrawRect(HDC hdc, RECT *rect, bool fNormal) +{ + RECT fill; + + HANDLE hOld; + + HPEN hhi = CreatePen(0, 0, MAKE_PALETTERGB(crHighlight)); + HPEN hsh = CreatePen(0, 0, MAKE_PALETTERGB(crShadow)); + HPEN hbl = (HPEN)GetStockObject(BLACK_PEN); + + int x = rect->left; + int y = rect->top; + int width = rect->right-rect->left - 1; + int height = rect->bottom-rect->top - 1; + + SetRect(&fill, x+1, y+1, x+width-1, y+height-1); + + int one = 1; + + if(!fNormal) + { + x += width; + y += height; + width = -width; + height = -height; + one = -1; + OffsetRect(&fill, 1, 1); + } + + if(fNormal) + hOld = SelectObject(hdc, hhi); + else + hOld = SelectObject(hdc, hhi); + + MoveToEx(hdc, x, y+height, 0); + LineTo(hdc, x, y); + LineTo(hdc, x+width, y); + SelectObject(hdc, hOld); + + hOld = SelectObject(hdc, hbl); + LineTo(hdc, x+width, y+height); + LineTo(hdc, x-one, y+height); + SelectObject(hdc, hOld); + + hOld = SelectObject(hdc, hsh); + MoveToEx(hdc, x+one, y+height-one, 0); + LineTo(hdc, x+width-one, y+height-one); + LineTo(hdc, x+width-one, y); + SelectObject(hdc, hOld); + + PaintRect(hdc, &fill, MAKE_PALETTERGB(crBack)); + + DeleteObject(hhi); + DeleteObject(hsh); +} + +void CardButton::Clip(HDC hdc) +{ + if(fVisible == false) return; + + ExcludeClipRect(hdc, rect.left, rect.top, rect.right, rect.bottom); +} + +void CardButton::Draw(HDC hdc, bool fNormal) +{ + SIZE textsize; + int x, y; //text x, y + int ix, iy; //icon x, y + int iconwidth = 0; + + RECT cliprect; + + if(fVisible == 0) return; + + if(hFont == 0) + SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + else + SelectObject(hdc, hFont); + + GetTextExtentPoint32(hdc, szText, lstrlen(szText), &textsize); + + if(hIcon) + { + x = rect.left + 32 + 8; + } + else + { + if(uStyle & CB_ALIGN_LEFT) + { + x = rect.left + iconwidth; + } + else if(uStyle & CB_ALIGN_RIGHT) + { + x = rect.left + (rect.right-rect.left-iconwidth-textsize.cx); + } + else //centered + { + x = rect.right - rect.left - iconwidth; + x = (x - textsize.cx) / 2; + x += rect.left + iconwidth; + } + } + + y = rect.bottom - rect.top; + y = (y - textsize.cy) / 2; + y += rect.top; + + //calc icon position.. + ix = rect.left + 4; + iy = rect.top + (rect.bottom-rect.top-32) / 2; + + //if button is pressed, then shift text + if(fNormal == false && (uStyle & CB_PUSHBUTTON)) + { + x += 1; + y += 1; + ix += 1; + iy += 1; + } + + SetRect(&cliprect, x, y, x+textsize.cx, y+textsize.cy); + ExcludeClipRect(hdc, x, y, x+textsize.cx, y+textsize.cy); + + // + // Calc icon pos + // + + if(hIcon) + { + ExcludeClipRect(hdc, ix, iy, ix + 32, iy + 32); + } + + if(uStyle & CB_PUSHBUTTON) + { + DrawRect(hdc, &rect, fNormal); + + SetBkColor(hdc, MAKE_PALETTERGB(crBack)); + SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText)); + + SelectClipRgn(hdc, 0); + + ExtTextOut(hdc, x, y, ETO_OPAQUE, &cliprect, szText, lstrlen(szText), 0); + } + else + { + SetBkColor(hdc, MAKE_PALETTERGB(crBack)); + SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText)); + + SelectClipRgn(hdc, 0); + + ExtTextOut(hdc, x, y, ETO_OPAQUE, &rect, szText, lstrlen(szText), 0); + } + + if(hIcon) + { + HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBack)); + DrawIconEx(hdc, ix, iy, hIcon, 32, 32, 0, hbr, 0); + DeleteObject(hbr); + } + +} + +void CardButton::AdjustPosition(int winwidth, int winheight) +{ + int width = rect.right-rect.left; + int height = rect.bottom-rect.top; + + width = width & ~0x1; + + switch(xjustify) + { + case CS_XJUST_NONE: + break; + + case CS_XJUST_CENTER: //centered + rect.left = (winwidth - (width)) / 2; + rect.left += xadjust; + rect.right = rect.left+width; + break; + + case CS_XJUST_RIGHT: //right-aligned + rect.left = winwidth - width; + rect.left += xadjust; + rect.right = rect.left+width; + break; + } + + switch(yjustify) + { + case CS_YJUST_NONE: + break; + + case CS_YJUST_CENTER: //centered + rect.top = (winheight - (height)) / 2; + rect.top += yadjust; + rect.bottom = rect.top+height; + break; + + case CS_YJUST_BOTTOM: //right-aligned + rect.top = winheight - height; + rect.top += yadjust; + rect.bottom = rect.top+height; + break; + } + +} + +int CardButton::OnLButtonDown(HWND hwnd, int x, int y) +{ + if((uStyle & CB_PUSHBUTTON) == 0) + return 0; + + //make sure that the user is allowed to do something + if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0) + { + return 0; + } + else + { + ReleaseMutex(mxlock); + } + + fMouseDown = true; + fButtonDown = true; + + Redraw(); + + SetCapture(hwnd); + + return 1; +} + +int CardButton::OnMouseMove(HWND hwnd, int x, int y) +{ + if(fMouseDown) + { + bool fOldButtonDown = fButtonDown; + + POINT pt; + + pt.x = x; + pt.y = y; + + if(PtInRect(&rect, pt)) + fButtonDown = true; + else + fButtonDown = false; + + if(fButtonDown != fOldButtonDown) + Redraw(); + } + + return 0; +} + +int CardButton::OnLButtonUp(HWND hwnd, int x, int y) +{ + if(fMouseDown) + { + fMouseDown = false; + fButtonDown = false; + + if(uStyle & CB_PUSHBUTTON) + { + Redraw(); + ReleaseCapture(); + } + + //if have clicked the button + if(parentWnd.CardButtonFromPoint(x, y) == this) + { + if(ButtonCallback) + { + ButtonCallback(*this); + } + else + { + HWND hwnd = (HWND)parentWnd; + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(id, BN_CLICKED), (LONG)hwnd); + } + } + } + + return 0; +} + +#define _countof(array) (sizeof(array)/sizeof(array[0])) + +CardButton *CardWindow::CreateButton(int id, TCHAR *szText, UINT uStyle, bool fVisible, int x, int y, int width, int height) +{ + CardButton *cb; + + if(nNumButtons == MAXBUTTONS) + return 0; + + cb = new CardButton(*this, id, szText, uStyle, fVisible, x, y, width, height); + Buttons[nNumButtons++] = cb; + + if(uStyle & CB_PUSHBUTTON) + { + cb->SetBackColor(CardButton::GetFace(crBackgnd)); + //cb->SetBackColor(ScaleLumRGB(crBackgnd, 0.1)); + cb->SetForeColor(RGB(255,255,255)); + } + else + { + cb->SetBackColor(crBackgnd); + cb->SetForeColor(RGB(255,255,255)); + } + + return cb; +} + +void CardButton::SetText(TCHAR *lpszFormat, ...) +{ + int count; + + va_list args; + va_start(args, lpszFormat); + + count = wvsprintf(szText, lpszFormat, args); + va_end(args); +} + +int CardButton::Id() +{ + return id; +} + +void CardButton::Show(bool fShow) +{ + fVisible = fShow; +} + +void CardButton::Move(int x, int y, int width, int height) +{ + SetRect(&rect, x, y, x+width, y+height); +} + +void CardButton::Redraw() +{ + HDC hdc = GetDC((HWND)parentWnd); + + HPALETTE hOldPal = UseNicePalette(hdc, __hPalette); + + Draw(hdc, !fButtonDown); + + RestorePalette(hdc, hOldPal); + + ReleaseDC((HWND)parentWnd, hdc); +} + +void CardButton::SetForeColor(COLORREF cr) +{ + crText = cr; +} + +void CardButton::SetBackColor(COLORREF cr) +{ + crBack = cr; + + crHighlight = GetHighlight(cr); + crShadow = GetShadow(cr); + + //crHighlight = ScaleLumRGB(cr, +0.25); + //crShadow = ScaleLumRGB(cr, -0.25); +} + +// Static member +COLORREF CardButton::GetHighlight(COLORREF crBase) +{ + return ColorScaleRGB(crBase, RGB(255,255,255), 0.25); +} + +// Static member +COLORREF CardButton::GetShadow(COLORREF crBase) +{ + return ColorScaleRGB(crBase, RGB(0, 0, 0), 0.25); +} + +COLORREF CardButton::GetFace(COLORREF crBase) +{ + return ColorScaleRGB(crBase, RGB(255,255,255), 0.1); +} + +void CardButton::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust) +{ + xadjust = xAdjust; + yadjust = yAdjust; + xjustify = xJustify; + yjustify = yJustify; +} + +void CardButton::SetIcon(HICON hicon, bool fRedraw) +{ + hIcon = hicon; + + if(fRedraw) + Redraw(); +} + +void CardButton::SetFont(HFONT font) +{ + //don't delete the existing font.. + hFont = font; +} + +void CardButton::SetButtonProc(pButtonProc proc) +{ + ButtonCallback = proc; +} + +bool CardButton::Lock() +{ + DWORD dw = WaitForSingleObject(mxlock, 0); + + if(dw == WAIT_OBJECT_0) + return true; + else + return false; +} + +bool CardButton::UnLock() +{ + if(ReleaseMutex(mxlock)) + return true; + else + return false; +} + +void CardButton::SetStyle(UINT style) +{ + uStyle = style; +} + +UINT CardButton::GetStyle() +{ + return uStyle; +} diff --git a/rosapps/games/solitaire/cardlib/cardbutton.cpp.bak b/rosapps/games/solitaire/cardlib/cardbutton.cpp.bak new file mode 100644 index 00000000000..123f2543515 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardbutton.cpp.bak @@ -0,0 +1,489 @@ +// +// CardLib - CardButton class +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include + +#include "cardlib.h" +#include "cardwindow.h" +#include "cardbutton.h" +#include "cardcolor.h" + +HPALETTE UseNicePalette(HDC, HPALETTE); +void RestorePalette(HDC, HPALETTE); + +void PaintRect(HDC hdc, RECT *rect, COLORREF colour); + +CardButton::CardButton(CardWindow &parent, int Id, TCHAR *szText, UINT Style, bool visible, + int x, int y, int width, int height) + + : parentWnd(parent), id(Id), fVisible(visible), uStyle(Style), ButtonCallback(0) +{ + crText = RGB(255,255,255); + crBack = RGB(0, 128, 0); + + xadjust = 0; + yadjust = 0; + xjustify = 0; + yjustify = 0; + + fMouseDown = false; + fButtonDown = false; + + hIcon = 0; + + SetText(szText); + Move(x, y, width, height); + + mxlock = CreateMutex(0, FALSE, 0); + + hFont = 0; +} + +CardButton::~CardButton() +{ + CloseHandle(mxlock); +} + +void CardButton::DrawRect(HDC hdc, RECT *rect, bool fNormal) +{ + RECT fill; + + HANDLE hOld; + + HPEN hhi = CreatePen(0, 0, MAKE_PALETTERGB(crHighlight)); + HPEN hsh = CreatePen(0, 0, MAKE_PALETTERGB(crShadow)); + HPEN hbl = (HPEN)GetStockObject(BLACK_PEN); + + int x = rect->left; + int y = rect->top; + int width = rect->right-rect->left - 1; + int height = rect->bottom-rect->top - 1; + + SetRect(&fill, x+1, y+1, x+width-1, y+height-1); + + int one = 1; + + if(!fNormal) + { + x += width; + y += height; + width = -width; + height = -height; + one = -1; + OffsetRect(&fill, 1, 1); + } + + if(fNormal) + hOld = SelectObject(hdc, hhi); + else + hOld = SelectObject(hdc, hhi); + + MoveToEx(hdc, x, y+height, 0); + LineTo(hdc, x, y); + LineTo(hdc, x+width, y); + SelectObject(hdc, hOld); + + hOld = SelectObject(hdc, hbl); + LineTo(hdc, x+width, y+height); + LineTo(hdc, x-one, y+height); + SelectObject(hdc, hOld); + + hOld = SelectObject(hdc, hsh); + MoveToEx(hdc, x+one, y+height-one, 0); + LineTo(hdc, x+width-one, y+height-one); + LineTo(hdc, x+width-one, y); + SelectObject(hdc, hOld); + + PaintRect(hdc, &fill, MAKE_PALETTERGB(crBack)); + + DeleteObject(hhi); + DeleteObject(hsh); +} + +void CardButton::Clip(HDC hdc) +{ + if(fVisible == false) return; + + ExcludeClipRect(hdc, rect.left, rect.top, rect.right, rect.bottom); +} + +void CardButton::Draw(HDC hdc, bool fNormal) +{ + SIZE textsize; + int x, y; //text x, y + int ix, iy; //icon x, y + int iconwidth = 0; + + RECT cliprect; + + if(fVisible == 0) return; + + if(hFont == 0) + SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + else + SelectObject(hdc, hFont); + + GetTextExtentPoint32(hdc, szText, lstrlen(szText), &textsize); + + if(hIcon) + { + x = rect.left + 32 + 8; + } + else + { + if(uStyle & CB_ALIGN_LEFT) + { + x = rect.left + iconwidth; + } + else if(uStyle & CB_ALIGN_RIGHT) + { + x = rect.left + (rect.right-rect.left-iconwidth-textsize.cx); + } + else //centered + { + x = rect.right - rect.left - iconwidth; + x = (x - textsize.cx) / 2; + x += rect.left + iconwidth; + } + } + + y = rect.bottom - rect.top; + y = (y - textsize.cy) / 2; + y += rect.top; + + //calc icon position.. + ix = rect.left + 4; + iy = rect.top + (rect.bottom-rect.top-32) / 2; + + //if button is pressed, then shift text + if(fNormal == false && (uStyle & CB_PUSHBUTTON)) + { + x += 1; + y += 1; + ix += 1; + iy += 1; + } + + SetRect(&cliprect, x, y, x+textsize.cx, y+textsize.cy); + ExcludeClipRect(hdc, x, y, x+textsize.cx, y+textsize.cy); + + // + // Calc icon pos + // + + if(hIcon) + { + ExcludeClipRect(hdc, ix, iy, ix + 32, iy + 32); + } + + if(uStyle & CB_PUSHBUTTON) + { + DrawRect(hdc, &rect, fNormal); + + SetBkColor(hdc, MAKE_PALETTERGB(crBack)); + SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText)); + + SelectClipRgn(hdc, 0); + + ExtTextOut(hdc, x, y, ETO_OPAQUE, &cliprect, szText, lstrlen(szText), 0); + } + else + { + SetBkColor(hdc, MAKE_PALETTERGB(crBack)); + SetTextColor(hdc, crText);//MAKE_PALETTERGB(crText)); + + SelectClipRgn(hdc, 0); + + ExtTextOut(hdc, x, y, ETO_OPAQUE, &rect, szText, lstrlen(szText), 0); + } + + if(hIcon) + { + HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBack)); + DrawIconEx(hdc, ix, iy, hIcon, 32, 32, 0, hbr, 0); + DeleteObject(hbr); + } + +} + +void CardButton::AdjustPosition(int winwidth, int winheight) +{ + int width = rect.right-rect.left; + int height = rect.bottom-rect.top; + + width = width & ~0x1; + + switch(xjustify) + { + case CS_XJUST_NONE: + break; + + case CS_XJUST_CENTER: //centered + rect.left = (winwidth - (width)) / 2; + rect.left += xadjust; + rect.right = rect.left+width; + break; + + case CS_XJUST_RIGHT: //right-aligned + rect.left = winwidth - width; + rect.left += xadjust; + rect.right = rect.left+width; + break; + } + + switch(yjustify) + { + case CS_YJUST_NONE: + break; + + case CS_YJUST_CENTER: //centered + rect.top = (winheight - (height)) / 2; + rect.top += yadjust; + rect.bottom = rect.top+height; + break; + + case CS_YJUST_BOTTOM: //right-aligned + rect.top = winheight - height; + rect.top += yadjust; + rect.bottom = rect.top+height; + break; + } + +} + +int CardButton::OnLButtonDown(HWND hwnd, int x, int y) +{ + if((uStyle & CB_PUSHBUTTON) == 0) + return 0; + + //make sure that the user is allowed to do something + if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0) + { + return 0; + } + else + { + ReleaseMutex(mxlock); + } + + fMouseDown = true; + fButtonDown = true; + + Redraw(); + + SetCapture(hwnd); + + return 1; +} + +int CardButton::OnMouseMove(HWND hwnd, int x, int y) +{ + if(fMouseDown) + { + bool fOldButtonDown = fButtonDown; + + POINT pt; + + pt.x = x; + pt.y = y; + + if(PtInRect(&rect, pt)) + fButtonDown = true; + else + fButtonDown = false; + + if(fButtonDown != fOldButtonDown) + Redraw(); + } + + return 0; +} + +int CardButton::OnLButtonUp(HWND hwnd, int x, int y) +{ + if(fMouseDown) + { + fMouseDown = false; + fButtonDown = false; + + if(uStyle & CB_PUSHBUTTON) + { + Redraw(); + ReleaseCapture(); + } + + //if have clicked the button + if(parentWnd.CardButtonFromPoint(x, y) == this) + { + if(ButtonCallback) + { + ButtonCallback(*this); + } + else + { + HWND hwnd = (HWND)parentWnd; + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(id, BN_CLICKED), (LONG)hwnd); + } + } + } + + return 0; +} + +#define _countof(array) (sizeof(array)/sizeof(array[0])) + +CardButton *CardWindow::CreateButton(int id, TCHAR *szText, UINT uStyle, bool fVisible, int x, int y, int width, int height) +{ + CardButton *cb; + + if(nNumButtons == MAXBUTTONS) + return 0; + + cb = new CardButton(*this, id, szText, uStyle, fVisible, x, y, width, height); + Buttons[nNumButtons++] = cb; + + if(uStyle & CB_PUSHBUTTON) + { + cb->SetBackColor(CardButton::GetFace(crBackgnd)); + //cb->SetBackColor(ScaleLumRGB(crBackgnd, 0.1)); + cb->SetForeColor(RGB(255,255,255)); + } + else + { + cb->SetBackColor(crBackgnd); + cb->SetForeColor(RGB(255,255,255)); + } + + return cb; +} + +void CardButton::SetText(TCHAR *lpszFormat, ...) +{ + int count; + + va_list args; + va_start(args, lpszFormat); + + count = wvsprintf(szText, lpszFormat, args); + va_end(args); +} + +int CardButton::Id() +{ + return id; +} + +void CardButton::Show(bool fShow) +{ + fVisible = fShow; +} + +void CardButton::Move(int x, int y, int width, int height) +{ + SetRect(&rect, x, y, x+width, y+height); +} + +void CardButton::Redraw() +{ + HDC hdc = GetDC((HWND)parentWnd); + + HPALETTE hOldPal = UseNicePalette(hdc, __hPalette); + + Draw(hdc, !fButtonDown); + + RestorePalette(hdc, hOldPal); + + ReleaseDC((HWND)parentWnd, hdc); +} + +void CardButton::SetForeColor(COLORREF cr) +{ + crText = cr; +} + +void CardButton::SetBackColor(COLORREF cr) +{ + crBack = cr; + + crHighlight = GetHighlight(cr); + crShadow = GetShadow(cr); + + //crHighlight = ScaleLumRGB(cr, +0.25); + //crShadow = ScaleLumRGB(cr, -0.25); +} + +// Static member +COLORREF CardButton::GetHighlight(COLORREF crBase) +{ + return ColorScaleRGB(crBase, RGB(255,255,255), 0.25); +} + +// Static member +COLORREF CardButton::GetShadow(COLORREF crBase) +{ + return ColorScaleRGB(crBase, RGB(0, 0, 0), 0.25); +} + +COLORREF CardButton::GetFace(COLORREF crBase) +{ + return ColorScaleRGB(crBase, RGB(255,255,255), 0.1); +} + +void CardButton::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust) +{ + xadjust = xAdjust; + yadjust = yAdjust; + xjustify = xJustify; + yjustify = yJustify; +} + +void CardButton::SetIcon(HICON hicon, bool fRedraw) +{ + hIcon = hicon; + + if(fRedraw) + Redraw(); +} + +void CardButton::SetFont(HFONT font) +{ + //don't delete the existing font.. + hFont = font; +} + +void CardButton::SetButtonProc(pButtonProc proc) +{ + ButtonCallback = proc; +} + +bool CardButton::Lock() +{ + DWORD dw = WaitForSingleObject(mxlock, 0); + + if(dw == WAIT_OBJECT_0) + return true; + else + return false; +} + +bool CardButton::UnLock() +{ + if(ReleaseMutex(mxlock)) + return true; + else + return false; +} + +void CardButton::SetStyle(UINT style) +{ + uStyle = style; +} + +UINT CardButton::GetStyle() +{ + return uStyle; +} \ No newline at end of file diff --git a/rosapps/games/solitaire/cardlib/cardbutton.h b/rosapps/games/solitaire/cardlib/cardbutton.h new file mode 100644 index 00000000000..14be629e678 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardbutton.h @@ -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 diff --git a/rosapps/games/solitaire/cardlib/cardcolor.cpp b/rosapps/games/solitaire/cardlib/cardcolor.cpp new file mode 100644 index 00000000000..f82c9fa77a1 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardcolor.cpp @@ -0,0 +1,353 @@ +// +// Colour support +// +#include + +#define MakeRGB RGB + +#define MIN3(a,b,c) ( (a)<=(b) ? (a)<=(c)?(a):(c) : (b)<=(c)?(b):(c) ) +#define MAX3(a,b,c) ( (a)>=(b) ? (a)>=(c)?(a):(c) : (b)>=(c)?(b):(c) ) + +inline double fMax(double a, double b) +{ + return a < b ? b : a; +} + +inline double fMin(double a, double b) +{ + return a < b ? a : b; +} +/****************************************************************************** + FUNCTION: RGBtoHLS + PURPOSE: Convert from RGB to HLS + IN: RGB color (0xBBGGRR) + OUT: Hue, Saturation, Luminance from 0 to 1 + COPYRIGHT:1995-1997 Robert Mashlan + Modified for LabWindows/CVI, 1999 Guillaume Dargaud +******************************************************************************/ +void RGBtoHLS(const COLORREF rgb, double *H, double *L, double *S ) +{ + double delta; + double r = (double)((rgb )&0xFF)/255; + double g = (double)((rgb>> 8)&0xFF)/255; + double b = (double)((rgb>>16)&0xFF)/255; + double cmax = MAX3(r,g,b); + double cmin = MIN3(r,g,b); + *L=(cmax+cmin)/2.0; + + if(cmax == cmin) + { + *S = *H = 0; // it's really undefined + } + else + { + if(*L < 0.5) *S = (cmax-cmin)/(cmax+cmin); + else *S = (cmax-cmin)/(2.0-cmax-cmin); + + delta = cmax - cmin; + + if(r == cmax) + { + *H = (g - b) / delta; + } + else + { + if(g == cmax) *H = 2.0 + (b-r) / delta; + else *H = 4.0 + (r-g) / delta; + } + *H /= 6.0; + if (*H < 0.0) *H += 1; + } +} + +/****************************************************************************** + FUNCTION: HueToRGB + PURPOSE: Convert a hue (color) to RGB + COPYRIGHT:1995-1997 Robert Mashlan + Modified for LabWindows/CVI, 1999 Guillaume Dargaud +******************************************************************************/ +double HueToRGB(const double m1, const double m2, double h ) +{ + if (h<0) h+=1.0; + if (h>1) h-=1.0; + if (6.0*h < 1 ) return (m1+(m2-m1)*h*6.0); + if (2.0*h < 1 ) return m2; + if (3.0*h < 2.0) return (m1+(m2-m1)*((2.0/3.0)-h)*6.0); + return m1; +} + + +/****************************************************************************** + FUNCTION: HLStoRGB + PURPOSE: Convert from HSL to RGB + IN: Hue, Saturation, Luminance from 0 to 1 + RETURN: RGB color (0xBBGGRR) + COPYRIGHT:1995-1997 Robert Mashlan + Modified for LabWindows/CVI, 1999 Guillaume Dargaud +******************************************************************************/ + +COLORREF HLStoRGB(const double H, const double L, const double S ) +{ + double r,g,b; + double m1, m2; + + if(S == 0) + { + r = g = b = L; + } + else + { + if (L <= 0.5) + m2 = L * (1.0 + S); + else + m2 = L + S - L * S; + + m1 = 2.0 * L - m2; + + r = HueToRGB(m1,m2,H+1.0/3.0); + g = HueToRGB(m1,m2,H); + b = HueToRGB(m1,m2,H-1.0/3.0); + } + + return RGB(r*255, g*255, b*255); +} + + + +/****************************************************************************** + FUNCTION: ColorScaleHSL + PURPOSE: Returns the HSL linear interpolated color between 2 colors + (more natural looking than RGB interpolation) + For instance if the luminance is the same in Col1 and Col2, + then the luminance of the result will be the same + If Ratio=0, you get Col1, + If Ratio=1, you get Col2 + IN: Col1: low color in hex 0xBBGGRR format + Col2: high color in hex 0xBBGGRR format + Ratio: 0 for low color, 1 for high color, or in between + EXAMPLE: Col1=0, Col2=0xFF00FF, Ratio=0.5 returns 0x1F5F3F +******************************************************************************/ +COLORREF ColorScaleHSL( const COLORREF Col1, const COLORREF Col2, const double Ratio) +{ + static double H1, H2, S1, S2, L1, L2; + + if (Ratio<=0) return Col1; // Ratio parameter must be between 0 and 1 + else if (Ratio>=1) return Col2; + + RGBtoHLS( Col1, &H1, &L1, &S1); + RGBtoHLS( Col2, &H2, &L2, &S2); + return HLStoRGB( H1+(H2-H1)*Ratio, L1+(L2-L1)*Ratio, S1+(S2-S1)*Ratio ); +} + + +/****************************************************************************** + FUNCTION: ColorScaleRGB + PURPOSE: Returns the RGB linear interpolated color between 2 colors + If Ratio=0, you get Col1, + If Ratio=1, you get Col2 + IN: Col1: low color in hex 0xBBGGRR format + Col2: high color in hex 0xBBGGRR format + Ratio: 0 for low color, 1 for high color, or in between + EXAMPLE: Col1=0, Col2=0xFF00FF, Ratio=0.5 returns 0x800080 +******************************************************************************/ +COLORREF ColorScaleRGB( const COLORREF Col1, + const COLORREF Col2, + const double Ratio) { + int R1=(Col1)&0xFF, G1=(Col1>>8)&0xFF, B1=(Col1>>16)&0xFF; + int R2=(Col2)&0xFF, G2=(Col2>>8)&0xFF, B2=(Col2>>16)&0xFF; + + if (Ratio<=0) return Col1; // Ratio parameter must be between 0 and 1 + else if (Ratio>=1) return Col2; + +/* return RGB( + (R1 + (R2 - R1) * (Ratio + 0.02) + 0.5), // rounding + (G1 + (G2 - G1) * (Ratio - 0.00) + 0.5), + (B1 + (B2 - B1) * (Ratio + 0.05) + 0.5) + );*/ + + /*double r = Ratio; + if(Col2 == 0) + r = 1-Ratio; + else + r = 1+Ratio; + R1 = (int)(double(R1) * r + 0.5); + G1 = (int)(double(G1) * r + 0.5); + B1 = (int)(double(B1) * r + 0.5); + return RGB(R1,G1,B1);*/ + + return RGB( + (R1 + (R2 - R1) * (Ratio + 0.02) + 0.5), // rounding + (G1 + (G2 - G1) * (Ratio - 0.00) + 0.5), + (B1 + (B2 - B1) * (Ratio + 0.05) + 0.5) + ); +} + + + +COLORREF ColorDarker(COLORREF col, double ratio) +{ + static double Hue, Lum, Sat; + + //RGBtoHLS(col, &Hue, &Lum, &Sat); + + //col = HLStoRGB(Hue, fMax(0.0,Lum-ratio), Sat); + + return ColorScaleHSL(col, RGB(0,0,0), ratio); + + //return col; +} + +COLORREF ColorLighter(COLORREF col, double ratio) +{ + static double Hue, Lum, Sat; + + //RGBtoHLS(col, &Hue, &Lum, &Sat); + + //col = HLStoRGB(Hue, fMin(1.0,Lum+ratio), Sat); + + return ColorScaleHSL(col, RGB(255,255,255), ratio); + + //return col; +} + +// +// Experimental!!! +// +#if 0 + +typedef enum { Red, Green, Blue }; + +void RGBtoHLS(COLORREF rgb, double *Hue, double *Lum, double *Sat) +{ + double mn, mx; + int major; + + BYTE red, green, blue; + + red = GetRValue(rgb); + green = GetGValue(rgb); + blue = GetBValue(rgb); + + if(red < green) + { + mn = red; mx = green; major = Green; + } + else + { + mn = green; mx = red; major = Red; + } + + if(blue < mn) + { + mn = blue; + } + else if(blue > mx) + { + mx = blue; major = Blue; + } + + if(mn == mx) + { + *Lum = mn / 255; + *Sat = 0; + *Hue = 0; + } + else + { + *Lum = (mx + mn) / 510; + + if(*Lum <= 0.5) + *Sat = (mx-mn) / (mn+mx); + else + *Sat = (mx-mn) / (510-mn-mx); + + switch(major) + { + case Red: *Hue = (green-blue) * 60.0 / (mx-mn) + 360.0; + break; + + case Green: *Hue = (blue-red) * 60.0 / (mx-mn) + 120.0; + break; + + case Blue: *Hue = (red-green) * 60.0 / (mx-mn) + 240.0; + break; + + } + + if(*Hue > 360.0) + *Hue -= 360.0; + } +} + +static BYTE Value(double m1, double m2, double hue) +{ + + if(hue > 360) hue -= 360; + else if(hue < 0) hue += 360; + + if(hue < 60) + m1 = m1 + (m2 - m1) * hue / 60; + else if(hue < 180) + m1 = m2; + else if(hue < 240) + m1 = m1 + (m2 - m1) * (240 - hue) / 60; + + return (BYTE)(m1 * 255); +} + +COLORREF HLStoRGB(const double Hue, const double Lum, const double Sat) +{ + BYTE red, green, blue; + + if(Sat == 0) + { + red = green = blue = (BYTE)(Lum * 255); + } + else + { + double m1, m2; + + if(Lum <= 0.5) + m2 = Lum + Lum * Sat; + else + m2 = Lum + Sat - Lum * Sat; + + m1 = 2 * Lum - m2; + + red = Value(m1, m2, Hue + 120); + green = Value(m1, m2, Hue); + blue = Value(m1, m2, Hue - 120); + } + + return RGB(red, green, blue); +} + +COLORREF ScaleLumRGB(COLORREF col1, double ratio) +{ + double H1, L1, S1; + + RGBtoHLS(col1, &H1, &L1, &S1); + + L1 += L1 * ratio; + + return HLStoRGB(H1, L1, S1); +} + +COLORREF ColorScaleHSL(const COLORREF Col1, const COLORREF Col2, const double Ratio) +{ + static double H1, H2, S1, S2, L1, L2; + + if(Ratio <= 0) return Col1; // Ratio parameter must be between 0 and 1 + else if(Ratio >= 1) return Col2; + + RGBtoHLS( Col1, &H1, &L1, &S1); + RGBtoHLS( Col2, &H2, &L2, &S2); + + return HLStoRGB( H1 /*+ (H2 - H1 ) * Ratio*/, L1 + (L2 - L1) * Ratio, S1 + (S2 - S1) * Ratio * 2); +} + +COLORREF ColorScaleRGB(const COLORREF Col1, const COLORREF Col2, const double Ratio) +{ + return ColorScaleHSL(Col1, Col2, Ratio); +} +#endif diff --git a/rosapps/games/solitaire/cardlib/cardcolor.h b/rosapps/games/solitaire/cardlib/cardcolor.h new file mode 100644 index 00000000000..d97adce8471 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardcolor.h @@ -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) diff --git a/rosapps/games/solitaire/cardlib/cardcount.cpp b/rosapps/games/solitaire/cardlib/cardcount.cpp new file mode 100644 index 00000000000..e14777afbbb --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardcount.cpp @@ -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]--; +} \ No newline at end of file diff --git a/rosapps/games/solitaire/cardlib/cardcount.h b/rosapps/games/solitaire/cardlib/cardcount.h new file mode 100644 index 00000000000..f97ba153151 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardcount.h @@ -0,0 +1,31 @@ +#ifndef _CARDCOUNT_INCLUDED +#define _CARDCOUNT_INCLUDED + +#include + +#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 diff --git a/rosapps/games/solitaire/cardlib/cardlib.cpp b/rosapps/games/solitaire/cardlib/cardlib.cpp new file mode 100644 index 00000000000..07cd4eec73b --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardlib.cpp @@ -0,0 +1,122 @@ +// +// CardLib - not much of interest in here +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include "cardlib.h" +#include "globals.h" + +void LoadCardBitmaps(void); + +static bool __CARDLIB_ACES_HIGH = false; +extern double __CARDZOOMSPEED; + +// +// Global variables! +// +HDC __hdcCardBitmaps; +HBITMAP __hbmCardBitmaps; + +HDC __hdcPlaceHolder; +HBITMAP __hbmPlaceHolder; +HPALETTE __holdplacepal; + +int __cardwidth; +int __cardheight; + +HPALETTE __hPalette; + + +// +// Cardlib global functions! +// +void CardLib_SetZoomSpeed(int speed) +{ + __CARDZOOMSPEED = (double)speed; +} + +/* + + It's dangerous to use these operators, because of all + the implicit conversions that could take place, which + would have unpredicted side-effects. + + e.g. Card card(Hearts, 4); + if(card == 4) - how does 4 get converted?? + It uses the Card(int uval) constructor, + which results in a 2 of clubs... + not what was expected +*/ +/* +void CardLib_SetAcesHigh(bool fHigh); +bool operator != (const Card &lhs, const Card &rhs); +bool operator == (const Card &lhs, const Card &rhs); +bool operator < (const Card &lhs, const Card &rhs); +bool operator <= (const Card &lhs, const Card &rhs); +bool operator > (const Card &lhs, const Card &rhs); +bool operator >= (const Card &lhs, const Card &rhs); +*/ + +/* +void CardLib_SetAcesHigh(bool fHigh) +{ + __CARDLIB_ACES_HIGH = fHigh; +} + +bool operator == (const Card &lhs, const Card &rhs) +{ + if(__CARDLIB_ACES_HIGH) + return lhs.HiVal() == rhs.HiVal(); + else + return lhs.LoVal() == rhs.LoVal(); +} + +bool operator != (const Card &lhs, const Card &rhs) +{ + if(__CARDLIB_ACES_HIGH) + return lhs.HiVal() != rhs.HiVal(); + else + return lhs.LoVal() != rhs.LoVal(); +} + +bool operator > (const Card &lhs, const Card &rhs) +{ + if(__CARDLIB_ACES_HIGH) + return lhs.HiVal() > rhs.HiVal(); + else + return lhs.LoVal() > rhs.LoVal(); +} + +bool operator >= (const Card &lhs, const Card &rhs) +{ + if(__CARDLIB_ACES_HIGH) + return lhs.HiVal() >= rhs.HiVal(); + else + return lhs.LoVal() >= rhs.LoVal(); +} + +bool operator < (const Card &lhs, const Card &rhs) +{ + if(__CARDLIB_ACES_HIGH) + return lhs.HiVal() < rhs.HiVal(); + else + return lhs.LoVal() < rhs.LoVal(); +} + +bool operator <= (const Card &lhs, const Card &rhs) +{ + if(__CARDLIB_ACES_HIGH) + return lhs.HiVal() <= rhs.HiVal(); + else + return lhs.LoVal() <= rhs.LoVal(); +} +*/ + +void PaintRect(HDC hdc, RECT *rect, COLORREF colour) +{ + COLORREF oldcr = SetBkColor(hdc, colour); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, rect, "", 0, 0); + SetBkColor(hdc, oldcr); +} diff --git a/rosapps/games/solitaire/cardlib/cardlib.h b/rosapps/games/solitaire/cardlib/cardlib.h new file mode 100644 index 00000000000..bad3f0cf121 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardlib.h @@ -0,0 +1,101 @@ +#ifndef CARDLIB_INCLUDED +#define CARDLIB_INCLUDED + +#define CARDLIBPROC __stdcall + +void CardBlt(HDC hdc, int x, int y, int nCardNum); +void CardLib_SetZoomSpeed(int); + +#define CS_EI_NONE 0 +#define CS_EI_SUNK 1 + +#define CS_DEFXOFF 12 //x-offset +#define CS_DEFYOFF 18 //y-offset +#define CS_NO3D 1 //default 3d counts (recommened) +#define CS_DEF3D 10 //(best for decks) + +//#define CS_EI_CIRC 2 +//#define CS_EI_X 3 + +#define CS_DRAG_NONE 0 +#define CS_DRAG_TOP 1 +#define CS_DRAG_ALL 2 +#define CS_DRAG_CALLBACK 3 + +#define CS_DROP_NONE 0 +#define CS_DROP_ALL 1 +#define CS_DROP_CALLBACK 2 + +#define CS_XJUST_NONE 0 +#define CS_XJUST_RIGHT 1 +#define CS_XJUST_CENTER 2 + +#define CS_YJUST_NONE 0 +#define CS_YJUST_BOTTOM 1 +#define CS_YJUST_CENTER 2 + +#define CB_STATIC 0 //static text label +#define CB_PUSHBUTTON 1 //normal button +#define CB_ALIGN_CENTER 0 //centered is default +#define CB_ALIGN_LEFT 2 +#define CB_ALIGN_RIGHT 4 + +#define CS_FACE_UP 0 //all cards face-up +#define CS_FACE_DOWN 1 //all cards face-down +#define CS_FACE_DOWNUP 2 //bottom X cards down, top-most face-up +#define CS_FACE_UPDOWN 3 //bottom X cards up, top-most face-down +#define CS_FACE_ANY 4 //cards can be any orientation + +#define CS_DROPZONE_NODROP -1 + +// +// Define the standard card-back indices +// +#define ecbCROSSHATCH 53 +#define ecbWEAVE1 54 +#define ecbWEAVE2 55 +#define ecbROBOT 56 +#define ecbFLOWERS 57 +#define ecbVINE1 58 +#define ecbVINE2 59 +#define ecbFISH1 60 +#define ecbFISH2 61 +#define ecbSHELLS 62 +#define ecbCASTLE 63 +#define ecbISLAND 64 +#define ecbCARDHAND 65 +#define ecbUNUSED 66 +#define ecbTHE_X 67 +#define ecbTHE_O 68 + + +class CardRegion; +class CardButton; +class CardStack; + +typedef bool (CARDLIBPROC *pCanDragProc) (CardRegion &stackobj, int iNumDragging); +typedef bool (CARDLIBPROC *pCanDropProc) (CardRegion &stackobj, const CardStack &cards); +typedef void (CARDLIBPROC *pClickProc) (CardRegion &stackobj, int iNumCards); +typedef void (CARDLIBPROC *pAddProc) (CardRegion &stackobj, const CardStack &cards); +typedef void (CARDLIBPROC *pRemoveProc) (CardRegion &stackobj, int iNumRemoved); + +typedef void (CARDLIBPROC *pResizeWndProc) (int width, int height); +typedef int (CARDLIBPROC *pDropZoneProc) (int dzid, const CardStack &cards); + +typedef void (CARDLIBPROC *pButtonProc) (CardButton &pButton); + + +#include "card.h" +#include "cardbutton.h" +#include "cardstack.h" +#include "cardregion.h" +#include "cardcount.h" +#include "cardwindow.h" + +#ifdef _DEBUG +typedef bool (CARDLIBPROC *pDebugClickProc) (CardRegion &stackobj); +void CardLib_SetStackClickProc(pDebugClickProc proc); +#endif + + +#endif diff --git a/rosapps/games/solitaire/cardlib/cardregion.cpp b/rosapps/games/solitaire/cardlib/cardregion.cpp new file mode 100644 index 00000000000..1a7e8ce19ce --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardregion.cpp @@ -0,0 +1,658 @@ +// +// CardLib - CardRegion class +// +// Freeware +// Copyright J Brown 2001 +// +#include + +#include "cardlib.h" +#include "cardregion.h" +#include "cardwindow.h" +#include "cardcolor.h" + +HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, int width, int height); + +void PaintRect(HDC hdc, RECT *rect, COLORREF colour); + +CardRegion::CardRegion(CardWindow &parent, int Id, bool visible, int x, int y, int xOffset, int yOffset) +: parentWnd(parent), id(Id), fVisible(visible), xpos(x), ypos(y), xoffset(xOffset), yoffset(yOffset) +{ + width = __cardwidth; + height = __cardheight; + + crBackgnd = RGB(0, 64, 100); + + uFaceDirType = CS_FACE_UP; + nFaceDirOption = 0; + uEmptyImage = CS_EI_SUNK; + + fVisible = visible; + + nThreedCount = 1; + nBackCardIdx = 53; + + Update(); //Update this stack's size+card count + + hdcBackGnd = 0; + hbmBackGnd = 0; + hdcDragCard = 0; + hbmDragCard = 0; + + nDragCardWidth = 0; + nDragCardHeight = 0; + + CanDragCallback = 0; + CanDropCallback = 0; + AddCallback = 0; + RemoveCallback = 0; + ClickCallback = 0; + DblClickCallback = 0; + + uDragRule = CS_DRAG_ALL; + uDropRule = CS_DROP_ALL; + + xjustify = yjustify = xadjust = yadjust = 0; + + nFlashCount = 0; + fFlashVisible = false; + uFlashTimer = -1; + + fMouseDragging = false; + + mxlock = CreateMutex(0, FALSE, 0); +} + +CardRegion::~CardRegion() +{ + CloseHandle(mxlock); +} + +void CardRegion::SetBackColor(COLORREF cr) +{ + crBackgnd = cr; +} + +int CardRegion::CalcApparentCards(int realnum) +{ + return ((realnum + nThreedCount - 1) - (realnum + nThreedCount - 1) % nThreedCount) / nThreedCount; +} + +void CardRegion::CalcApparentCards() +{ + nNumApparentCards = CalcApparentCards(cardstack.NumCards()); +} + + +void CardRegion::UpdateSize(void) +{ + if(cardstack.NumCards() > 0) + { + if(xoffset > 0) + width = (nNumApparentCards - 1) * xoffset + __cardwidth; + else + width = (nNumApparentCards - 1) * -xoffset + __cardwidth; + + if(yoffset > 0) + height = (nNumApparentCards - 1) * yoffset + __cardheight; + else + height = (nNumApparentCards - 1) * -yoffset + __cardheight; + } + else + { + width = __cardwidth; + height = __cardheight; + } +} + +CardRegion *CardWindow::CreateRegion(int id, bool fVisible, int x, int y, int xoffset, int yoffset) +{ + CardRegion *cr; + + if(nNumCardRegions == MAXCARDSTACKS) + return FALSE; + + cr = new CardRegion(*this, id, fVisible, x, y, xoffset, yoffset); + cr->SetBackColor(crBackgnd); + cr->SetBackCardIdx(nBackCardIdx); + + Regions[nNumCardRegions++] = cr; + + return cr; +} + +int CardRegion::GetOverlapRatio(int x, int y, int w, int h) +{ + RECT me, him; + RECT inter; + SetRect(&him, x, y, x+w, y+h); + SetRect(&me, xpos, ypos, xpos+width, ypos+height); + + //see if the specified rectangle overlaps us + if(IntersectRect(&inter, &me, &him)) + { + int wi = inter.right - inter.left; + int hi = inter.bottom - inter.top; + + int overlap = wi * hi; + int total = width * height; + + int percent = (overlap << 16) / total; + return (percent * 100) >> 16; + } + //do not overlap + else + { + return 0; + } +} + +bool CardRegion::SetDragRule(UINT uDragType, pCanDragProc proc) +{ + switch(uDragType) + { + case CS_DRAG_NONE: case CS_DRAG_ALL: case CS_DRAG_TOP: + uDragRule = uDragType; + return true; + + case CS_DRAG_CALLBACK: + uDragRule = uDragType; + CanDragCallback = proc; + return true; + + default: + return false; + } +} + +bool CardRegion::SetDropRule(UINT uDropType, pCanDropProc proc) +{ + switch(uDropType) + { + case CS_DROP_NONE: case CS_DROP_ALL: + uDropRule = uDropType; + return true; + + case CS_DROP_CALLBACK: + uDropRule = uDropType; + CanDropCallback = proc; + return true; + + default: + return false; + } +} + +void CardRegion::SetClickProc(pClickProc proc) +{ + ClickCallback = proc; +} + +void CardRegion::SetDblClickProc(pClickProc proc) +{ + DblClickCallback = proc; +} + +void CardRegion::SetAddCardProc(pAddProc proc) +{ + AddCallback = proc; +} + +void CardRegion::SetRemoveCardProc(pRemoveProc proc) +{ + RemoveCallback = proc; +} + +void CardRegion::Update() +{ + CalcApparentCards(); + UpdateSize(); + UpdateFaceDir(cardstack); +} + + +bool CardRegion::SetThreedCount(int count) +{ + if(count < 1) + { + return false; + } + else + { + nThreedCount = count; + return true; + } +} + +void CardRegion::SetOffsets(int x, int y) +{ + xoffset = x; + yoffset = y; +} + +void CardRegion::SetPos(int x, int y) +{ + xpos = x; + ypos = y; +} + +void CardRegion::Show(bool fShow) +{ + fVisible = fShow; +} + +bool CardRegion::IsVisible() +{ + return fVisible; +} + +void CardRegion::SetPlacement(UINT xJustify, UINT yJustify, int xAdjust, int yAdjust) +{ + xjustify = xJustify; + yjustify = yJustify; + xadjust = xAdjust; + yadjust = yAdjust; +} + +void CardRegion::SetFaceDirection(UINT uDirType, int nOption) +{ + switch(uDirType) + { + case CS_FACE_UP: case CS_FACE_DOWN: case CS_FACE_DOWNUP: + case CS_FACE_UPDOWN: case CS_FACE_ANY: + uFaceDirType = uDirType; + nFaceDirOption = nOption; + + UpdateFaceDir(cardstack); + + break; + } +} + +UINT CardRegion::GetFaceDirection(int *pnOption) +{ + if(pnOption) + *pnOption = nFaceDirOption; + + return uFaceDirType; +} + +void CardRegion::AdjustPosition(int winwidth, int winheight) +{ + Update(); //Update this stack's card count + size + + switch(xjustify) + { + default: case CS_XJUST_NONE: break; + + case CS_XJUST_CENTER: //centered + xpos = (winwidth - (width & ~0x1)) / 2; + xpos += xadjust; + + if(xoffset < 0) xpos += (width - __cardwidth); + + break; + + case CS_XJUST_RIGHT: //right-aligned + xpos = winwidth - __cardwidth;//width - 20; + xpos += xadjust; + break; + } + + switch(yjustify) + { + default: case CS_YJUST_NONE: break; + + case CS_YJUST_CENTER: //centered + ypos = (winheight - height) / 2; + ypos += yadjust; + if(yoffset < 0) ypos += (height - __cardheight); + break; + + case CS_YJUST_BOTTOM: //bottom-aligned + ypos = winheight - __cardheight;//height - 20; + ypos += yadjust; + break; + } + +} + + +void CardRegion::Flash(int count, int milliseconds) +{ + if(count <= 0) return; + + nFlashCount = count; + fFlashVisible = false; + uFlashTimer = SetTimer((HWND)parentWnd, (WPARAM)this, milliseconds, 0); + + parentWnd.Redraw(); +} + +void CardRegion::StopFlash() +{ + if(uFlashTimer != -1) + { + KillTimer((HWND)parentWnd, uFlashTimer); + nFlashCount = 0; + uFlashTimer = -1; + fFlashVisible = true; + } +} + +void CardRegion::DoFlash() +{ + if(uFlashTimer != -1) + { + fFlashVisible = !fFlashVisible; + + if(--nFlashCount == 0) + { + KillTimer((HWND)parentWnd, uFlashTimer); + uFlashTimer = -1; + fFlashVisible = true; + } + + parentWnd.Redraw(); + } +} + +int CardRegion::Id() +{ + return id; +} + +void CardRegion::SetEmptyImage(UINT uImage) +{ + switch(uImage) + { + case CS_EI_NONE: case CS_EI_SUNK: + uEmptyImage = uImage; + break; + + default: + uEmptyImage = CS_EI_NONE; + break; + } + +} + +void CardRegion::SetBackCardIdx(UINT uBackIdx) +{ + if(uBackIdx >= 52 && uBackIdx <= 68) + nBackCardIdx = uBackIdx; +} + +void CardRegion::SetCardStack(const CardStack &cs) +{ + //make a complete copy of the specified stack.. + cardstack = cs; + + // Update the face-direction and stack-size + Update(); +} + +const CardStack & CardRegion::GetCardStack() +{ + //return reference to our internal stack + return cardstack; +} + +// +// Update specified card-stack using THIS stack's +// face direction rules! +// +void CardRegion::UpdateFaceDir(CardStack &cards) +{ + int i, n, num; + + num = cards.NumCards(); + + //Now apply the face direction rules.. + switch(uFaceDirType) + { + case CS_FACE_UP: + + for(i = 0; i < num; i++) + { + cards[i].SetFaceUp(true); + } + + break; + + case CS_FACE_DOWN: + + for(i = 0; i < num; i++) + { + cards[i].SetFaceUp(false); + } + + break; + + case CS_FACE_DOWNUP: + + num = cardstack.NumCards(); + n = min(nFaceDirOption, num); + + //bottom n cards.. + for(i = 0; i < n; i++) + { + cards[num - i - 1].SetFaceUp(false); + } + + for(i = n; i < num; i++) + { + cards[num - i - 1].SetFaceUp(true); + } + + break; + + case CS_FACE_UPDOWN: + + num = cardstack.NumCards(); + n = min(nFaceDirOption, num); + + for(i = 0; i < n; i++) + { + cards[num - i - 1].SetFaceUp(true); + } + + for(i = n; i < num; i++) + { + cards[num - i - 1].SetFaceUp(false); + } + + break; + + case CS_FACE_ANY: //cards can be any orientation + default: + break; + } +} + +bool CardRegion::MoveCard(CardRegion *pDestStack, int nNumCards, bool fAnimate) +{ + HDC hdc; + + int x, y; + + if(pDestStack == 0) return false; //{ forcedfacedir = -1 ;return 0; } + + if(nNumCards < 0 || nNumCards > cardstack.NumCards()) + return false; + + x = xpos + xoffset * (nNumApparentCards - nNumCards); + y = ypos + yoffset * (nNumApparentCards - nNumCards); + + oldx = x; + oldy = y; + + dragstack = cardstack.Pop(nNumCards); + + //Alter the drag-stack so that it's cards are the same way up + //as the destination. Use the destination's drag-rules + //instead of this ones!! + CardStack temp; + temp.Push(pDestStack->GetCardStack()); + temp.Push(dragstack); + + pDestStack->UpdateFaceDir(temp); + + dragstack = temp.Pop(nNumCards); + + if(fAnimate) + { + iNumDragCards = nNumCards; + PrepareDragBitmaps(nNumCards); + } + + Update(); //Update this stack's size+card count + + if(fAnimate) + { + hdc = GetDC((HWND)parentWnd); + + ZoomCard(hdc, x, y, pDestStack); + + ReleaseDC((HWND)parentWnd, hdc); + ReleaseDragBitmaps(); + } + + // Get a copy of the cardstack + CardStack cs = pDestStack->GetCardStack(); + cs.Push(dragstack); + + pDestStack->SetCardStack(cs); + + //cs = pDestStack->GetCardStack(); + //pDestStack->Update(); + //pDestStack->UpdateFaceDir(cs); + + RedrawIfNotDim(pDestStack, false); + + //forcedfacedir = -1; + return true; +} + +// +// Simple wrappers +// +int CardRegion::NumCards() const +{ + if(fMouseDragging) + return cardstack.NumCards() + dragstack.NumCards(); + else + return cardstack.NumCards(); +} + +bool CardRegion::Lock() +{ + DWORD dw = WaitForSingleObject(mxlock, 0); + + if(dw == WAIT_OBJECT_0) + { + //TRACE("LockStack succeeded\n"); + return true; + } + else + { + //TRACE("LockStack failed\n"); + return false; + } + return false; +} + +bool CardRegion::UnLock() +{ + if(ReleaseMutex(mxlock)) + { + //TRACE("Unlocking stack\n"); + return true; + } + else + { + //TRACE("Unlocking stack failed\n"); + return false; + } +} + +bool CardRegion::PlayCard(CardRegion *pDestStack, int value, int num) +{ + //search the stack for the specified card value... + while(num--) + { + for(int i = 0; i < cardstack.NumCards(); i++) + { + if(cardstack[i].HiVal() == value) + { + //swap the card with one at top pos... + Card card = cardstack.RemoveCard(i); + cardstack.Push(card); + + Redraw(); + + MoveCard(pDestStack, 1, true); + break; + } + } + } + + return true; +} + +// +// Redraw the current stack if it has a different +// layout than the comparison stack. +// +void CardRegion::RedrawIfNotDim(CardRegion *pCompare, bool fFullRedraw) +{ + // + // + // + if( pCompare->xoffset != xoffset || + pCompare->yoffset != yoffset || + pCompare->nThreedCount != nThreedCount || + pCompare->uFaceDirType != uFaceDirType || + pCompare->uFaceDirType != CS_FACE_ANY + ) + { + if(fFullRedraw) + parentWnd.Redraw(); + else + pCompare->Redraw(); + } + +} + +// +// SimulateDrag mimicks the complete drag+drop process. +// It basically just a MoveCard(..), but it calls the +// event callbacks as well. +// +bool CardRegion::SimulateDrag(CardRegion *pDestStack, int iNumDragCards, bool fAnimate) +{ + if(pDestStack == 0) + return false; + + if(CanDragCards(iNumDragCards) != false) + { + //make a list of the cards that would be in the drag list + CardStack tempstack = cardstack.Top(iNumDragCards); + + if(pDestStack->CanDropCards(tempstack)) + { + MoveCard(pDestStack, iNumDragCards, fAnimate); + + if(RemoveCallback) + RemoveCallback(*this, iNumDragCards); + + if(pDestStack->AddCallback) + pDestStack->AddCallback(*pDestStack, pDestStack->cardstack); + + RedrawIfNotDim(pDestStack, true); + } + + } + + return true; +} \ No newline at end of file diff --git a/rosapps/games/solitaire/cardlib/cardregion.h b/rosapps/games/solitaire/cardlib/cardregion.h new file mode 100644 index 00000000000..d2806a9c9b5 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardregion.h @@ -0,0 +1,216 @@ +#ifndef CARDREGION_INCLUDED +#define CARDREGION_INCLUDED + +#include "globals.h" +#include "cardstack.h" +#include "cardlib.h" + +class CardWindow; + +// +// This class defines a physical card-stack, +// which draws the cards, supports +// + +class CardRegion +{ + friend class CardWindow; + friend class CardStack; + + // + // Constructor is PRIVATE - only + // a CardWindow can create cardstacks! + // + CardRegion(CardWindow &parent, int id, bool fVisible, + int x, int y, int xOffset, int yOffset); + + ~CardRegion(); + +public: + + void SetBackColor(COLORREF cr); + + void SetCardStack(const CardStack &cs); + const CardStack & GetCardStack(); + + // + // Event-callback support + // + bool SetDragRule(UINT uDragType, pCanDragProc proc = 0); + bool SetDropRule(UINT uDropType, pCanDropProc proc = 0); + + void SetClickProc (pClickProc proc); + void SetDblClickProc (pClickProc proc); + + void SetAddCardProc (pAddProc proc); + void SetRemoveCardProc (pRemoveProc proc); + + // + // Physical attribute support + // + bool SetThreedCount (int count); + void SetOffsets (int x, int y); + void SetPos (int x, int y); + void Show (bool fShow); + bool IsVisible (); + + void SetEmptyImage (UINT uImage); + void SetBackCardIdx (UINT uBackIdx); + void SetPlacement (UINT xJustify, UINT yJustify, int xAdjust, int yAdjust); + + void Update(); + void Redraw(); + + void SetFaceDirection(UINT uDirType, int nOption); + UINT GetFaceDirection(int *pnOption); + + void Flash(int count, int timeout); + void StopFlash(); + + int Id(); + + CardWindow &GetCardWindow() { return parentWnd; } + + bool PlayCard(CardRegion *pDestStack, int value, int num); + bool MoveCard(CardRegion *pDestStack, int nNumCards, bool fAnimate); + bool SimulateDrag(CardRegion *pDestStack, int nNumCards, bool fAnimate); + + bool Lock(); + bool UnLock(); + + // + // Common wrappers for the CardStack object + // + int NumCards() const; + void NewDeck() { cardstack.NewDeck(); } + void Shuffle() { cardstack.Shuffle(); } + void Clear() { cardstack.Clear(); } + + void Reverse() { cardstack.Reverse(); } + + void Push(const Card card) { cardstack.Push(card); } + void Push(const CardStack &cs) { cardstack.Push(cs); } + + Card Pop() { return cardstack.Pop(); } + CardStack Pop(int items) { return cardstack.Pop(items); } + + Card Top() { return cardstack.Top(); } + CardStack Top(int items) { return cardstack.Top(items); } + + +private: + + void DoFlash(); + void RedrawIfNotDim(CardRegion *compare, bool fFullRedraw); + + void UpdateFaceDir(CardStack &cards); + void Clip(HDC hdc); + void Render(HDC hdc); + int GetOverlapRatio(int x, int y, int width, int height); + + void MoveDragCardTo(HDC hdc, int x, int y); + void ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *dest); + + void RenderBottomMost(HDC hdc, int minustopmost = 0); + void PrepareDragBitmaps(int numtodrag); + void PrepareDragBitmapsThreed(int numtodrag); + void ReleaseDragBitmaps(void); + + bool CanDragCards(int iNumCards); + bool CanDropCards(CardStack &cards); + + void CalcApparentCards(); + int CalcApparentCards(int realnum); + + void UpdateSize(); + void AdjustPosition(int winwidth, int winheight); + + bool IsPointInStack(int x, int y); + + int GetNumDragCards(int x, int y); + bool OnLButtonDown(int x, int y); + bool OnLButtonDblClk(int x, int y); + bool OnMouseMove(int x, int y); + bool OnLButtonUp(int x, int y); + + + // + // Private data members + // + + int id; + + CardWindow &parentWnd; + + CardStack cardstack; //cards in this stack + CardStack dragstack; //cards which we might be dragging + + bool fMouseDragging; + + int xoffset; //direction that cards take + int yoffset; + + int xpos; //coordinates of stack + int ypos; + + int width; //stack-size of all cards + int height; + + // + // justify / placement vars + int xjustify; + int yjustify; + int xadjust; + int yadjust; + + // + // Used for mouse-dragging / moving cards + // + int iNumDragCards; + int mousexoffset; + int mouseyoffset; + int oldx; + int oldy; + + int nDragCardWidth; + int nDragCardHeight; + + HDC hdcBackGnd; + HBITMAP hbmBackGnd; + HDC hdcDragCard; + HBITMAP hbmDragCard; + + int nNumApparentCards; + int nThreedCount; + bool fVisible; + + int nFlashCount; + bool fFlashVisible; + UINT uFlashTimer; + + COLORREF crBackgnd; + + UINT uEmptyImage; + UINT uFaceDirType; + int nFaceDirOption; + int nBackCardIdx; + + UINT uDragRule; + UINT uDropRule; + + // + // Stack callback support + // + pCanDragProc CanDragCallback; + pCanDropProc CanDropCallback; + pClickProc ClickCallback; + pClickProc DblClickCallback; + pAddProc AddCallback; + pRemoveProc RemoveCallback; + + //locking mechanism to prevent user dragging etc + HANDLE mxlock; +}; + +#endif + diff --git a/rosapps/games/solitaire/cardlib/cardrgndraw.cpp b/rosapps/games/solitaire/cardlib/cardrgndraw.cpp new file mode 100644 index 00000000000..32d8bbf7cfa --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardrgndraw.cpp @@ -0,0 +1,613 @@ +// +// CardLib - CardRegion drawing support +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include "cardlib.h" +#include "cardregion.h" +#include "cardcolor.h" + +HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette); +void PaintRect(HDC hdc, RECT *rect, COLORREF colour); +void CardBlt(HDC hdc, int x, int y, int nCardNum); +void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height); + +// +// Draw specified card at position x, y +// xoff - source offset from left of card +// yoff - source offset from top of card +// width - width to draw +// height - height to draw +// +void CardBlt(HDC hdc, int x, int y, int nCardNum)//, int xoff, int yoff, int width, int height) +{ + int sx = nCardNum * __cardwidth; + int sy = 0; + int width = __cardwidth; + int height = __cardheight; + + //draw main center band + BitBlt(hdc, x+2, y, width - 4, height, __hdcCardBitmaps, sx+2, sy+0, SRCCOPY); + + //draw the two bits to the left + BitBlt(hdc, x, y+2, 1, height - 4, __hdcCardBitmaps, sx+0, sy+2, SRCCOPY); + BitBlt(hdc, x+1, y+1, 1, height - 2, __hdcCardBitmaps, sx+1, sy+1, SRCCOPY); + + //draw the two bits to the right + BitBlt(hdc, x+width-2, y+1, 1, height - 2, __hdcCardBitmaps, sx+width-2, sy+1, SRCCOPY); + BitBlt(hdc, x+width-1, y+2, 1, height - 4, __hdcCardBitmaps, sx+width-1, sy+2, SRCCOPY); +} + +// +// Draw a shape this this: +// +// ++++++++++++ +// ++++++++++++++ +// ++ ++ +// +void DrawHorzCardStrip(HDC hdc, int x, int y, int nCardNum, int height, BOOL fDrawTips) +{ + int sx = nCardNum * __cardwidth; + int sy = 0; + int one = 1; + int two = 2; + BOOL tips = fDrawTips ? FALSE : TRUE; + + if(height == 0) return; + + if(height < 0) + { + sy = sy + __cardheight; + y -= height; + one = -one; + two = -two; + } + + // draw the main vertical band + // + BitBlt(hdc, x + 2, y, __cardwidth - 4, height, __hdcCardBitmaps, sx+2, sy, SRCCOPY); + + //if(height <= 1) return; + + // draw the "lips" at the left and right + BitBlt(hdc, x+1, y+one, 1, height-one*tips, __hdcCardBitmaps, sx+1, sy+one, SRCCOPY); + BitBlt(hdc, x+__cardwidth-2, y+one, 1, height-one*tips, __hdcCardBitmaps, sx+__cardwidth-2, sy+one, SRCCOPY); + + //if(height <= 2) return; + + // draw the outer-most lips + BitBlt(hdc, x, y+two, 1, height-two*tips, __hdcCardBitmaps, sx, sy+two, SRCCOPY); + BitBlt(hdc, x+__cardwidth-1, y+two, 1, height-two*tips, __hdcCardBitmaps, sx+__cardwidth-1, sy+two, SRCCOPY); +} + +// +// Draw a shape like this: +// +// +++ +// +++ +// +++ +// +++ +// +++ +// +++ +// +++ +// +++ +// +++ +// +++ +// +// +void DrawVertCardStrip(HDC hdc, int x, int y, int nCardNum, int width, BOOL fDrawTips) +{ + int sx = nCardNum * __cardwidth; + int sy = 0; + int one = 1; + int two = 2; + BOOL tips = fDrawTips ? FALSE : TRUE; + + if(width == 0) return; + + + if(width < 0) + { + sx = sx + __cardwidth; + x -= width; + one = -1; + two = -2; + } + + // draw the main vertical band + // + BitBlt(hdc, x, y + 2, width, __cardheight - 4, __hdcCardBitmaps, sx, sy+2, SRCCOPY); + + //if(width <= 1) return; + + // draw the "lips" at the top and bottom + BitBlt(hdc, x+one, y+1, width-one*tips, 1, __hdcCardBitmaps, sx+one, sy + 1, SRCCOPY); + BitBlt(hdc, x+one, y+__cardheight-2, width-one*tips, 1, __hdcCardBitmaps, sx+one, sy + __cardheight-2, SRCCOPY); + + //if(width <= 2) return; + + // draw the outer-most lips + BitBlt(hdc, x+two, y, width-two*tips, 1, __hdcCardBitmaps, sx+two, sy, SRCCOPY); + BitBlt(hdc, x+two, y+__cardheight-1, width-two*tips, 1, __hdcCardBitmaps, sx+two, sy + __cardheight-1, SRCCOPY); +} + +// +// xdir - <0 or >0 +// ydir - <0 or >0 +// +void DrawCardCorner(HDC hdc, int x, int y, int cardval, int xdir, int ydir) +{ + int sx = cardval * __cardwidth; + int sy = 0; + + HDC hdcSource = __hdcCardBitmaps; + + if(xdir < 0) + { + x += __cardwidth + xdir - 1; + sx += __cardwidth + xdir - 1; + } + else + { + x += xdir; + sx += xdir; + } + + if(ydir < 0) + { + y += __cardheight + ydir - 1; + sy += __cardheight + ydir - 1; + } + else + { + y += ydir; + sy += ydir; + } + + //convert x,y directions to -1, +1 + xdir = xdir < 0 ? -1 : 1; + ydir = ydir < 0 ? -1 : 1; + + SetPixel(hdc, x+xdir, y , GetPixel(hdcSource, sx+xdir, sy)); + SetPixel(hdc, x, y, GetPixel(hdcSource, sx, sy)); + SetPixel(hdc, x, y+ydir, GetPixel(hdcSource, sx, sy+ydir)); + +} + +// +// Draw a card (i.e. miss out the corners) +// +void DrawCard(HDC hdc, int x, int y, HDC hdcDragCard, int width, int height) +{ + //draw main center band + BitBlt(hdc, x+2, y, width - 4, height, hdcDragCard, 2, 0, SRCCOPY); + + //draw the two bits to the left + BitBlt(hdc, x, y+2, 1, height - 4, hdcDragCard, 0, 2, SRCCOPY); + BitBlt(hdc, x+1, y+1, 1, height - 2, hdcDragCard, 1, 1, SRCCOPY); + + //draw the two bits to the right + BitBlt(hdc, x+width-2, y+1, 1, height - 2, hdcDragCard, width-2, 1, SRCCOPY); + BitBlt(hdc, x+width-1, y+2, 1, height - 4, hdcDragCard, width-1, 2, SRCCOPY); +} + +// +// Clip a card SHAPE - basically any rectangle +// with rounded corners +// +int ClipCard(HDC hdc, int x, int y, int width, int height) +{ + ExcludeClipRect(hdc, x+2, y, x+2+width-4, y+ height); + ExcludeClipRect(hdc, x, y+2, x+1, y+2+height-4); + ExcludeClipRect(hdc, x+1, y+1, x+2, y+1+height-2); + ExcludeClipRect(hdc, x+width-2, y+1, x+width-2+1, y+1+height-2); + ExcludeClipRect(hdc, x+width-1, y+2, x+width-1+1, y+2+height-4); + return 0; +} + +void CardRegion::Clip(HDC hdc) +{ + int numtoclip; + + if(fVisible == false) + return; + + Update(); //Update this stack's size+card count + numtoclip = nNumApparentCards; + + //if we are making this stack flash on/off, then only + //clip the stack for drawing if the flash is in its ON state + if(nFlashCount != 0) + { + if(fFlashVisible == FALSE) + numtoclip = 0; + } + + //if offset along a diagonal + if(xoffset != 0 && yoffset != 0 && cardstack.NumCards() != 0) + { + for(int j = 0; j < numtoclip; j ++) + { + ClipCard(hdc, xpos + xoffset * j, ypos + yoffset * j, __cardwidth, __cardheight); + } + } + //otherwise if just offset along a horizontal/vertical axis + else + { + if(yoffset < 0 && numtoclip > 0) + { + ClipCard(hdc, xpos, ypos-((numtoclip-1)*-yoffset), width, height); + } + else if(xoffset < 0 && numtoclip > 0) + { + ClipCard(hdc, xpos-((numtoclip-1)*-xoffset), ypos, width, height); + } + else + { + ClipCard(hdc, xpos, ypos, width, height); + } + } + +} + +void CardRegion::Render(HDC hdc) +{ + int cardnum = 0; + int numtodraw; + BOOL fDrawTips; + + Update(); //Update this stack's card count + size + + numtodraw = nNumApparentCards; + + if(nFlashCount != 0) + { + if(fFlashVisible == false) + numtodraw = 0; + } + + if(fVisible == 0) return; + + cardnum = cardstack.NumCards() - numtodraw; + int counter; + + for(counter = 0; counter < numtodraw; counter++) + { + int cardval; + + int x = xoffset * counter + xpos; + int y = yoffset * counter + ypos; + + //if about to draw last card, then actually draw the top card + if(counter == numtodraw - 1) cardnum = cardstack.NumCards() - 1; + + Card card = cardstack.cardlist[cardnum]; + cardval = card.Idx(); + + if(card.FaceDown()) + cardval = nBackCardIdx; //card-back + + //only draw the visible part of the card + if(counter < numtodraw - 1) + { + if(yoffset != 0 && xoffset != 0) + fDrawTips = FALSE; + else + fDrawTips = TRUE; + + if(yoffset != 0 && abs(xoffset) == 1 || xoffset != 0 && abs(yoffset) == 1) + fDrawTips = TRUE; + + //draw horizontal strips + if(yoffset > 0) + { + DrawHorzCardStrip(hdc, x, y, cardval, yoffset, fDrawTips); + } + else if(yoffset < 0) + { + DrawHorzCardStrip(hdc, x, y+__cardheight+yoffset, cardval, yoffset, fDrawTips); + } + + //draw some vertical bars + if(xoffset > 0) + { + DrawVertCardStrip(hdc, x, y, cardval, xoffset, fDrawTips); + } + else if(xoffset < 0) + { + DrawVertCardStrip(hdc, x+__cardwidth+xoffset, y, cardval, xoffset, fDrawTips); + } + + if(yoffset != 0 && xoffset != 0)//fDrawTips == FALSE) + { + //if we didn't draw any tips, then this is a 2-dim stack + //(i.e, it goes at a diagonal). + //in this case, we need to fill in the small triangle in + //each corner! + DrawCardCorner(hdc, x, y, cardval, xoffset, yoffset); + } + } + //if the top card, draw the whole thing + else + { + CardBlt(hdc, x, y, cardval); + } + + cardnum ++; + + } //end of index + + if(counter == 0) //if the cardstack is empty, then draw it that way + { + int x = xpos; + int y = ypos; + + switch(uEmptyImage) + { + default: case CS_EI_NONE: + //this wipes the RECT variable, so watch out! + //SetRect(&rect, x, y, x+__cardwidth, y+__cardheight); + //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd)); + parentWnd.PaintCardRgn(hdc, x, y, __cardwidth, __cardheight, x, y); + break; + + case CS_EI_SUNK: //case CS_EI_CIRC: case CS_EI_X: + DrawCard(hdc, x, y, __hdcPlaceHolder, __cardwidth, __cardheight); + break; + } + + } + + return; +} + +int calc_offset(int offset, int numcards, int numtodrag, int realvisible) +{ + if(offset >= 0) + return -offset * numcards; + else + return -offset * (numtodrag) + + -offset * (realvisible - 1); +} + +void CardRegion::PrepareDragBitmaps(int numtodrag) +{ + RECT rect; + HDC hdc; + int icard; + int numcards = cardstack.NumCards(); + int xoff, yoff; + + if(nThreedCount > 1) + { + PrepareDragBitmapsThreed(numtodrag); + return; + } + + //work out how big the bitmaps need to be + nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth; + nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight; + + //Create bitmap for the back-buffer + hdc = GetDC(NULL); + hdcBackGnd = CreateCompatibleDC(hdc); + hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); + SelectObject(hdcBackGnd, hbmBackGnd); + + //Create bitmap for the drag-image + hdcDragCard = CreateCompatibleDC(hdc); + hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); + SelectObject(hdcDragCard, hbmDragCard); + ReleaseDC(NULL, hdc); + + UseNicePalette(hdcBackGnd, __hPalette); + UseNicePalette(hdcDragCard, __hPalette); + + int realvisible = numcards / nThreedCount; + + //if(numcards > 0 && realvisible == 0) realvisible = 1; + int iwhichcard = numcards - 1; + if(nThreedCount == 1) iwhichcard = 0; + + //grab the first bit of background so we can prep the back buffer; do this by + //rendering the card stack (minus the card we are dragging) to the temporary + //background buffer, so it appears if we have lifted the card from the stack + //PaintRect(hdcBackGnd, &rect, crBackgnd); + SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight); + + xoff = calc_offset(xoffset, numcards, numtodrag, realvisible); + yoff = calc_offset(yoffset, numcards, numtodrag, realvisible); + + parentWnd.PaintCardRgn(hdcBackGnd, 0, 0, nDragCardWidth, nDragCardHeight, xpos - xoff, ypos - yoff); + + // + // Render the cardstack into the back-buffer. The stack + // has already had the dragcards removed, so just draw + // what is left + // + for(icard = 0; icard < realvisible; icard++) + { + Card card = cardstack.cardlist[iwhichcard]; + int nCardVal; + + nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; + + xoff = xoffset * icard + calc_offset(xoffset, numcards, numtodrag, realvisible);//- xoffset * ((numcards+numtodrag) / nThreedCount - numtodrag); + yoff = yoffset * icard + calc_offset(yoffset, numcards, numtodrag, realvisible);//- yoffset * ((numcards+numtodrag) / nThreedCount - numtodrag); + + CardBlt(hdcBackGnd, xoff, yoff, nCardVal); + iwhichcard++; + } + + // + // If there are no cards under this one, just draw the place holder + // + if(numcards == 0) + { + int xoff = 0, yoff = 0; + + if(xoffset < 0) xoff = nDragCardWidth - __cardwidth; + if(yoffset < 0) yoff = nDragCardHeight - __cardheight; + + switch(uEmptyImage) + { + case CS_EI_NONE: + //No need to draw anything: We already cleared the + //back-buffer before the main loop.. + + //SetRect(&rc, xoff, yoff, xoff+ __cardwidth, yoff + __cardheight); + //PaintRect(hdcBackGnd, &rc, MAKE_PALETTERGB(crBackgnd)); + //parentWnd.PaintCardRgn(hdcBackGnd, xoff, yoff, __cardwidth, __cardheight, xpos, ypos);// + xoff, ypos + yoff); + break; + + case CS_EI_SUNK: + DrawCard(hdcBackGnd, xoff, yoff, __hdcPlaceHolder, __cardwidth, __cardheight); + break; + } + } + + // + // now render the drag-cards into the dragcard image + // + PaintRect(hdcDragCard, &rect, crBackgnd); + + for(icard = 0; icard < numtodrag; icard++) + { + int nCardVal; + + if(xoffset >= 0) xoff = xoffset * icard; + else xoff = -xoffset * (numtodrag - icard - 1); + + if(yoffset >= 0) yoff = yoffset * icard; + else yoff = -yoffset * (numtodrag - icard - 1); + + Card card = dragstack.cardlist[icard]; + + nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; + + CardBlt(hdcDragCard, xoff, yoff, nCardVal); + } +} + +void CardRegion::PrepareDragBitmapsThreed(int numtodrag) +{ + RECT rect; + HDC hdc; + int icard; + int numunder = 0; + int iwhichcard; + + int numcards = cardstack.NumCards(); + + //work out how big the bitmaps need to be + nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth; + nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight; + + //Create bitmap for the back-buffer + hdc = GetDC(NULL); + hdcBackGnd = CreateCompatibleDC(hdc); + hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); + SelectObject(hdcBackGnd, hbmBackGnd); + + //create bitmap for the drag-image + hdcDragCard = CreateCompatibleDC(hdc); + hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); + SelectObject(hdcDragCard, hbmDragCard); + ReleaseDC(NULL, hdc); + + UseNicePalette(hdcBackGnd, __hPalette); + UseNicePalette(hdcDragCard, __hPalette); + + //grab the first bit of background so we can prep the back buffer; do this by + //rendering the card stack (minus the card we are dragging) to the temporary + //background buffer, so it appears if we have lifted the card from the stack + //--SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight); + //--PaintRect(hdcBackGnd, &rect, crBackgnd); + + int threedadjust = numcards % nThreedCount == 0; + + numunder = CalcApparentCards(numcards); + iwhichcard = (numcards+numtodrag) - numunder - 1; + if(nThreedCount == 1) iwhichcard = 0; + + int xoff = calc_offset(xoffset, numunder, numtodrag, numunder); + int yoff = calc_offset(yoffset, numunder, numtodrag, numunder); + + parentWnd.PaintCardRgn(hdcBackGnd, 0,0, nDragCardWidth,nDragCardHeight, xpos - xoff,ypos - yoff); + + // + // Render the cardstack into the back-buffer. The stack + // has already had the dragcards removed, so just draw + // what is left + // + for(icard = 0; icard < numunder; icard++) + { + Card card = cardstack.cardlist[iwhichcard]; + int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; + + CardBlt(hdcBackGnd, + xoffset * icard - xoffset*(numunder-numtodrag+threedadjust), + yoffset * icard - yoffset*(numunder-numtodrag+threedadjust), + nCardVal); + + iwhichcard++; + } + + // + // If there are no cards under this one, just draw the place holder + // + if(numcards == 0) + { + switch(uEmptyImage) + { + case CS_EI_NONE: + //no need! we've already cleared the whole + //back-buffer before the main loop! + //SetRect(&rect, 0, 0, __cardwidth, __cardheight); + //PaintRect(hdcBackGnd, &rect, MAKE_PALETTERGB(crBackgnd)); + break; + + case CS_EI_SUNK: + DrawCard(hdcBackGnd, 0, 0, __hdcPlaceHolder, __cardwidth, __cardheight); + break; + + } + } + + // + // now render the drag-cards into the dragcard image + // + PaintRect(hdcDragCard, &rect, crBackgnd); + + for(icard = 0; icard < numtodrag; icard++) + { + Card card = dragstack.cardlist[icard]; + int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; + + CardBlt(hdcDragCard, xoffset * icard, yoffset * icard, nCardVal); + } +} + +void CardRegion::ReleaseDragBitmaps(void) +{ + //SelectObject(hdcBackGnd, hOld1); + DeleteObject(hbmBackGnd); + DeleteDC(hdcBackGnd); + + //SelectObject(hdcDragCard, hOld2); + DeleteObject(hbmDragCard); + DeleteDC(hdcDragCard); +} + + +void CardRegion::Redraw() +{ + HDC hdc = GetDC((HWND)parentWnd); + + Update(); + Render(hdc); + + ReleaseDC((HWND)parentWnd, hdc); +} diff --git a/rosapps/games/solitaire/cardlib/cardrgnmouse.cpp b/rosapps/games/solitaire/cardlib/cardrgnmouse.cpp new file mode 100644 index 00000000000..a3bf6e771ea --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardrgnmouse.cpp @@ -0,0 +1,618 @@ +// +// CardLib - CardRegion mouse-related stuff +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include + +#include "cardlib.h" +#include "cardwindow.h" +#include "cardregion.h" + +double __CARDZOOMSPEED = 32; + +int ClipCard(HDC hdc, int x, int y, int width, int height); +void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height); + +#ifdef _DEBUG + +static pDebugClickProc DebugStackClickProc = 0; + +void CardLib_SetStackClickProc(pDebugClickProc proc) +{ + DebugStackClickProc = proc; +} + +#endif + +CardRegion *CardWindow::GetBestStack(int x, int y, int w, int h) +{ + int maxoverlap = 0; + int maxoverlapidx = -1; + + //find the stack which is most covered by the dropped + //cards. Only include those which allow drops. + // + for(int i = 0; i < nNumCardRegions; i++) + { + int percent = Regions[i]->GetOverlapRatio(x, y, w, h); + + //if this stack has the biggest coverage yet + if(percent > maxoverlap && Regions[i]->IsVisible()) + { + maxoverlap = percent; + maxoverlapidx = i; + } + } + + //if we found a stack to drop onto + if(maxoverlapidx != -1) + { + return Regions[maxoverlapidx]; + } + else + { + return 0; + } +} + +bool CardRegion::IsPointInStack(int x, int y) +{ + int axpos = xoffset < 0 ? xpos + (nNumApparentCards-1)*xoffset : xpos; + int aypos = yoffset < 0 ? ypos + (nNumApparentCards-1)*yoffset : ypos; + + if(x >= axpos && x < axpos + width && y >= aypos && y < aypos + height && fVisible) + return true; + else + return false; +} + +int CardRegion::GetNumDragCards(int x, int y) +{ + int cardindex = 0; //index from stack start + int maxidx; + + //make x,y relative to the stack's upper left corner + x -= xpos + (xoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * xoffset : 0); + y -= ypos + (yoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * yoffset : 0); + + //if stack is empty, cannot drag any cards from it + if(cardstack.NumCards() <= 0) + return 0; + + //see which card in the stack has been clicked on + //top-bottom ordering + if(yoffset > 0) + { + if(y < height - __cardheight) + cardindex = y / yoffset; + else + cardindex = cardstack.NumCards() - 1; + } + else if(yoffset < 0) + { + if(y < __cardheight) + cardindex = cardstack.NumCards() - 1; + else + cardindex = cardstack.NumCards() - ((y - __cardheight) / -yoffset) - 2; + } + else //yoffset == 0 + { + cardindex = cardstack.NumCards() - 1; + } + + maxidx = cardindex; + + //if left-right + if(xoffset > 0) + { + if(x < width - __cardwidth) + cardindex = x / xoffset; + else + cardindex = cardstack.NumCards() - 1; + } + else if(xoffset < 0) + { + if(x < __cardwidth) + cardindex = cardstack.NumCards() - 1; + else + cardindex = cardstack.NumCards() - ((x - __cardwidth) / -xoffset) - 2; + } + else + { + cardindex = cardstack.NumCards() - 1; + } + + if(cardindex > maxidx) cardindex = maxidx; + + if(cardindex > cardstack.NumCards()) + cardindex = 1; + + //if are trying to drag too many cards at once + return cardstack.NumCards() - cardindex; +} + +bool CardRegion::CanDragCards(int iNumCards) +{ + if(iNumCards <= 0) return false; + if(nThreedCount > 1 && iNumCards > 1) return false; + + if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0) + { +// TRACE("Failed to gain access to card stack\n"); + return false; + } + + ReleaseMutex(mxlock); + + switch(uDragRule) + { + case CS_DRAG_ALL: + return true; + + case CS_DRAG_TOP: + + if(iNumCards == 1) + return true; + else + return false; + + case CS_DRAG_NONE: + return false; + + case CS_DRAG_CALLBACK: + + if(CanDragCallback) + { + return CanDragCallback(*this, iNumCards); + } + else + { + return false; + } + + default: + return false; + } +} + +bool CardRegion::CanDropCards(CardStack &cards) +{ + if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0) + { + return false; + } + + ReleaseMutex(mxlock); + + switch(uDropRule) + { + case CS_DROP_ALL: + return true; + + case CS_DROP_NONE: + return false; + + case CS_DROP_CALLBACK: + + if(CanDropCallback) + { + return CanDropCallback(*this, cards); + } + else + { + return false; + } + + default: + return false; + } +} + +bool CardRegion::OnLButtonDblClk(int x, int y) +{ + iNumDragCards = GetNumDragCards(x, y); + + if(DblClickCallback) + DblClickCallback(*this, iNumDragCards); + + return true; +} + +bool CardRegion::OnLButtonDown(int x, int y) +{ + iNumDragCards = GetNumDragCards(x, y); + +#ifdef _DEBUG + if(DebugStackClickProc) + { + if(!DebugStackClickProc(*this)) + return false; + } +#endif + + if(ClickCallback) + ClickCallback(*this, iNumDragCards); + + if(CanDragCards(iNumDragCards) != false) + { + + //offset of the mouse cursor relative to the top-left corner + //of the cards that are being dragged + mousexoffset = x - xpos - xoffset * (nNumApparentCards - iNumDragCards); + mouseyoffset = y - ypos - yoffset * (nNumApparentCards - iNumDragCards); + + if(xoffset < 0) + mousexoffset += -xoffset * (iNumDragCards - 1); + + if(yoffset < 0) + mouseyoffset += -yoffset * (iNumDragCards - 1); + + //remove the cards from the source stack + dragstack = cardstack.Pop(iNumDragCards); + + //prepare the back buffer, and the drag image + PrepareDragBitmaps(iNumDragCards); + + oldx = x - mousexoffset; + oldy = y - mouseyoffset; + + Update(); //Update this stack's card count + size + + SetCapture((HWND)parentWnd); + + //set AFTER settings the dragstack... + fMouseDragging = true; + + return true; + } + + return false; +} + +bool CardRegion::OnLButtonUp(int x, int y) +{ + CardRegion *pDestStack = 0; + HDC hdc; + int dropstackid = CS_DROPZONE_NODROP; + + RECT dragrect; + DropZone *dropzone; + + fMouseDragging = false; + + //first of all, see if any drop zones have been registered + SetRect(&dragrect, x-mousexoffset, y-mouseyoffset, x-mousexoffset+nDragCardWidth, y-mouseyoffset+nDragCardHeight); + + dropzone = parentWnd.GetDropZoneFromRect(&dragrect); + + if(dropzone) + { + dropstackid = dropzone->DropCards(dragstack); + + if(dropstackid != CS_DROPZONE_NODROP) + pDestStack = parentWnd.CardRegionFromId(dropstackid); + else + pDestStack = 0; + } + else + { + pDestStack = parentWnd.GetBestStack(x - mousexoffset, y - mouseyoffset, nDragCardWidth, nDragCardHeight); + } + + // If have found a stack to drop onto + // + if(pDestStack && pDestStack->CanDropCards(dragstack)) + { + hdc = GetDC((HWND)parentWnd); + // UseNicePalette(hdc); + ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, pDestStack); + ReleaseDC((HWND)parentWnd, hdc); + + // + //add the cards to the destination stack + // + CardStack temp = pDestStack->GetCardStack(); + temp.Push(dragstack); + + pDestStack->SetCardStack(temp); +// pDestStack->Update(); //Update this stack's card count + size +// pDestStack->UpdateFaceDir(temp); + + // Call the remove callback on THIS stack, if one is specified + // + if(RemoveCallback) + RemoveCallback(*this, iNumDragCards); + + // Call the add callback, if one is specified + // + if(pDestStack->AddCallback) + pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);//index, deststack->numcards); + + RedrawIfNotDim(pDestStack, true); + } + + // + // Otherwise, let the cards snap back onto this stack + // + else + { + + hdc = GetDC((HWND)parentWnd); + ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this); + cardstack += dragstack; + ReleaseDC((HWND)parentWnd, hdc); + + Update(); //Update this stack's card count + size + } + + ReleaseDragBitmaps(); + ReleaseCapture(); + + return true; +} + +bool CardRegion::OnMouseMove(int x, int y) +{ + HDC hdc; + + hdc = GetDC((HWND)parentWnd); + + x -= mousexoffset; + y -= mouseyoffset; + + MoveDragCardTo(hdc, x, y); + + //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY); + //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY); + + ReleaseDC((HWND)parentWnd, hdc); + + oldx = x; + oldy = y; + + return true; +} + +// +// There is a bug in BitBlt when the source x,y +// become < 0. So this wrapper function simply adjusts +// the coords so that we never try to blt in from this range +// +BOOL ClippedBitBlt(HDC hdcDest, int x, int y, int width, int height, HDC hdcSrc, int srcx, int srcy, DWORD dwROP) +{ + if(srcx < 0) + { + x = 0 - srcx; + width = width + srcx; + srcx = 0; + } + + if(srcy < 0) + { + y = 0 - srcy; + height = height + srcy; + srcy = 0; + } + + return BitBlt(hdcDest, x, y, width, height, hdcSrc, srcx, srcy, dwROP); +} + +void CardRegion::MoveDragCardTo(HDC hdc, int x, int y) +{ + RECT inter, rect1, rect2; + + //mask off the new position of the drag-card, so + //that it will not be painted over + ClipCard(hdc, x, y, nDragCardWidth, nDragCardHeight); + + //restore the area covered by the card at its previous position + BitBlt(hdc, oldx, oldy, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY); + + //remove clipping so we can draw the card at its new place + SelectClipRgn(hdc, NULL); + + //if the card's old and new positions overlap, then we + //need some funky code to update the "saved background" image, + SetRect(&rect1, oldx, oldy, oldx+nDragCardWidth, oldy+nDragCardHeight); + SetRect(&rect2, x, y, x+nDragCardWidth, y+nDragCardHeight); + + if(IntersectRect(&inter, &rect1, &rect2)) + { + int interwidth = inter.right-inter.left; + int interheight = inter.bottom-inter.top; + int destx, desty, srcx, srcy; + + if(rect2.left > rect1.left) + { + destx = 0; srcx = nDragCardWidth - interwidth; + } + else + { + destx = nDragCardWidth - interwidth; srcx = 0; + } + + if(rect2.top > rect1.top) + { + desty = 0; srcy = nDragCardHeight - interheight; + } + else + { + desty = nDragCardHeight - interheight; srcy = 0; + } + + //shift the bit we didn't use for the restore (due to the clipping) + //into the opposite corner + BitBlt(hdcBackGnd, destx,desty, interwidth, interheight, hdcBackGnd, srcx, srcy, SRCCOPY); + + ExcludeClipRect(hdcBackGnd, destx, desty, destx+interwidth, desty+interheight); + + //this bit requires us to clip the BitBlt (from screen to background) + //as BitBlt is a bit buggy it seems + ClippedBitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY); + SelectClipRgn(hdcBackGnd, NULL); + } + else + { + BitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY); + } + + //finally draw the card to the screen + DrawCard(hdc, x, y, hdcDragCard, nDragCardWidth, nDragCardHeight); +} + + +//extern "C" int _fltused(void) { return 0; } +//extern "C" int _ftol(void) { return 0; } + +// +// Better do this in fixed-point, to stop +// VC from linking in floatingpoint-long conversions +// +//#define FIXED_PREC_MOVE +#ifdef FIXED_PREC_MOVE +#define PRECISION 12 +void ZoomCard(HDC hdc, int xpos, int ypos, CARDSTACK *dest) +{ + long dx, dy, x , y; + + + int apparentcards; + x = xpos << PRECISION; y = ypos << PRECISION; + + oldx = (int)xpos; + oldy = (int)ypos; + + apparentcards=dest->numcards/dest->threedcount; + + int idestx = dest->xpos + dest->xoffset * (apparentcards);// - iNumDragCards); + int idesty = dest->ypos + dest->yoffset * (apparentcards);// - iNumDragCards); + + //normalise the motion vector + dx = (idestx<>PRECISION; + iy = (int)y>>PRECISION; + if(dx < 0 && ix < idestx) ix = idestx; + else if(dx > 0 && ix > idestx) ix = idestx; + + if(dy < 0 && iy < idesty) iy = idesty; + else if(dy > 0 && iy > idesty) iy = idesty; + + MoveDragCardTo(hdc, ix, iy); + + if(ix == idestx && iy == idesty) + break; + + oldx = (int)x >> PRECISION; + oldy = (int)y >> PRECISION; + + //dx *= 1.2; + //dy *= 1.2; + + Sleep(10); + } +} +#else +void CardRegion::ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *pDestStack) +{ + double dx, dy, x ,y; + int apparentcards; + x = (double)xpos; y = (double)ypos; + + oldx = (int)x; + oldy = (int)y; + + apparentcards = pDestStack->cardstack.NumCards() / pDestStack->nThreedCount; + + int idestx = pDestStack->xpos + pDestStack->xoffset * (apparentcards); + int idesty = pDestStack->ypos + pDestStack->yoffset * (apparentcards); + + if(pDestStack->yoffset < 0) + idesty += pDestStack->yoffset * (iNumDragCards-1); + + if(pDestStack->xoffset < 0) + idestx += pDestStack->xoffset * (iNumDragCards-1); + + //normalise the motion vector + dx = idestx - x; + dy = idesty - y; + double recip = 1.0 / sqrt(dx*dx + dy*dy); + dx *= recip * __CARDZOOMSPEED; dy *= recip * __CARDZOOMSPEED; + + //if(dx < 0) dxinc = 1.001; else + + for(;;) + { + bool attarget = true; + int ix, iy; + x += dx; + y += dy; + + ix = (int)x; + iy = (int)y; + if(dx < 0.0 && ix < idestx) ix = idestx; + else if(dx > 0.0 && ix > idestx) ix = idestx; + else attarget = false; + + if(dy < 0.0 && iy < idesty) iy = idesty; + else if(dy > 0.0 && iy > idesty) iy = idesty; + else attarget = false; + + //if the target stack wants the drag cards drawn differently + //to how they are, then redraw the drag card image just before + //the cards land + /*if(attarget == true) + { + for(int i = 0; i < iNumDragCards; i++) + { + int xdraw = pDestStack->xoffset*i; + int ydraw = pDestStack->yoffset*i; + + if(pDestStack->yoffset < 0) + ydraw = -pDestStack->yoffset * (iNumDragCards-i-1); + if(pDestStack->xoffset < 0) + xdraw = -pDestStack->xoffset * (iNumDragCards-i-1); + + if(pDestStack->facedirection == CS_FACEUP && + pDestStack->numcards+i >= dest->numfacedown) + { + //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0); + } + else + { + //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0); + } + } + }*/ + + MoveDragCardTo(hdc, ix, iy); + + if(attarget || ix == idestx && iy == idesty) + break; + + oldx = (int)x; + oldy = (int)y; + + //dx *= 1.2; + //dy *= 1.2; + + Sleep(10); + } +} +#endif diff --git a/rosapps/games/solitaire/cardlib/cardrgnmouse.cpp.bak b/rosapps/games/solitaire/cardlib/cardrgnmouse.cpp.bak new file mode 100644 index 00000000000..1a913dcb31d --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardrgnmouse.cpp.bak @@ -0,0 +1,618 @@ +// +// CardLib - CardRegion mouse-related stuff +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include + +#include "cardlib.h" +#include "cardwindow.h" +#include "cardregion.h" + +double __CARDZOOMSPEED = 32; + +int ClipCard(HDC hdc, int x, int y, int width, int height); +void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height); + +#ifdef _DEBUG + +static pDebugClickProc DebugStackClickProc = 0; + +void CardLib_SetStackClickProc(pDebugClickProc proc) +{ + DebugStackClickProc = proc; +} + +#endif + +CardRegion *CardWindow::GetBestStack(int x, int y, int w, int h) +{ + int maxoverlap = 0; + int maxoverlapidx = -1; + + //find the stack which is most covered by the dropped + //cards. Only include those which allow drops. + // + for(int i = 0; i < nNumCardRegions; i++) + { + int percent = Regions[i]->GetOverlapRatio(x, y, w, h); + + //if this stack has the biggest coverage yet + if(percent > maxoverlap && Regions[i]->IsVisible()) + { + maxoverlap = percent; + maxoverlapidx = i; + } + } + + //if we found a stack to drop onto + if(maxoverlapidx != -1) + { + return Regions[maxoverlapidx]; + } + else + { + return 0; + } +} + +bool CardRegion::IsPointInStack(int x, int y) +{ + int axpos = xoffset < 0 ? xpos + (nNumApparentCards-1)*xoffset : xpos; + int aypos = yoffset < 0 ? ypos + (nNumApparentCards-1)*yoffset : ypos; + + if(x >= axpos && x < axpos + width && y >= aypos && y < aypos + height && fVisible) + return true; + else + return false; +} + +int CardRegion::GetNumDragCards(int x, int y) +{ + int cardindex = 0; //index from stack start + int maxidx; + + //make x,y relative to the stack's upper left corner + x -= xpos + (xoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * xoffset : 0); + y -= ypos + (yoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * yoffset : 0); + + //if stack is empty, cannot drag any cards from it + if(cardstack.NumCards() <= 0) + return 0; + + //see which card in the stack has been clicked on + //top-bottom ordering + if(yoffset > 0) + { + if(y < height - __cardheight) + cardindex = y / yoffset; + else + cardindex = cardstack.NumCards() - 1; + } + else if(yoffset < 0) + { + if(y < __cardheight) + cardindex = cardstack.NumCards() - 1; + else + cardindex = cardstack.NumCards() - ((y - __cardheight) / -yoffset) - 2; + } + else //yoffset == 0 + { + cardindex = cardstack.NumCards() - 1; + } + + maxidx = cardindex; + + //if left-right + if(xoffset > 0) + { + if(x < width - __cardwidth) + cardindex = x / xoffset; + else + cardindex = cardstack.NumCards() - 1; + } + else if(xoffset < 0) + { + if(x < __cardwidth) + cardindex = cardstack.NumCards() - 1; + else + cardindex = cardstack.NumCards() - ((x - __cardwidth) / -xoffset) - 2; + } + else + { + cardindex = cardstack.NumCards() - 1; + } + + if(cardindex > maxidx) cardindex = maxidx; + + if(cardindex > cardstack.NumCards()) + cardindex = 1; + + //if are trying to drag too many cards at once + return cardstack.NumCards() - cardindex; +} + +bool CardRegion::CanDragCards(int iNumCards) +{ + if(iNumCards <= 0) return false; + if(nThreedCount > 1 && iNumCards > 1) return false; + + if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0) + { +// TRACE("Failed to gain access to card stack\n"); + return false; + } + + ReleaseMutex(mxlock); + + switch(uDragRule) + { + case CS_DRAG_ALL: + return true; + + case CS_DRAG_TOP: + + if(iNumCards == 1) + return true; + else + return false; + + case CS_DRAG_NONE: + return false; + + case CS_DRAG_CALLBACK: + + if(CanDragCallback) + { + return CanDragCallback(*this, iNumCards); + } + else + { + return false; + } + + default: + return false; + } +} + +bool CardRegion::CanDropCards(CardStack &cards) +{ + if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0) + { + return false; + } + + ReleaseMutex(mxlock); + + switch(uDropRule) + { + case CS_DROP_ALL: + return true; + + case CS_DROP_NONE: + return false; + + case CS_DROP_CALLBACK: + + if(CanDropCallback) + { + return CanDropCallback(*this, cards); + } + else + { + return false; + } + + default: + return false; + } +} + +bool CardRegion::OnLButtonDblClk(int x, int y) +{ + iNumDragCards = GetNumDragCards(x, y); + + if(DblClickCallback) + DblClickCallback(*this, iNumDragCards); + + return true; +} + +bool CardRegion::OnLButtonDown(int x, int y) +{ + iNumDragCards = GetNumDragCards(x, y); + +#ifdef _DEBUG + if(DebugStackClickProc) + { + if(!DebugStackClickProc(*this)) + return false; + } +#endif + + if(ClickCallback) + ClickCallback(*this, iNumDragCards); + + if(CanDragCards(iNumDragCards) != false) + { + + //offset of the mouse cursor relative to the top-left corner + //of the cards that are being dragged + mousexoffset = x - xpos - xoffset * (nNumApparentCards - iNumDragCards); + mouseyoffset = y - ypos - yoffset * (nNumApparentCards - iNumDragCards); + + if(xoffset < 0) + mousexoffset += -xoffset * (iNumDragCards - 1); + + if(yoffset < 0) + mouseyoffset += -yoffset * (iNumDragCards - 1); + + //remove the cards from the source stack + dragstack = cardstack.Pop(iNumDragCards); + + //prepare the back buffer, and the drag image + PrepareDragBitmaps(iNumDragCards); + + oldx = x - mousexoffset; + oldy = y - mouseyoffset; + + Update(); //Update this stack's card count + size + + SetCapture((HWND)parentWnd); + + //set AFTER settings the dragstack... + fMouseDragging = true; + + return true; + } + + return false; +} + +bool CardRegion::OnLButtonUp(int x, int y) +{ + CardRegion *pDestStack = 0; + HDC hdc; + int dropstackid = CS_DROPZONE_NODROP; + + RECT dragrect; + DropZone *dropzone; + + fMouseDragging = false; + + //first of all, see if any drop zones have been registered + SetRect(&dragrect, x-mousexoffset, y-mouseyoffset, x-mousexoffset+nDragCardWidth, y-mouseyoffset+nDragCardHeight); + + dropzone = parentWnd.GetDropZoneFromRect(&dragrect); + + if(dropzone) + { + dropstackid = dropzone->DropCards(dragstack); + + if(dropstackid != CS_DROPZONE_NODROP) + pDestStack = parentWnd.CardRegionFromId(dropstackid); + else + pDestStack = 0; + } + else + { + pDestStack = parentWnd.GetBestStack(x - mousexoffset, y - mouseyoffset, nDragCardWidth, nDragCardHeight); + } + + // If have found a stack to drop onto + // + if(pDestStack && pDestStack->CanDropCards(dragstack)) + { + hdc = GetDC((HWND)parentWnd); + // UseNicePalette(hdc); + ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, pDestStack); + ReleaseDC((HWND)parentWnd, hdc); + + // + //add the cards to the destination stack + // + CardStack temp = pDestStack->GetCardStack(); + temp.Push(dragstack); + + pDestStack->SetCardStack(temp); +// pDestStack->Update(); //Update this stack's card count + size +// pDestStack->UpdateFaceDir(temp); + + // Call the remove callback on THIS stack, if one is specified + // + if(RemoveCallback) + RemoveCallback(*this, iNumDragCards); + + // Call the add callback, if one is specified + // + if(pDestStack->AddCallback) + pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);//index, deststack->numcards); + + RedrawIfNotDim(pDestStack, true); + } + + // + // Otherwise, let the cards snap back onto this stack + // + else + { + + hdc = GetDC((HWND)parentWnd); + ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this); + cardstack += dragstack; + ReleaseDC((HWND)parentWnd, hdc); + + Update(); //Update this stack's card count + size + } + + ReleaseDragBitmaps(); + ReleaseCapture(); + + return true; +} + +bool CardRegion::OnMouseMove(int x, int y) +{ + HDC hdc; + + hdc = GetDC((HWND)parentWnd); + + x -= mousexoffset; + y -= mouseyoffset; + + MoveDragCardTo(hdc, x, y); + + //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY); + //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY); + + ReleaseDC((HWND)parentWnd, hdc); + + oldx = x; + oldy = y; + + return true; +} + +// +// There is a bug in BitBlt when the source x,y +// become < 0. So this wrapper function simply adjusts +// the coords so that we never try to blt in from this range +// +BOOL ClippedBitBlt(HDC hdcDest, int x, int y, int width, int height, HDC hdcSrc, int srcx, int srcy, DWORD dwROP) +{ + if(srcx < 0) + { + x = 0 - srcx; + width = width + srcx; + srcx = 0; + } + + if(srcy < 0) + { + y = 0 - srcy; + height = height + srcy; + srcy = 0; + } + + return BitBlt(hdcDest, x, y, width, height, hdcSrc, srcx, srcy, dwROP); +} + +void CardRegion::MoveDragCardTo(HDC hdc, int x, int y) +{ + RECT inter, rect1, rect2; + + //mask off the new position of the drag-card, so + //that it will not be painted over + ClipCard(hdc, x, y, nDragCardWidth, nDragCardHeight); + + //restore the area covered by the card at its previous position + BitBlt(hdc, oldx, oldy, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY); + + //remove clipping so we can draw the card at its new place + SelectClipRgn(hdc, NULL); + + //if the card's old and new positions overlap, then we + //need some funky code to update the "saved background" image, + SetRect(&rect1, oldx, oldy, oldx+nDragCardWidth, oldy+nDragCardHeight); + SetRect(&rect2, x, y, x+nDragCardWidth, y+nDragCardHeight); + + if(IntersectRect(&inter, &rect1, &rect2)) + { + int interwidth = inter.right-inter.left; + int interheight = inter.bottom-inter.top; + int destx, desty, srcx, srcy; + + if(rect2.left > rect1.left) + { + destx = 0; srcx = nDragCardWidth - interwidth; + } + else + { + destx = nDragCardWidth - interwidth; srcx = 0; + } + + if(rect2.top > rect1.top) + { + desty = 0; srcy = nDragCardHeight - interheight; + } + else + { + desty = nDragCardHeight - interheight; srcy = 0; + } + + //shift the bit we didn't use for the restore (due to the clipping) + //into the opposite corner + BitBlt(hdcBackGnd, destx,desty, interwidth, interheight, hdcBackGnd, srcx, srcy, SRCCOPY); + + ExcludeClipRect(hdcBackGnd, destx, desty, destx+interwidth, desty+interheight); + + //this bit requires us to clip the BitBlt (from screen to background) + //as BitBlt is a bit buggy it seems + ClippedBitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY); + SelectClipRgn(hdcBackGnd, NULL); + } + else + { + BitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY); + } + + //finally draw the card to the screen + DrawCard(hdc, x, y, hdcDragCard, nDragCardWidth, nDragCardHeight); +} + + +//extern "C" int _fltused(void) { return 0; } +//extern "C" int _ftol(void) { return 0; } + +// +// Better do this in fixed-point, to stop +// VC from linking in floatingpoint-long conversions +// +//#define FIXED_PREC_MOVE +#ifdef FIXED_PREC_MOVE +#define PRECISION 12 +void ZoomCard(HDC hdc, int xpos, int ypos, CARDSTACK *dest) +{ + long dx, dy, x , y; + + + int apparentcards; + x = xpos << PRECISION; y = ypos << PRECISION; + + oldx = (int)xpos; + oldy = (int)ypos; + + apparentcards=dest->numcards/dest->threedcount; + + int idestx = dest->xpos + dest->xoffset * (apparentcards);// - iNumDragCards); + int idesty = dest->ypos + dest->yoffset * (apparentcards);// - iNumDragCards); + + //normalise the motion vector + dx = (idestx<>PRECISION; + iy = (int)y>>PRECISION; + if(dx < 0 && ix < idestx) ix = idestx; + else if(dx > 0 && ix > idestx) ix = idestx; + + if(dy < 0 && iy < idesty) iy = idesty; + else if(dy > 0 && iy > idesty) iy = idesty; + + MoveDragCardTo(hdc, ix, iy); + + if(ix == idestx && iy == idesty) + break; + + oldx = (int)x >> PRECISION; + oldy = (int)y >> PRECISION; + + //dx *= 1.2; + //dy *= 1.2; + + Sleep(10); + } +} +#else +void CardRegion::ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *pDestStack) +{ + double dx, dy, x ,y; + int apparentcards; + x = (double)xpos; y = (double)ypos; + + oldx = (int)x; + oldy = (int)y; + + apparentcards = pDestStack->cardstack.NumCards() / pDestStack->nThreedCount; + + int idestx = pDestStack->xpos + pDestStack->xoffset * (apparentcards); + int idesty = pDestStack->ypos + pDestStack->yoffset * (apparentcards); + + if(pDestStack->yoffset < 0) + idesty += pDestStack->yoffset * (iNumDragCards-1); + + if(pDestStack->xoffset < 0) + idestx += pDestStack->xoffset * (iNumDragCards-1); + + //normalise the motion vector + dx = idestx - x; + dy = idesty - y; + double recip = 1.0 / sqrt(dx*dx + dy*dy); + dx *= recip * __CARDZOOMSPEED; dy *= recip * __CARDZOOMSPEED; + + //if(dx < 0) dxinc = 1.001; else + + for(;;) + { + bool attarget = true; + int ix, iy; + x += dx; + y += dy; + + ix = (int)x; + iy = (int)y; + if(dx < 0.0 && ix < idestx) ix = idestx; + else if(dx > 0.0 && ix > idestx) ix = idestx; + else attarget = false; + + if(dy < 0.0 && iy < idesty) iy = idesty; + else if(dy > 0.0 && iy > idesty) iy = idesty; + else attarget = false; + + //if the target stack wants the drag cards drawn differently + //to how they are, then redraw the drag card image just before + //the cards land + /*if(attarget == true) + { + for(int i = 0; i < iNumDragCards; i++) + { + int xdraw = pDestStack->xoffset*i; + int ydraw = pDestStack->yoffset*i; + + if(pDestStack->yoffset < 0) + ydraw = -pDestStack->yoffset * (iNumDragCards-i-1); + if(pDestStack->xoffset < 0) + xdraw = -pDestStack->xoffset * (iNumDragCards-i-1); + + if(pDestStack->facedirection == CS_FACEUP && + pDestStack->numcards+i >= dest->numfacedown) + { + //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0); + } + else + { + //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0); + } + } + }*/ + + MoveDragCardTo(hdc, ix, iy); + + if(attarget || ix == idestx && iy == idesty) + break; + + oldx = (int)x; + oldy = (int)y; + + //dx *= 1.2; + //dy *= 1.2; + + Sleep(10); + } +} +#endif \ No newline at end of file diff --git a/rosapps/games/solitaire/cardlib/cardstack.cpp b/rosapps/games/solitaire/cardlib/cardstack.cpp new file mode 100644 index 00000000000..147c0962588 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardstack.cpp @@ -0,0 +1,237 @@ +// +// CardLib - CardStack class +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include + +#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 ©this, size_t fromindex) +{ + nNumCards = copythis.nNumCards - fromindex; + + for(int i = 0; i < nNumCards; i++) + cardlist[i] = copythis.cardlist[fromindex + i]; +} + diff --git a/rosapps/games/solitaire/cardlib/cardstack.h b/rosapps/games/solitaire/cardlib/cardstack.h new file mode 100644 index 00000000000..eae8736157b --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardstack.h @@ -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 ©this, size_t fromindex); + + Card cardlist[MAX_CARDSTACK_SIZE]; + int nNumCards; +}; + +#endif diff --git a/rosapps/games/solitaire/cardlib/cardwindow.cpp b/rosapps/games/solitaire/cardlib/cardwindow.cpp new file mode 100644 index 00000000000..748ac71e52b --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardwindow.cpp @@ -0,0 +1,812 @@ +// +// CardLib - CardWindow class +// +// Freeware +// Copyright J Brown 2001 +// +#include +#include + +#include "globals.h" +#include "cardlib.h" +#include "cardbutton.h" +#include "cardregion.h" +#include "cardwindow.h" +#include "cardcolor.h" + +extern HPALETTE __holdplacepal; + +HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette) +{ + HPALETTE hOld; + + hOld = SelectPalette(hdc, hPalette, FALSE); + RealizePalette(hdc); + + return hOld; +} + +void RestorePalette(HDC hdc, HPALETTE hOldPal) +{ + SelectPalette(hdc, hOldPal, TRUE); +} + +HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours); +void PaintRect(HDC hdc, RECT *rect, COLORREF colour); +HBITMAP CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height); +void GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2); + +void LoadCardBitmaps(); +void FreeCardBitmaps(); + +static TCHAR szCardName[] = _T("CardWnd32"); +static bool fRegistered = false; +static LONG uCardBitmapRef = 0; + + +void RegisterCardWindow() +{ + WNDCLASSEX wc; + + //Window class for the main application parent window + wc.cbSize = sizeof(wc); + wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW; + wc.lpfnWndProc = CardWindow::CardWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(CardWindow *); + wc.hInstance = GetModuleHandle(0); + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL, IDC_ARROW); + wc.hbrBackground = 0; + wc.lpszMenuName = 0; + wc.lpszClassName = szCardName; + wc.hIconSm = 0; + + RegisterClassEx(&wc); +} + +CardWindow::CardWindow() : m_hWnd(0) +{ + HDC hdc = GetDC(0); + + nNumButtons = 0; + nNumCardRegions = 0; + nNumDropZones = 0; + nBackCardIdx = 53; + + ResizeWndCallback = 0; + hbmBackImage = 0; + hdcBackImage = 0; + + srand((unsigned)GetTickCount()); + + //All colours (buttons, highlights, decks) + //are calculated off this single base colour + crBackgnd = PALETTERGB(0,80,0);//PALETTERGB(0,64,100); + + // If uCardBitmapRef was previously zero, then + // load the card bitmaps + if(1 == InterlockedIncrement(&uCardBitmapRef)) + { + LoadCardBitmaps(); + + __hPalette = CreateCardPalette(); + + __hdcPlaceHolder = CreateCompatibleDC(hdc); + + __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette); + + __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight); + + } + + ReleaseDC(0, hdc); + + //register the window class if necessary + if(!fRegistered) + { + fRegistered = true; + RegisterCardWindow(); + } + +} + +BOOL CardWindow::Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height) +{ + if(m_hWnd) + return FALSE; + + //Create the window associated with this object + m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szCardName, 0, + WS_CHILD | WS_VISIBLE, + 0,0,100,100, + hwndParent, 0, GetModuleHandle(0), this); + + return TRUE; +} + +BOOL CardWindow::Destroy() +{ + DestroyWindow(m_hWnd); + m_hWnd = 0; + + return TRUE; +} + +CardWindow::~CardWindow() +{ + if(m_hWnd) + DestroyWindow(m_hWnd); + + DeleteAll(); + + if(0 == InterlockedDecrement(&uCardBitmapRef)) + { + FreeCardBitmaps(); + + DeleteObject(__hbmPlaceHolder); + DeleteDC (__hdcPlaceHolder); + + RestorePalette(__hdcPlaceHolder, __holdplacepal); + + if(__hPalette) + DeleteObject(__hPalette); + } +} + +bool CardWindow::DeleteAll() +{ + int i; + + for(i = 0; i < nNumCardRegions; i++) + { + delete Regions[i]; + } + + for(i = 0; i < nNumButtons; i++) + { + delete Buttons[i]; + } + + for(i = 0; i < nNumDropZones; i++) + { + delete dropzone[i]; + } + + nNumCardRegions = nNumButtons = nNumDropZones = 0; + + return true; +} + +void CardWindow::SetBackColor(COLORREF cr) +{ + crBackgnd = cr; + int i; + + // + // Create the exact palette we need to render the buttons/stacks + // + RestorePalette(__hdcPlaceHolder, __holdplacepal); + + if(__hPalette) + DeleteObject(__hPalette); + + __hPalette = CreateCardPalette(); + + // + // re-create the place-holder! + HDC hdc = GetDC(m_hWnd); + + DeleteObject(__hbmPlaceHolder); + + __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette); + + __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight); + //SelectObject(__hdcPlaceHolder, __hbmPlaceHolder); + + //reset all buttons to same colour + for(i = 0; i < nNumButtons; i++) + { + if(Buttons[i]->GetStyle() & CB_PUSHBUTTON) + { + Buttons[i]->SetBackColor(ColorScaleRGB(crBackgnd, RGB(255,255,255), 0.1)); + } + else + { + Buttons[i]->SetBackColor(crBackgnd); + } + } + + for(i = 0; i < nNumCardRegions; i++) + { + Regions[i]->SetBackColor(crBackgnd); + } + + + ReleaseDC(m_hWnd, hdc); +} + +COLORREF CardWindow::GetBackColor() +{ + return crBackgnd; +} + +CardButton* CardWindow::CardButtonFromPoint(int x, int y) +{ + CardButton *bptr = 0; + + POINT pt; + pt.x = x; + pt.y = y; + + //Search BACKWARDS...to reflect the implicit Z-order that + //the button creation provided + for(int i = nNumButtons - 1; i >= 0; i--) + { + bptr = Buttons[i]; + if(PtInRect(&bptr->rect, pt) && bptr->fVisible) + return bptr; + } + + return 0; +} + +CardRegion* CardWindow::CardRegionFromPoint(int x, int y) +{ + POINT pt; + pt.x = x; + pt.y = y; + + //Search BACKWARDS...to reflect the implicit Z-order that + //the stack creation provided + for(int i = nNumCardRegions - 1; i >= 0; i--) + { + if(Regions[i]->IsPointInStack(x, y)) + return Regions[i]; + } + + return 0; +} + +// +// Forward all window messages onto the appropriate +// class instance +// +LRESULT CALLBACK CardWindow::CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + CardWindow *cw = (CardWindow *)GetWindowLong(hwnd, 0); + return cw->WndProc(hwnd, iMsg, wParam, lParam); +} + +void CardWindow::Paint(HDC hdc) +{ + int i; + RECT rect; + int xpos = 10; + HPALETTE hOldPal; + + hOldPal = UseNicePalette(hdc, __hPalette); + + // + // Clip the card stacks so that they won't + // get painted over + // + for(i = 0; i < nNumCardRegions; i++) + { + Regions[i]->Clip(hdc); + } + + // + // Clip the buttons + // + for(i = 0; i < nNumButtons; i++) + { + Buttons[i]->Clip(hdc); + } + + + // Now paint the whole screen with background colour, + // + GetClientRect(m_hWnd, &rect); + + //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd)); + PaintCardRgn(hdc, 0, 0, rect.right, rect.bottom, 0, 0); + SelectClipRgn(hdc, NULL); + + // Don't let cards draw over buttons, so clip buttons again + // + for(i = 0; i < nNumButtons; i++) + { + Buttons[i]->Clip(hdc); + } + + // Paint each card stack in turn + // + for(i = 0; i < nNumCardRegions; i++) + { + Regions[i]->Render(hdc); + } + + // Paint each button now + // + SelectClipRgn(hdc, NULL); + + for(i = 0; i < nNumButtons; i++) + { + Buttons[i]->Redraw(); + } + + RestorePalette(hdc, hOldPal); +} + + + + +LRESULT CALLBACK CardWindow::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + + CREATESTRUCT *cs; + + static CardButton *buttonptr = 0; + static CardRegion *stackptr = 0; + + int x, y, i; + + switch(iMsg) + { + case WM_NCCREATE: + + // When we created this window, we passed in the + // pointer to the class object (CardWindow *) in the + // call to CreateWindow. + cs = (CREATESTRUCT *)lParam; + + // + // associate this class with the window + // + SetWindowLong(hwnd, 0, (LONG)cs->lpCreateParams); + + return 1; + + case WM_NCDESTROY: + // Don't delete anything here.. + break; + + case WM_SIZE: + nWidth = LOWORD(lParam); + nHeight = HIWORD(lParam); + + // + // reposition all the stacks and buttons + // in case any of them are centered, right-justified etc + // + for(i = 0; i < nNumCardRegions; i++) + { + Regions[i]->AdjustPosition(nWidth, nHeight); + } + + for(i = 0; i < nNumButtons; i++) + { + Buttons[i]->AdjustPosition(nWidth, nHeight); + } + + // + // Call the user-defined resize proc AFTER all the stacks + // have been positioned + // + if(ResizeWndCallback) + ResizeWndCallback(nWidth, nHeight); + + return 0; + + case WM_PAINT: + + hdc = BeginPaint(hwnd, &ps); + + Paint(hdc); + + EndPaint(hwnd, &ps); + return 0; + + case WM_TIMER: + + //find the timer object in the registered funcs + /*if(wParam >= 0x10000) + { + for(i = 0; i < nRegFuncs; i++) + { + if(RegFuncs[i].id == wParam) + { + KillTimer(hwnd, wParam); + + //call the registered function!! + RegFuncs[i].func(RegFuncs[i].dwParam); + + RegFuncs[i] = RegFuncs[nRegFuncs-1]; + nRegFuncs--; + } + } + } + else*/ + { + //find the cardstack + CardRegion *stackobj = (CardRegion *)wParam;//CardStackFromId(wParam); + stackobj->DoFlash(); + } + + return 0; + + case WM_LBUTTONDBLCLK: + + x = (short)LOWORD(lParam); + y = (short)HIWORD(lParam); + + if((buttonptr = CardButtonFromPoint(x, y)) != 0) + { + buttonptr->OnLButtonDown(hwnd, x, y); + return 0; + } + + if((stackptr = CardRegionFromPoint(x, y)) != 0) + { + stackptr->OnLButtonDblClk(x, y); + stackptr = 0; + } + + return 0; + + case WM_LBUTTONDOWN: + + x = (short)LOWORD(lParam); + y = (short)HIWORD(lParam); + + //if clicked on a button + if((buttonptr = CardButtonFromPoint(x, y)) != 0) + { + if(buttonptr->OnLButtonDown(hwnd, x, y) == 0) + buttonptr = 0; + + return 0; + } + + if((stackptr = CardRegionFromPoint(x, y)) != 0) + { + if(!stackptr->OnLButtonDown(x, y)) + stackptr = 0; + } + + return 0; + + case WM_LBUTTONUP: + + x = (short)LOWORD(lParam); + y = (short)HIWORD(lParam); + + // + // if we were clicking a button + // + if(buttonptr != 0) + { + buttonptr->OnLButtonUp(hwnd, x, y); + buttonptr = 0; + return 0; + } + + if(stackptr != 0) + { + stackptr->OnLButtonUp(x, y); + stackptr = 0; + return 0; + } + + return 0; + + case WM_MOUSEMOVE: + + x = (short)LOWORD(lParam); + y = (short)HIWORD(lParam); + + // if we were clicking a button + if(buttonptr != 0) + { + buttonptr->OnMouseMove(hwnd, x, y); + return 0; + } + + if(stackptr != 0) + { + return stackptr->OnMouseMove(x, y); + } + + return 0; + + } + + return DefWindowProc (hwnd, iMsg, wParam, lParam); +} + + +CardRegion* CardWindow::CardRegionFromId(int id) +{ + for(int i = 0; i < nNumCardRegions; i++) + { + if(Regions[i]->id == id) + return Regions[i]; + } + + return 0; +} + +CardButton* CardWindow::CardButtonFromId(int id) +{ + for(int i = 0; i < nNumButtons; i++) + { + if(Buttons[i]->id == id) + return Buttons[i]; + } + + return 0; +} + +void CardWindow::Redraw() +{ + InvalidateRect(m_hWnd, 0, 0); + UpdateWindow(m_hWnd); +} + +bool CardWindow::DeleteButton(CardButton *pButton) +{ + for(int i = 0; i < nNumButtons; i++) + { + if(Buttons[i] == pButton) + { + CardButton *cb = Buttons[i]; + + //shift any after this one backwards + for(int j = i; j < nNumButtons - 1; j++) + { + Buttons[j] = Buttons[j + 1]; + } + + delete cb; + nNumButtons--; + + return true; + } + } + + return false; +} + +bool CardWindow::DeleteRegion(CardRegion *pRegion) +{ + for(int i = 0; i < nNumCardRegions; i++) + { + if(Regions[i] == pRegion) + { + CardRegion *cr = Regions[i]; + + //shift any after this one backwards + for(int j = i; j < nNumCardRegions - 1; j++) + { + Regions[j] = Regions[j + 1]; + } + + delete cr; + nNumCardRegions--; + + return true; + } + } + + return false; +} + +void CardWindow::EmptyStacks(void) +{ + for(int i = 0; i < nNumCardRegions; i++) + { + Regions[i]->Clear(); + Regions[i]->Update(); + } + + Redraw(); +} + +bool CardWindow::DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX) +{ + int numvisiblestacks = 0; + int curx = nStartX; + int startindex = -1; + int i; + + //find the stack which starts with our ID + for(i = 0; i < nNumCardRegions; i++) + { + if(Regions[i]->Id() == nIdFrom) + { + startindex = i; + break; + } + } + + //if didn't find, return + if(i == nNumCardRegions) return false; + + //count the stacks that are visible + for(i = startindex; i < startindex + nNumStacks; i++) + { + if(Regions[i]->IsVisible()) + numvisiblestacks++; + } + + if(xJustify == CS_XJUST_CENTER) + { + //startx -= ((numvisiblestacks + spacing) * cardwidth - spacing) / 2; + int viswidth; + viswidth = numvisiblestacks * __cardwidth; + viswidth += xSpacing * (numvisiblestacks - 1); + curx = -(viswidth - __cardwidth) / 2; + + for(i = startindex; i < startindex + nNumStacks; i++) + { + if(Regions[i]->IsVisible()) + { + Regions[i]->xadjust = curx; + Regions[i]->xjustify = CS_XJUST_CENTER; + curx += Regions[i]->width + xSpacing; + } + + } + } + + if(xJustify == CS_XJUST_RIGHT) + { + nStartX -= ((numvisiblestacks + xSpacing) * __cardwidth - xSpacing); + } + + if(xJustify == CS_XJUST_NONE) + { + for(i = startindex; i < startindex + nNumStacks; i++) + { + if(Regions[i]->IsVisible()) + { + Regions[i]->xpos = curx; + curx += Regions[i]->width + xSpacing; + Regions[i]->UpdateSize(); + } + + } + } + + return 0; +} + +void CardWindow::Update() +{ + for(int i = 0; i < nNumCardRegions; i++) + { + Regions[i]->AdjustPosition(nWidth, nHeight); + } +} + + +void CardWindow::SetResizeProc(pResizeWndProc proc) +{ + ResizeWndCallback = proc; +} + + +HPALETTE CardWindow::CreateCardPalette() +{ + COLORREF cols[10]; + int nNumCols; + + + //include button text colours + cols[0] = RGB(0, 0, 0); + cols[1] = RGB(255, 255, 255); + + //include the base background colour + cols[1] = crBackgnd; + + //include the standard button colours... + cols[3] = CardButton::GetHighlight(crBackgnd); + cols[4] = CardButton::GetShadow(crBackgnd); + cols[5] = CardButton::GetFace(crBackgnd); + + //include the sunken image bitmap colours... + GetSinkCols(crBackgnd, &cols[6], &cols[7], &cols[8], &cols[9]); + + nNumCols = 10; + + return MakePaletteFromCols(cols, nNumCols); +} + +void CardWindow::SetBackCardIdx(UINT uBackIdx) +{ + if(uBackIdx >= 52 && uBackIdx <= 68) + nBackCardIdx = uBackIdx; + + for(int i = 0; i < nNumCardRegions; i++) + Regions[i]->SetBackCardIdx(uBackIdx); + +} + +void CardWindow::PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy) +{ + RECT rect; + + //if just a solid background colour + if(hbmBackImage == 0) + { + SetRect(&rect, dx, dy, dx+width, dy+height); + + /*if(GetVersion() < 0x80000000) + { + PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd)); + } + else*/ + { + HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBackgnd)); + FillRect(hdc, &rect, hbr); + DeleteObject(hbr); + } + } + //otherwise, paint using the bitmap + else + { + // Draw whatever part of background we can + BitBlt(hdc, dx, dy, width, height, hdcBackImage, sx, sy, SRCCOPY); + + // Now we need to paint any area outside the bitmap, + // just in case the bitmap is too small to fill whole window + if(0)//sx + width > bm.bmWidth || sy + height > bm.bmHeight) + { + // Find out size of bitmap + BITMAP bm; + GetObject(hbmBackImage, sizeof(bm), &bm); + + HRGN hr1 = CreateRectRgn(sx, sy, sx+width, sy+height); + HRGN hr2 = CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight); + HRGN hr3 = CreateRectRgn(0,0, 1, 1); + HRGN hr4 = CreateRectRgn(0,0, 1, 1); + + CombineRgn(hr3, hr1, hr2, RGN_DIFF); + + GetClipRgn(hdc, hr4); + + CombineRgn(hr3, hr4, hr3, RGN_AND); + SelectClipRgn(hdc, hr3); + + // Fill remaining space not filled with bitmap + HBRUSH hbr = CreateSolidBrush(crBackgnd); + FillRgn(hdc, hr3, hbr); + DeleteObject(hbr); + + // Clean up + SelectClipRgn(hdc, hr4); + + DeleteObject(hr1); + DeleteObject(hr2); + DeleteObject(hr3); + DeleteObject(hr4); + } + } +} + +void CardWindow::SetBackImage(HBITMAP hBitmap) +{ + //delete current image?? NO! + if(hdcBackImage == 0) + { + hdcBackImage = CreateCompatibleDC(0); + } + + hbmBackImage = hBitmap; + + if(hBitmap) + SelectObject(hdcBackImage, hBitmap); +} diff --git a/rosapps/games/solitaire/cardlib/cardwindow.h b/rosapps/games/solitaire/cardlib/cardwindow.h new file mode 100644 index 00000000000..bcc24092e18 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/cardwindow.h @@ -0,0 +1,119 @@ +#ifndef CARDBOARD_INCLUDED +#define CARDBOARD_INCLUDED + +#define MAXBUTTONS 32 +#define MAXCARDSTACKS 32 +#define MAXDROPZONES 8 + +#include "dropzone.h" +#include "cardlib.h" + +class CardRegion; +class CardButton; + +LRESULT CALLBACK CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); + +class CardWindow +{ + friend class CardRegion; + friend class CardButton; + + friend void RegisterCardWindow(); + +public: + + CardWindow(); + ~CardWindow(); + + // + // Basic windowing support + // + BOOL Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height); + BOOL Destroy(); + + operator HWND() { return m_hWnd; } + + CardButton *CreateButton (int id, TCHAR *szText, UINT uStyle, bool fVisible, int x, int y, int width, int height); + CardRegion *CreateRegion (int id, bool fVisible, int x, int y, int xoffset, int yoffset); + + CardButton *CardButtonFromId(int id); + CardRegion *CardRegionFromId(int id); + + bool DeleteButton(CardButton *pButton); + bool DeleteRegion(CardRegion *pRegion); + bool DeleteAll(); + + void SetBackColor(COLORREF cr); + COLORREF GetBackColor(); + void SetBackCardIdx(UINT uBackIdx); + void SetBackImage(HBITMAP hBitmap); + + void EmptyStacks(void); + void Redraw(void); + void Update(void); + + bool DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX); + void SetResizeProc(pResizeWndProc proc); + int GetWidth() { return nWidth; } + int GetHeight() { return nHeight; } + + // + // Dropzone support + // + bool RegisterDropZone(int id, RECT *rect, pDropZoneProc proc); + bool DeleteDropZone(int id); + +private: + + int GetNumDropZones() { return nNumDropZones; } + DropZone* GetDropZoneFromRect(RECT *rect); + + // + // Window procedure - don't call + // + LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); + + // + // Private functions + // + void Paint(HDC hdc); + void PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy); + + HPALETTE CreateCardPalette(); + + CardButton *CardButtonFromPoint(int x, int y); + CardRegion *CardRegionFromPoint(int x, int y); + CardRegion *GetBestStack(int x, int y, int w, int h); + + // + // Private members + // + + HWND m_hWnd; //window handle! + int nWidth, nHeight; + + UINT nBackCardIdx; //all stacks share this card index by default + + HBITMAP hbmBackImage; + HDC hdcBackImage; + + + CardButton * Buttons[MAXBUTTONS]; + int nNumButtons; + + CardRegion * Regions[MAXCARDSTACKS]; + int nNumCardRegions; + + DropZone * dropzone[MAXDROPZONES]; + int nNumDropZones; + + COLORREF crBackgnd; + + pResizeWndProc ResizeWndCallback; + + +}; + + +#endif diff --git a/rosapps/games/solitaire/cardlib/dropzone.cpp b/rosapps/games/solitaire/cardlib/dropzone.cpp new file mode 100644 index 00000000000..dfa6dcc2636 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/dropzone.cpp @@ -0,0 +1,69 @@ +// +// CardLib - DropZone class +// +// Freeware +// Copyright J Brown 2001 +// +#include + +#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; +} + diff --git a/rosapps/games/solitaire/cardlib/dropzone.h b/rosapps/games/solitaire/cardlib/dropzone.h new file mode 100644 index 00000000000..2f5d0802fa0 --- /dev/null +++ b/rosapps/games/solitaire/cardlib/dropzone.h @@ -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 diff --git a/rosapps/games/solitaire/cardlib/globals.h b/rosapps/games/solitaire/cardlib/globals.h new file mode 100644 index 00000000000..e4cdb48013c --- /dev/null +++ b/rosapps/games/solitaire/cardlib/globals.h @@ -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 diff --git a/rosapps/games/solitaire/icon1.ico b/rosapps/games/solitaire/icon1.ico new file mode 100644 index 00000000000..92bcf506ec2 Binary files /dev/null and b/rosapps/games/solitaire/icon1.ico differ diff --git a/rosapps/games/solitaire/makefile b/rosapps/games/solitaire/makefile new file mode 100644 index 00000000000..449a771e950 --- /dev/null +++ b/rosapps/games/solitaire/makefile @@ -0,0 +1,42 @@ + +PATH_TO_TOP = ../../../reactos + +TARGET_TYPE = program + +TARGET_APPTYPE = windows + +TARGET_INSTALLDIR = system32 + +TARGET_NAME = sol + +TARGET_SDKLIBS = kernel32.a user32.a gdi32.a cards.a comctl32.a + +TARGET_GCCLIBS = stdc++ + +TARGET_OBJECTS = $(SOL_OBJECTS) $(CARDLIB_OBJECTS) + +SOL_OBJECTS = \ + solcreate.o \ + solgame.o \ + solitaire.o + +CARDLIB_OBJECTS = \ + cardlib/cardbitmaps.o \ + cardlib/cardbutton.o \ + cardlib/cardcolor.o \ + cardlib/cardcount.o \ + cardlib/cardlib.o \ + cardlib/cardregion.o \ + cardlib/cardrgndraw.o \ + cardlib/cardrgnmouse.o \ + cardlib/cardstack.o \ + cardlib/cardwindow.o \ + cardlib/dropzone.o + +TARGET_CPPFLAGS = -Icardlib -Wall -D__USE_W32API -D_WIN32_IE=0x0501 -D_WIN32_WINNT=0x0501 -D__REACTOS__ + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF diff --git a/rosapps/games/solitaire/resource.h b/rosapps/games/solitaire/resource.h new file mode 100644 index 00000000000..25abe7ec27e --- /dev/null +++ b/rosapps/games/solitaire/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Solitaire.rc +// +#define IDD_DIALOG1 101 +#define IDR_MENU1 102 +#define IDR_ACCELERATOR1 103 +#define IDI_ICON1 104 +#define IDM_GAME_NEW 40001 +#define IDM_GAME_DECK 40002 +#define IDM_GAME_OPTIONS 40003 +#define IDM_GAME_EXIT 40004 +#define IDM_HELP_CONTENTS 40005 +#define IDM_HELP_ABOUT 40006 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40007 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/rosapps/games/solitaire/sol.rc b/rosapps/games/solitaire/sol.rc new file mode 100644 index 00000000000..cfc0760edfd --- /dev/null +++ b/rosapps/games/solitaire/sol.rc @@ -0,0 +1,144 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +/* winemaker: #include "afxres.h" */ +/* winemaker:warning: 'afxres.h' is an MFC specific header. Replacing it with 'winres.h' */ +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU DISCARDABLE +BEGIN + POPUP "&Game" + BEGIN + MENUITEM "&Deal\tF2", IDM_GAME_NEW + MENUITEM SEPARATOR + MENUITEM "De&ck...", IDM_GAME_DECK + MENUITEM "&Options...", IDM_GAME_OPTIONS + MENUITEM SEPARATOR + MENUITEM "&Exit", IDM_GAME_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&Contents\tF1", IDM_HELP_CONTENTS + MENUITEM "&About", IDM_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE +BEGIN + VK_F1, IDM_HELP_CONTENTS, VIRTKEY, NOINVERT + VK_F2, IDM_GAME_NEW, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/rosapps/games/solitaire/solcreate.cpp b/rosapps/games/solitaire/solcreate.cpp new file mode 100644 index 00000000000..9f2facbc87e --- /dev/null +++ b/rosapps/games/solitaire/solcreate.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include "resource.h" +#include "cardlib/cardlib.h" + +#include "solitaire.h" + +const int yBorder = 20; +const int xBorder = 20; +const int yRowStacks = yBorder + 128; + +CardRegion *pDeck; +CardRegion *pPile; +CardRegion *pSuitStack[4]; +CardRegion *pRowStack[NUM_ROW_STACKS]; + +extern CardStack activepile; + +HBITMAP hbmBitmap; +HDC hdcBitmap; + +void CreateSol() +{ + int i; + +// hbmBitmap = (HBITMAP)LoadImage(0,"test.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE); +// SolWnd.SetBackImage(hbmBitmap); + + activepile.Clear(); + + + pDeck = SolWnd.CreateRegion(DECK_ID, true, xBorder, yBorder, 2, 1); + pDeck->SetEmptyImage(CS_EI_SUNK); + pDeck->SetThreedCount(6); + pDeck->SetDragRule(CS_DRAG_NONE, 0); + pDeck->SetDropRule(CS_DROP_NONE, 0); + pDeck->SetClickProc(DeckClickProc); + pDeck->SetDblClickProc(DeckClickProc); + pDeck->SetFaceDirection(CS_FACE_DOWN, 0); + + pPile = SolWnd.CreateRegion(PILE_ID, true, 110, yBorder, CS_DEFXOFF, 1); + pPile->SetEmptyImage(CS_EI_NONE); + pPile->SetDragRule(CS_DRAG_TOP, 0); + pPile->SetDropRule(CS_DROP_NONE, 0); + pPile->SetDblClickProc(PileDblClickProc); + pPile->SetRemoveCardProc(PileRemoveProc); + + // + // Create the suit stacks + // + for(i = 0; i < 4; i++) + { + pSuitStack[i] = SolWnd.CreateRegion(SUIT_ID+i, true, 0, yBorder, 0, 0); + pSuitStack[i]->SetEmptyImage(CS_EI_SUNK); + //pSuitStack[i]->SetPlacement(CS_XJUST_RIGHT, 0, -i * (__cardwidth + 4) - xBorder, 0); + pSuitStack[i]->SetPlacement(CS_XJUST_CENTER, 0, i * (__cardwidth + 10) , 0); + + pSuitStack[i]->SetDropRule(CS_DROP_CALLBACK, SuitStackDropProc); + pSuitStack[i]->SetDragRule(CS_DRAG_TOP); + + pSuitStack[i]->SetAddCardProc(SuitStackAddProc); + } + + // + // Create the row stacks + // + for(i = 0; i < NUM_ROW_STACKS; i++) + { + pRowStack[i] = SolWnd.CreateRegion(ROW_ID+i, true, 0, yRowStacks, 0, 14); + pRowStack[i]->SetEmptyImage(CS_EI_SUNK); + pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i); + + pRowStack[i]->SetPlacement(CS_XJUST_CENTER, 0, + (i - NUM_ROW_STACKS/2) * (__cardwidth + 10), 0); + + pRowStack[i]->SetEmptyImage(CS_EI_NONE); + + pRowStack[i]->SetDragRule(CS_DRAG_CALLBACK, RowStackDragProc); + pRowStack[i]->SetDropRule(CS_DROP_CALLBACK, RowStackDropProc); + pRowStack[i]->SetClickProc(RowStackClickProc); + pRowStack[i]->SetDblClickProc(RowStackDblClickProc); + } + + + +} diff --git a/rosapps/games/solitaire/solgame.cpp b/rosapps/games/solitaire/solgame.cpp new file mode 100644 index 00000000000..b2ae928e583 --- /dev/null +++ b/rosapps/games/solitaire/solgame.cpp @@ -0,0 +1,308 @@ +#include +#include +#include +#include "resource.h" +#include "cardlib/cardlib.h" +//#include "../catch22lib/trace.h" +#include "solitaire.h" + +CardStack activepile; +bool fGameStarted = false; + +void NewGame(void) +{ + int i, j; + + SolWnd.EmptyStacks(); + + //create a new card-stack + CardStack deck; + deck.NewDeck(); + deck.Shuffle(); + activepile.Clear(); + + //deal to each row stack.. + for(i = 0; i < NUM_ROW_STACKS; i++) + { + CardStack temp; + temp.Clear(); + + pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i); + + for(j = 0; j <= i; j++) + { + temp.Push(deck.Pop()); + } + + pRowStack[i]->SetCardStack(temp); + } + + //put the other cards onto the deck + pDeck->SetCardStack(deck); + pDeck->Update(); + + SolWnd.Redraw(); + + fGameStarted = false; +} + +// +// Now follow the stack callback functions. This is where we +// provide the game functionality and rules +// + +// +// Can only drag face-up cards +// +bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards) +{ + int numfacedown; + int numcards; + + stackobj.GetFaceDirection(&numfacedown); + + numcards = stackobj.NumCards(); + + if(iNumDragCards <= numcards-numfacedown) + return true; + else + return false; + +} + +// +// Row a row-stack, we can only drop cards +// that are lower / different colour +// +bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards) +{ + Card dragcard = dragcards[dragcards.NumCards() - 1]; + + //if we are empty, can only drop a stack with a King at bottom + if(stackobj.NumCards() == 0) + { + if(dragcard.LoVal() != 13) + return false; + } + else + { + const CardStack &mystack = stackobj.GetCardStack(); + + //can only drop if card is 1 less + if(mystack[0].LoVal() != dragcard.LoVal() + 1) + return false; + + //can only drop if card is different colour + if( mystack[0].IsBlack() && !dragcard.IsRed() || + !mystack[0].IsBlack() && dragcard.IsRed() ) + return false; + } + + return true; +} + +// +// Can only drop a card onto a suit-stack if the +// card is 1 higher, and is the same suit +// +bool CanDrop(CardRegion &stackobj, Card card) +{ + int topval; + + const CardStack &cardstack = stackobj.GetCardStack(); + + if(cardstack.NumCards() > 0) + { + if(card.Suit() != cardstack[0].Suit()) + { + return false; + } + + topval = cardstack[0].LoVal(); + } + else + { + topval = 0; + } + + //make sure 1 higher + if(card.LoVal() != (topval + 1)) + return false; + + return true; +} + +// +// Can only drop a card onto suit stack if it is same suit, and 1 higher +// +bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, const CardStack &dragcards) +{ + int topval = 0; + + //only drop 1 card at a time + if(dragcards.NumCards() != 1) + return false; + + return CanDrop(stackobj, dragcards[0]); +} + +// +// Single-click on one of the row-stacks +// Turn the top-card over if they are all face-down +// +void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked) +{ + int numfacedown; + + stackobj.GetFaceDirection(&numfacedown); + + //if all face-down, then make top card face-up + if(stackobj.NumCards() == numfacedown) + { + if(numfacedown > 0) numfacedown--; + stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown); + stackobj.Redraw(); + } +} + +// +// Find the suit-stack that can accept the specified card +// +CardRegion *FindSuitStackFromCard(Card card) +{ + for(int i = 0; i < 4; i++) + { + if(CanDrop(*pSuitStack[i], card)) + return pSuitStack[i]; + } + + return 0; +} + +// +// What happens when we add a card to one of the suit stacks? +// Well, nothing (it is already added), but we need to +// check all four stacks (not just this one) to see if +// the game has finished. +// +void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added) +{ + bool fGameOver = true; + + for(int i = 0; i < 4; i++) + { + if(pSuitStack[i]->NumCards() != 13) + { + fGameOver = false; + break; + } + } + + if(fGameOver) + { + MessageBox(SolWnd, _T("Congratulations, you win!!"), szAppName, MB_OK | MB_ICONINFORMATION); + + for(int i = 0; i < 4; i++) + { + pSuitStack[i]->Flash(11, 100); + } + } +} + +// +// Double-click on one of the row stacks +// The aim is to find a suit-stack to move the +// double-clicked card to. +// +void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked) +{ + //can only move 1 card at a time + if(iNumClicked != 1) + return; + + //find a suit-stack to move the card to... + const CardStack &cardstack = stackobj.GetCardStack(); + CardRegion *pDest = FindSuitStackFromCard(cardstack[0]); + + if(pDest != 0) + { + //stackobj.MoveCards(pDest, 1, true); + //use the SimulateDrag funcion, because we get the + //AddProc callbacks called for us on the destination stacks... + stackobj.SimulateDrag(pDest, 1, true); + } +} + +// +// Face-up pile double-click +// +void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked) +{ + RowStackDblClickProc(stackobj, iNumClicked); +} + +// +// What happens when a card is removed from face-up pile? +// +void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems) +{ + //modify our "virtual" pile by removing the same card + //that was removed from the physical card stack + activepile.Pop(iItems); + + //if there is just 1 card left, then modify the + //stack to contain ALL the face-up cards..the effect + //will be, the next time a card is dragged, all the + //previous card-triplets will be available underneath + if(stackobj.NumCards() == 1) + { + stackobj.SetOffsets(0,0); + stackobj.SetCardStack(activepile); + } +} + +// +// Double-click on the deck +// Move 3 cards to the face-up pile +// +void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) +{ + CardStack cardstack = stackobj.GetCardStack(); + CardStack pile = pPile->GetCardStack(); + + fGameStarted = true; + + //reset the face-up pile to represent 3 cards + pPile->SetOffsets(CS_DEFXOFF, 1); + + if(cardstack.NumCards() == 0) + { + pile.Clear(); + + activepile.Reverse(); + cardstack.Push(activepile); + activepile.Clear(); + } + else + { + int numcards = min(3, cardstack.NumCards()); + + //make a "visible" copy of these cards + CardStack temp; + temp = cardstack.Pop(numcards); + temp.Reverse(); + + pile.Clear(); + pile.Push(temp); + + //remove the top 3 from deck + activepile.Push(temp); + } + + activepile.Print(); + + pDeck->SetCardStack(cardstack); + pPile->SetCardStack(pile); + + SolWnd.Redraw(); +} diff --git a/rosapps/games/solitaire/solitaire.cpp b/rosapps/games/solitaire/solitaire.cpp new file mode 100644 index 00000000000..c8e3e66c148 --- /dev/null +++ b/rosapps/games/solitaire/solitaire.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include "resource.h" +#include "cardlib/cardlib.h" + +#include "solitaire.h" + +TCHAR szHelpPath[MAX_PATH]; + +DWORD dwAppStartTime; +HWND hwndMain; +HWND hwndStatus; +HINSTANCE hInstance; + +TCHAR szAppName[] = _T("Solitaire"); + +CardWindow SolWnd; + +LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); + +void MakePath(TCHAR *szDest, UINT nDestLen, TCHAR *szExt) +{ + TCHAR *ptr; + + ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1; + while(*ptr-- != '.'); + lstrcpy(ptr + 1, szExt); +} + +// +// Main entry point +// +int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, PSTR szCmdLine, int iCmdShow) +{ + HWND hwnd; + MSG msg; + WNDCLASSEX wndclass; + INITCOMMONCONTROLSEX ice; + HACCEL hAccelTable; + + hInstance = hInst; + + //Window class for the main application parent window + wndclass.cbSize = sizeof(wndclass); + wndclass.style = 0;//CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInst; + wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_ICON1)); + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)NULL; + wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + wndclass.lpszClassName = szAppName; + wndclass.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 16, 16, 0); + + RegisterClassEx(&wndclass); + + ice.dwSize = sizeof(ice); + ice.dwICC = ICC_BAR_CLASSES; + InitCommonControlsEx(&ice); + + srand((unsigned)GetTickCount());//timeGetTime()); + +// InitCardLib(); + +// LoadSettings(); + + //Construct the path to our help file + MakePath(szHelpPath, MAX_PATH, _T(".hlp")); + + hwnd = CreateWindow(szAppName, // window class name + szAppName, // window caption + WS_OVERLAPPEDWINDOW + ,//|WS_CLIPCHILDREN, // window style + CW_USEDEFAULT, // initial x position + CW_USEDEFAULT, // initial y position + CW_USEDEFAULT, // initial x size + CW_USEDEFAULT, // initial y size + NULL, // parent window handle + NULL, // use window class menu + hInst, // program instance handle + NULL); // creation parameters + + hwndMain = hwnd; + + ShowWindow(hwnd, iCmdShow); + UpdateWindow(hwnd); + + hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); + + while(GetMessage(&msg, NULL,0,0)) + { + if(!TranslateAccelerator(hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + +// SaveSettings(); + + return msg.wParam; +} + + +//----------------------------------------------------------------------------- +LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + static int nWidth, nHeight; + int nStatusHeight = 0;//20; + int parts[] = { 100, -1 }; + UINT ret; + + MINMAXINFO *mmi; + + switch(iMsg) + { + case WM_CREATE: + hwndStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, "Ready", hwnd, 0); + + //SendMessage(hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0); + + SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts); + SendMessage(hwndStatus, SB_SETTEXT, 0 | SBT_NOBORDERS, (LPARAM)""); + + ShowWindow(hwndStatus, SW_HIDE); + + SolWnd.Create(hwnd, WS_EX_CLIENTEDGE, WS_CHILD|WS_VISIBLE, 0, 0, 0, 0); + + CreateSol(); + + NewGame(); + + dwAppStartTime = GetTickCount(); + + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_SIZE: + nWidth = LOWORD(lParam); + nHeight = HIWORD(lParam); + + MoveWindow(SolWnd, 0, 0, nWidth, nHeight-nStatusHeight, TRUE); + //MoveWindow(hwndStatus, 0, nHeight-nStatusHeight, nWidth, nHeight, TRUE); + //parts[0] = nWidth - 256; + //SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts); + + return 0; + + case WM_GETMINMAXINFO: + mmi = (MINMAXINFO *)lParam; + mmi->ptMinTrackSize.x = 600; + mmi->ptMinTrackSize.y = 400; + + return 0; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDM_GAME_NEW: + //simulate a button click on the new button.. + NewGame(); + return 0; + + case IDM_GAME_DECK: + //ShowDeckOptionsDlg(hwnd); + return 0; + + case IDM_GAME_OPTIONS: + //ShowGameOptionsDlg(hwnd); + return 0; + + case IDM_HELP_CONTENTS: + + WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play"); + + return 0; + + case IDM_HELP_ABOUT: + MessageBox(hwnd, _T("Solitare by J Brown\r\n\r\nCardLib version 1.0."), szAppName, MB_OK|MB_ICONINFORMATION); + + return 0; + + case IDM_GAME_EXIT: + PostMessage(hwnd, WM_CLOSE, 0, 0); + return 0; + } + + return 0; + + case WM_CLOSE: + + ret = IDOK; + + if(fGameStarted) + { + ret = MessageBox(hwnd, _T("Quit the current game?"), szAppName, MB_OKCANCEL|MB_ICONQUESTION); + } + + if(ret == IDOK) + { + WinHelp(hwnd, szHelpPath, HELP_QUIT, 0); + DestroyWindow(hwnd); + } + + return 0; + } + + return DefWindowProc (hwnd, iMsg, wParam, lParam); +} + diff --git a/rosapps/games/solitaire/solitaire.h b/rosapps/games/solitaire/solitaire.h new file mode 100644 index 00000000000..a1b1d38bf70 --- /dev/null +++ b/rosapps/games/solitaire/solitaire.h @@ -0,0 +1,37 @@ +#ifndef SOLITAIRE_INCLUDED +#define SOLITAIRE_INCLUDED + +extern CardWindow SolWnd; +extern TCHAR szAppName[]; +extern bool fGameStarted; + +void CreateSol(); +void NewGame(void); + +#define NUM_ROW_STACKS 7 +#define DECK_ID 1 +#define PILE_ID 2 +#define SUIT_ID 4 +#define ROW_ID 10 + +extern CardRegion *pDeck; +extern CardRegion *pPile; +extern CardRegion *pSuitStack[]; +extern CardRegion *pRowStack[]; + + +bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumCards); +bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, const CardStack &dragcards); + +bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, const CardStack &dragcards); +void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added); + +void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked); +void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked); + +void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked); +void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked); + +void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iRemoved); + +#endif