update SVN properties
[reactos.git] / rosapps / games / solitaire / cardlib / cardwindow.cpp
index 4455086..1eea0bf 100644 (file)
-//\r
-//    CardLib - CardWindow class\r
-//\r
-//    Freeware\r
-//    Copyright J Brown 2001\r
-//\r
-#include <windows.h>\r
-#include <tchar.h>\r
-\r
-#include "globals.h"\r
-#include "cardlib.h"\r
-#include "cardbutton.h"\r
-#include "cardregion.h"\r
-#include "cardwindow.h"\r
-#include "cardcolor.h"\r
-\r
-extern HPALETTE __holdplacepal;\r
-\r
-HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette)\r
-{\r
-    HPALETTE hOld;\r
-\r
-    hOld = SelectPalette(hdc, hPalette, FALSE);\r
-    RealizePalette(hdc);\r
-\r
-    return hOld;\r
-}\r
-\r
-void RestorePalette(HDC hdc, HPALETTE hOldPal)\r
-{\r
-    SelectPalette(hdc, hOldPal, TRUE);\r
-}\r
-\r
-HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours);\r
-void     PaintRect(HDC hdc, RECT *rect, COLORREF colour);\r
-HBITMAP  CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height);\r
-void     GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2);\r
-\r
-void     LoadCardBitmaps();\r
-void     FreeCardBitmaps();\r
-\r
-static TCHAR szCardName[]   = _T("CardWnd32");\r
-static bool  fRegistered    = false;\r
-static LONG  uCardBitmapRef = 0;\r
-\r
-\r
-void RegisterCardWindow()\r
-{\r
-    WNDCLASSEX wc;\r
-\r
-    //Window class for the main application parent window\r
-    wc.cbSize            = sizeof(wc);\r
-    wc.style            = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;\r
-    wc.lpfnWndProc        = CardWindow::CardWndProc;\r
-    wc.cbClsExtra        = 0;\r
-    wc.cbWndExtra        = sizeof(CardWindow *);\r
-    wc.hInstance        = GetModuleHandle(0);\r
-    wc.hIcon            = 0;\r
-    wc.hCursor            = LoadCursor (NULL, IDC_ARROW);\r
-    wc.hbrBackground    = 0;\r
-    wc.lpszMenuName        = 0;\r
-    wc.lpszClassName    = szCardName;\r
-    wc.hIconSm            = 0;\r
-\r
-    RegisterClassEx(&wc);\r
-}\r
-\r
-CardWindow::CardWindow() : m_hWnd(0)\r
-{\r
-    HDC hdc = GetDC(0);\r
-\r
-    nNumButtons       = 0;\r
-    nNumCardRegions   = 0;\r
-    nNumDropZones     = 0;\r
-    nBackCardIdx      = 53;\r
-\r
-    ResizeWndCallback = 0;\r
-    hbmBackImage      = 0;\r
-    hdcBackImage      = 0;\r
-\r
-    srand((unsigned)GetTickCount());\r
-\r
-    //All colours (buttons, highlights, decks)\r
-    //are calculated off this single base colour\r
-    crBackgnd = PALETTERGB(0,80,0);//PALETTERGB(0,64,100);\r
-\r
-    // If uCardBitmapRef was previously zero, then\r
-    // load the card bitmaps\r
-    if(1 == InterlockedIncrement(&uCardBitmapRef))\r
-    {\r
-        LoadCardBitmaps();\r
-\r
-        __hPalette  = CreateCardPalette();\r
-\r
-        __hdcPlaceHolder  = CreateCompatibleDC(hdc);\r
-    \r
-        __holdplacepal  = UseNicePalette(__hdcPlaceHolder, __hPalette);\r
-\r
-        __hbmPlaceHolder  = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);\r
-\r
-    }\r
-\r
-    ReleaseDC(0, hdc);\r
-\r
-    //register the window class if necessary\r
-    if(!fRegistered)\r
-    {\r
-        fRegistered = true;\r
-        RegisterCardWindow();\r
-    }\r
-\r
-}\r
-\r
-BOOL CardWindow::Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height)\r
-{\r
-    if(m_hWnd)\r
-        return FALSE;\r
-\r
-    //Create the window associated with this object\r
-    m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szCardName, 0, \r
-        WS_CHILD | WS_VISIBLE,\r
-        0,0,100,100, \r
-        hwndParent, 0, GetModuleHandle(0), this);\r
-\r
-    return TRUE;\r
-}\r
-\r
-BOOL CardWindow::Destroy()\r
-{\r
-    DestroyWindow(m_hWnd);\r
-    m_hWnd = 0;\r
-\r
-    return TRUE;\r
-}\r
-\r
-CardWindow::~CardWindow()\r
-{\r
-    if(m_hWnd)\r
-        DestroyWindow(m_hWnd);\r
-\r
-    DeleteAll();\r
-\r
-    if(0 == InterlockedDecrement(&uCardBitmapRef))\r
-    {\r
-        FreeCardBitmaps();\r
-\r
-        DeleteObject(__hbmPlaceHolder);\r
-        DeleteDC    (__hdcPlaceHolder);\r
-\r
-        RestorePalette(__hdcPlaceHolder, __holdplacepal);\r
-\r
-        if(__hPalette)\r
-            DeleteObject(__hPalette);\r
-    }\r
-}\r
-\r
-bool CardWindow::DeleteAll()\r
-{\r
-    int i;\r
-\r
-    for(i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        delete Regions[i];\r
-    }\r
-\r
-    for(i = 0; i < nNumButtons; i++)\r
-    {\r
-        delete Buttons[i];\r
-    }\r
-\r
-    for(i = 0; i < nNumDropZones; i++)\r
-    {\r
-        delete dropzone[i];\r
-    }\r
-\r
-    nNumCardRegions = nNumButtons = nNumDropZones = 0;\r
-\r
-    return true;\r
-}\r
-\r
-void CardWindow::SetBackColor(COLORREF cr)\r
-{\r
-    crBackgnd = cr;\r
-    int i;\r
-    \r
-    //\r
-    // Create the exact palette we need to render the buttons/stacks\r
-    //\r
-    RestorePalette(__hdcPlaceHolder, __holdplacepal);\r
-\r
-    if(__hPalette)\r
-        DeleteObject(__hPalette);\r
-\r
-    __hPalette = CreateCardPalette();\r
-\r
-    //\r
-    // re-create the place-holder!\r
-    HDC hdc = GetDC(m_hWnd);\r
-\r
-    DeleteObject(__hbmPlaceHolder);\r
-\r
-    __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette);\r
-\r
-    __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);\r
-    //SelectObject(__hdcPlaceHolder, __hbmPlaceHolder);\r
-\r
-    //reset all buttons to same colour\r
-    for(i = 0; i < nNumButtons; i++)\r
-    {\r
-        if(Buttons[i]->GetStyle() & CB_PUSHBUTTON)\r
-        {\r
-            Buttons[i]->SetBackColor(ColorScaleRGB(crBackgnd, RGB(255,255,255), 0.1));\r
-        }\r
-        else\r
-        {\r
-            Buttons[i]->SetBackColor(crBackgnd);\r
-        }\r
-    }\r
-\r
-    for(i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        Regions[i]->SetBackColor(crBackgnd);\r
-    }\r
-\r
-\r
-    ReleaseDC(m_hWnd, hdc);\r
-}\r
-\r
-COLORREF CardWindow::GetBackColor()\r
-{\r
-    return crBackgnd;\r
-}\r
-\r
-CardButton* CardWindow::CardButtonFromPoint(int x, int y)\r
-{\r
-    CardButton *bptr = 0;\r
-\r
-    POINT pt;\r
-    pt.x = x;\r
-    pt.y = y;\r
-\r
-    //Search BACKWARDS...to reflect the implicit Z-order that\r
-    //the button creation provided\r
-    for(int i = nNumButtons - 1; i >= 0; i--)\r
-    {\r
-        bptr = Buttons[i];\r
-        if(PtInRect(&bptr->rect, pt) && bptr->fVisible)\r
-            return bptr;\r
-    }\r
-\r
-    return 0;    \r
-}\r
-\r
-CardRegion* CardWindow::CardRegionFromPoint(int x, int y)\r
-{\r
-    POINT pt;\r
-    pt.x = x;\r
-    pt.y = y;\r
-\r
-    //Search BACKWARDS...to reflect the implicit Z-order that\r
-    //the stack creation provided\r
-    for(int i = nNumCardRegions - 1; i >= 0; i--)\r
-    {\r
-        if(Regions[i]->IsPointInStack(x, y))\r
-            return Regions[i];\r
-    }\r
-\r
-    return 0;    \r
-}\r
-\r
-//\r
-//    Forward all window messages onto the appropriate\r
-//  class instance\r
-//\r
-LRESULT CALLBACK CardWindow::CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    CardWindow *cw = (CardWindow *)GetWindowLong(hwnd, 0);\r
-    return cw->WndProc(hwnd, iMsg, wParam, lParam);\r
-}\r
-\r
-void CardWindow::Paint(HDC hdc)\r
-{\r
-    int i;\r
-    RECT rect;\r
-    HPALETTE hOldPal;\r
-\r
-    hOldPal = UseNicePalette(hdc, __hPalette);\r
-\r
-    //\r
-    //    Clip the card stacks so that they won't\r
-    //    get painted over\r
-    //\r
-    for(i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        Regions[i]->Clip(hdc);\r
-    }\r
-\r
-    //\r
-    //    Clip the buttons \r
-    //\r
-    for(i = 0; i < nNumButtons; i++)\r
-    {\r
-        Buttons[i]->Clip(hdc);\r
-    }\r
-\r
-\r
-    //    Now paint the whole screen with background colour, \r
-    //\r
-    GetClientRect(m_hWnd, &rect);\r
-    \r
-    //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));\r
-    PaintCardRgn(hdc, 0, 0, rect.right, rect.bottom, 0, 0);\r
-    SelectClipRgn(hdc, NULL);\r
-\r
-    //    Don't let cards draw over buttons, so clip buttons again\r
-    //\r
-    for(i = 0; i < nNumButtons; i++)\r
-    {\r
-        Buttons[i]->Clip(hdc);\r
-    }\r
-\r
-    //    Paint each card stack in turn\r
-    //\r
-    for(i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        Regions[i]->Render(hdc);\r
-    }\r
-        \r
-    //    Paint each button now\r
-    //\r
-    SelectClipRgn(hdc, NULL);\r
-\r
-    for(i = 0; i < nNumButtons; i++)\r
-    {\r
-        Buttons[i]->Redraw();\r
-    }\r
-\r
-    RestorePalette(hdc, hOldPal);\r
-}\r
-\r
-\r
-\r
-\r
-LRESULT CALLBACK CardWindow::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    HDC hdc;\r
-    PAINTSTRUCT ps;\r
-\r
-    CREATESTRUCT *cs;\r
-\r
-    static CardButton *buttonptr   = 0;\r
-    static CardRegion *stackptr    = 0;\r
-\r
-    int x, y, i;\r
-\r
-    switch(iMsg)\r
-    {\r
-    case WM_NCCREATE:\r
-\r
-        // When we created this window, we passed in the\r
-        // pointer to the class object (CardWindow *) in the\r
-        // call to CreateWindow.\r
-        cs = (CREATESTRUCT *)lParam;\r
-\r
-        //\r
-        // associate this class with the window\r
-        //\r
-        SetWindowLong(hwnd, 0, (LONG)cs->lpCreateParams);\r
-\r
-        return 1;\r
-\r
-    case WM_NCDESTROY:\r
-        // Don't delete anything here..\r
-        break;\r
-\r
-    case WM_SIZE:\r
-        nWidth = LOWORD(lParam);\r
-        nHeight = HIWORD(lParam);\r
-        \r
-        //\r
-        // reposition all the stacks and buttons\r
-        // in case any of them are centered, right-justified etc\r
-        //\r
-        for(i = 0; i < nNumCardRegions; i++)\r
-        {\r
-            Regions[i]->AdjustPosition(nWidth, nHeight);\r
-        }\r
-    \r
-        for(i = 0; i < nNumButtons; i++)\r
-        {\r
-            Buttons[i]->AdjustPosition(nWidth, nHeight);\r
-        }\r
-\r
-        // \r
-        // Call the user-defined resize proc AFTER all the stacks\r
-        // have been positioned\r
-        //\r
-        if(ResizeWndCallback) \r
-            ResizeWndCallback(nWidth, nHeight);\r
-\r
-        return 0;\r
-\r
-    case WM_PAINT:\r
-\r
-        hdc = BeginPaint(hwnd, &ps);\r
-\r
-        Paint(hdc);\r
-\r
-        EndPaint(hwnd, &ps);\r
-        return 0;\r
-\r
-    case WM_TIMER:\r
-        \r
-        //find the timer object in the registered funcs\r
-        /*if(wParam >= 0x10000)\r
-        {\r
-            for(i = 0; i < nRegFuncs; i++)\r
-            {\r
-                if(RegFuncs[i].id == wParam)\r
-                {\r
-                    KillTimer(hwnd, wParam);\r
-    \r
-                    //call the registered function!!\r
-                    RegFuncs[i].func(RegFuncs[i].dwParam);\r
-    \r
-                    RegFuncs[i] = RegFuncs[nRegFuncs-1];\r
-                    nRegFuncs--;\r
-                }\r
-            }\r
-        }\r
-        else*/\r
-        {\r
-            //find the cardstack\r
-            CardRegion *stackobj = (CardRegion *)wParam;//CardStackFromId(wParam);\r
-            stackobj->DoFlash();\r
-        }\r
-\r
-        return 0;\r
-\r
-    case WM_LBUTTONDBLCLK:\r
-\r
-        x = (short)LOWORD(lParam);\r
-        y = (short)HIWORD(lParam);\r
-\r
-        if((buttonptr = CardButtonFromPoint(x, y)) != 0)\r
-        {\r
-            buttonptr->OnLButtonDown(hwnd, x, y);\r
-            return 0;\r
-        }\r
-\r
-        if((stackptr = CardRegionFromPoint(x, y)) != 0)\r
-        {\r
-            stackptr->OnLButtonDblClk(x, y);\r
-            stackptr = 0;\r
-        }\r
-\r
-        return 0;\r
-\r
-    case WM_LBUTTONDOWN:\r
-\r
-        x = (short)LOWORD(lParam);\r
-        y = (short)HIWORD(lParam);\r
-\r
-        //if clicked on a button\r
-        if((buttonptr = CardButtonFromPoint(x, y)) != 0)\r
-        {\r
-            if(buttonptr->OnLButtonDown(hwnd, x, y) == 0)\r
-                buttonptr = 0;\r
-\r
-            return 0;\r
-        }\r
-\r
-        if((stackptr = CardRegionFromPoint(x, y)) != 0)\r
-        {\r
-            if(!stackptr->OnLButtonDown(x, y))\r
-                stackptr = 0;\r
-        }\r
-        \r
-        return 0;\r
-\r
-    case WM_LBUTTONUP:\r
-        \r
-        x = (short)LOWORD(lParam);\r
-        y = (short)HIWORD(lParam);\r
-\r
-        //\r
-        // if we were clicking a button\r
-        //\r
-        if(buttonptr != 0)\r
-        {\r
-            buttonptr->OnLButtonUp(hwnd, x, y);\r
-            buttonptr = 0;\r
-            return 0;\r
-        }\r
-        \r
-        if(stackptr != 0)\r
-        {\r
-            stackptr->OnLButtonUp(x, y);\r
-            stackptr = 0;\r
-            return 0;\r
-        }\r
-\r
-        return 0;\r
-\r
-    case WM_MOUSEMOVE:\r
-        \r
-        x = (short)LOWORD(lParam);\r
-        y = (short)HIWORD(lParam);\r
-\r
-        // if we were clicking a button\r
-        if(buttonptr != 0)\r
-        {\r
-            buttonptr->OnMouseMove(hwnd, x, y);\r
-            return 0;\r
-        }\r
-\r
-        if(stackptr != 0)\r
-        {\r
-            return stackptr->OnMouseMove(x, y);\r
-        }\r
-        \r
-        return 0;\r
-\r
-    }\r
-\r
-      return DefWindowProc (hwnd, iMsg, wParam, lParam);\r
-}\r
-\r
-\r
-CardRegion* CardWindow::CardRegionFromId(int id)\r
-{\r
-    for(int i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        if(Regions[i]->id == id)\r
-            return Regions[i];\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-CardButton* CardWindow::CardButtonFromId(int id)\r
-{\r
-    for(int i = 0; i < nNumButtons; i++)\r
-    {\r
-        if(Buttons[i]->id == id)\r
-            return Buttons[i];\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-void CardWindow::Redraw()\r
-{\r
-    InvalidateRect(m_hWnd, 0, 0);\r
-    UpdateWindow(m_hWnd);\r
-}\r
-\r
-bool CardWindow::DeleteButton(CardButton *pButton)\r
-{\r
-    for(int i = 0; i < nNumButtons; i++)\r
-    {\r
-        if(Buttons[i] == pButton)\r
-        {\r
-            CardButton *cb = Buttons[i];\r
-            \r
-            //shift any after this one backwards\r
-            for(int j = i; j < nNumButtons - 1; j++)\r
-            {\r
-                Buttons[j] = Buttons[j + 1];\r
-            }\r
-\r
-            delete cb;\r
-            nNumButtons--;\r
-            \r
-            return true;\r
-        }\r
-    }\r
-\r
-    return false;\r
-}\r
-\r
-bool CardWindow::DeleteRegion(CardRegion *pRegion)\r
-{\r
-    for(int i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        if(Regions[i] == pRegion)\r
-        {\r
-            CardRegion *cr = Regions[i];\r
-            \r
-            //shift any after this one backwards\r
-            for(int j = i; j < nNumCardRegions - 1; j++)\r
-            {\r
-                Regions[j] = Regions[j + 1];\r
-            }\r
-\r
-            delete cr;\r
-            nNumCardRegions--;\r
-\r
-            return true;\r
-        }\r
-    }\r
-\r
-    return false;\r
-}\r
-\r
-void CardWindow::EmptyStacks(void)\r
-{\r
-    for(int i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        Regions[i]->Clear();\r
-        Regions[i]->Update();\r
-    }\r
-\r
-    Redraw();\r
-}\r
-\r
-bool CardWindow::DistributeStacks(int nIdFrom, int nNumStacks, UINT xJustify, int xSpacing, int nStartX)\r
-{\r
-    int numvisiblestacks = 0;\r
-    int curx = nStartX;\r
-    int startindex = -1;\r
-    int i;\r
-\r
-    //find the stack which starts with our ID\r
-    for(i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        if(Regions[i]->Id() == nIdFrom)\r
-        {\r
-            startindex = i;\r
-            break;\r
-        }\r
-    }\r
-\r
-    //if didn't find, return\r
-    if(i == nNumCardRegions) return false;\r
-\r
-    //count the stacks that are visible\r
-    for(i = startindex; i < startindex + nNumStacks; i++)\r
-    {\r
-        if(Regions[i]->IsVisible())\r
-            numvisiblestacks++;\r
-    }\r
-    \r
-    if(xJustify == CS_XJUST_CENTER)\r
-    {\r
-        //startx -= ((numvisiblestacks + spacing) * cardwidth - spacing) / 2;\r
-        int viswidth;\r
-        viswidth = numvisiblestacks * __cardwidth;\r
-        viswidth += xSpacing * (numvisiblestacks - 1);\r
-        curx = -(viswidth  - __cardwidth) / 2;\r
-\r
-        for(i = startindex; i < startindex + nNumStacks; i++)\r
-        {\r
-            if(Regions[i]->IsVisible())\r
-            {\r
-                Regions[i]->xadjust = curx;\r
-                Regions[i]->xjustify = CS_XJUST_CENTER;\r
-                curx += Regions[i]->width + xSpacing;\r
-            }\r
-            \r
-        }\r
-    }\r
-\r
-    if(xJustify == CS_XJUST_RIGHT)\r
-    {\r
-        nStartX -= ((numvisiblestacks + xSpacing) * __cardwidth - xSpacing);\r
-    }\r
-    \r
-    if(xJustify == CS_XJUST_NONE)\r
-    {\r
-        for(i = startindex; i < startindex + nNumStacks; i++)\r
-        {\r
-            if(Regions[i]->IsVisible())\r
-            {\r
-                Regions[i]->xpos = curx;\r
-                curx += Regions[i]->width + xSpacing;\r
-                Regions[i]->UpdateSize();\r
-            }\r
-            \r
-        }\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-void CardWindow::Update()\r
-{\r
-    for(int i = 0; i < nNumCardRegions; i++)\r
-    {\r
-        Regions[i]->AdjustPosition(nWidth, nHeight);\r
-    }\r
-}\r
-\r
-\r
-void CardWindow::SetResizeProc(pResizeWndProc proc)\r
-{\r
-    ResizeWndCallback = proc;\r
-}\r
-\r
-\r
-HPALETTE CardWindow::CreateCardPalette()\r
-{\r
-    COLORREF cols[10];\r
-    int nNumCols;\r
-\r
-\r
-    //include button text colours\r
-    cols[0] = RGB(0, 0, 0);\r
-    cols[1] = RGB(255, 255, 255);\r
-\r
-    //include the base background colour\r
-    cols[1] = crBackgnd;\r
-\r
-    //include the standard button colours...\r
-    cols[3] = CardButton::GetHighlight(crBackgnd);\r
-    cols[4] = CardButton::GetShadow(crBackgnd);\r
-    cols[5] = CardButton::GetFace(crBackgnd);\r
-\r
-    //include the sunken image bitmap colours...\r
-    GetSinkCols(crBackgnd, &cols[6], &cols[7], &cols[8], &cols[9]);\r
-\r
-    nNumCols = 10;\r
-\r
-    return MakePaletteFromCols(cols, nNumCols);\r
-}\r
-\r
-void CardWindow::SetBackCardIdx(UINT uBackIdx)\r
-{\r
-    if(uBackIdx >= 52 && uBackIdx <= 68)\r
-        nBackCardIdx = uBackIdx;\r
-\r
-    for(int i = 0; i < nNumCardRegions; i++)\r
-        Regions[i]->SetBackCardIdx(uBackIdx);\r
-\r
-}\r
-\r
-void CardWindow::PaintCardRgn(HDC hdc, int dx, int dy, int width, int height, int sx, int sy)\r
-{\r
-    RECT rect;\r
-\r
-    //if just a solid background colour\r
-    if(hbmBackImage == 0)\r
-    {\r
-        SetRect(&rect, dx, dy, dx+width, dy+height);\r
-        \r
-        /*if(GetVersion() < 0x80000000)\r
-        {\r
-            PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd));\r
-        }\r
-        else*/\r
-        {\r
-            HBRUSH hbr = CreateSolidBrush(MAKE_PALETTERGB(crBackgnd));\r
-            FillRect(hdc, &rect, hbr);\r
-            DeleteObject(hbr);\r
-        }\r
-    }\r
-    //otherwise, paint using the bitmap\r
-    else\r
-    {\r
-        // Draw whatever part of background we can \r
-        BitBlt(hdc, dx, dy, width, height, hdcBackImage, sx, sy, SRCCOPY);\r
-\r
-        // Now we need to paint any area outside the bitmap,\r
-        // just in case the bitmap is too small to fill whole window\r
-        if(0)//sx + width > bm.bmWidth || sy + height > bm.bmHeight)\r
-        {\r
-            // Find out size of bitmap\r
-            BITMAP bm;\r
-            GetObject(hbmBackImage, sizeof(bm), &bm);\r
-\r
-            HRGN hr1 = CreateRectRgn(sx, sy, sx+width, sy+height);\r
-            HRGN hr2 = CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight);\r
-            HRGN hr3 = CreateRectRgn(0,0, 1, 1);\r
-            HRGN hr4 = CreateRectRgn(0,0, 1, 1);\r
-        \r
-            CombineRgn(hr3, hr1, hr2, RGN_DIFF);\r
-        \r
-            GetClipRgn(hdc, hr4);\r
-            \r
-            CombineRgn(hr3, hr4, hr3, RGN_AND);\r
-            SelectClipRgn(hdc, hr3);\r
-        \r
-            // Fill remaining space not filled with bitmap\r
-            HBRUSH hbr = CreateSolidBrush(crBackgnd);\r
-            FillRgn(hdc, hr3, hbr);\r
-            DeleteObject(hbr);\r
-\r
-            // Clean up\r
-            SelectClipRgn(hdc, hr4);\r
-        \r
-            DeleteObject(hr1);\r
-            DeleteObject(hr2);\r
-            DeleteObject(hr3);\r
-            DeleteObject(hr4);\r
-        }\r
-    }\r
-}\r
-\r
-void CardWindow::SetBackImage(HBITMAP hBitmap)\r
-{\r
-    //delete current image?? NO!\r
-    if(hdcBackImage == 0)\r
-    {\r
-        hdcBackImage = CreateCompatibleDC(0);\r
-    }\r
-\r
-    hbmBackImage = hBitmap;\r
-\r
-    if(hBitmap)\r
-        SelectObject(hdcBackImage, hBitmap);\r
-}\r
+//
+//    CardLib - CardWindow class
+//
+//    Freeware
+//    Copyright J Brown 2001
+//
+#include <windows.h>
+#include <tchar.h>
+
+#include "globals.h"
+#include "cardlib.h"
+#include "cardbutton.h"
+#include "cardregion.h"
+#include "cardwindow.h"
+#include "cardcolor.h"
+
+extern HPALETTE __holdplacepal;
+
+HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette)
+{
+    HPALETTE hOld;
+
+    hOld = SelectPalette(hdc, hPalette, FALSE);
+    RealizePalette(hdc);
+
+    return hOld;
+}
+
+void RestorePalette(HDC hdc, HPALETTE hOldPal)
+{
+    SelectPalette(hdc, hOldPal, TRUE);
+}
+
+HPALETTE MakePaletteFromCols(COLORREF cols[], int nNumColours);
+void     PaintRect(HDC hdc, RECT *rect, COLORREF colour);
+HBITMAP  CreateSinkBmp(HDC hdcCompat, HDC hdc, COLORREF col, int width, int height);
+void     GetSinkCols(COLORREF crBase, COLORREF *fg, COLORREF *bg, COLORREF *sh1, COLORREF *sh2);
+
+void     LoadCardBitmaps();
+void     FreeCardBitmaps();
+
+static TCHAR szCardName[]   = _T("CardWnd32");
+static bool  fRegistered    = false;
+static LONG  uCardBitmapRef = 0;
+
+
+void RegisterCardWindow()
+{
+    WNDCLASSEX wc;
+
+    //Window class for the main application parent window
+    wc.cbSize            = sizeof(wc);
+    wc.style            = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
+    wc.lpfnWndProc        = CardWindow::CardWndProc;
+    wc.cbClsExtra        = 0;
+    wc.cbWndExtra        = sizeof(CardWindow *);
+    wc.hInstance        = GetModuleHandle(0);
+    wc.hIcon            = 0;
+    wc.hCursor            = LoadCursor (NULL, IDC_ARROW);
+    wc.hbrBackground    = 0;
+    wc.lpszMenuName        = 0;
+    wc.lpszClassName    = szCardName;
+    wc.hIconSm            = 0;
+
+    RegisterClassEx(&wc);
+}
+
+CardWindow::CardWindow() : m_hWnd(0)
+{
+    HDC hdc = GetDC(0);
+
+    nNumButtons       = 0;
+    nNumCardRegions   = 0;
+    nNumDropZones     = 0;
+    nBackCardIdx      = 53;
+
+    ResizeWndCallback = 0;
+    hbmBackImage      = 0;
+    hdcBackImage      = 0;
+
+    srand((unsigned)GetTickCount());
+
+    //All colours (buttons, highlights, decks)
+    //are calculated off this single base colour
+    crBackgnd = PALETTERGB(0,80,0);//PALETTERGB(0,64,100);
+
+    // If uCardBitmapRef was previously zero, then
+    // load the card bitmaps
+    if(1 == InterlockedIncrement(&uCardBitmapRef))
+    {
+        LoadCardBitmaps();
+
+        __hPalette  = CreateCardPalette();
+
+        __hdcPlaceHolder  = CreateCompatibleDC(hdc);
+    
+        __holdplacepal  = UseNicePalette(__hdcPlaceHolder, __hPalette);
+
+        __hbmPlaceHolder  = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);
+
+    }
+
+    ReleaseDC(0, hdc);
+
+    //register the window class if necessary
+    if(!fRegistered)
+    {
+        fRegistered = true;
+        RegisterCardWindow();
+    }
+
+}
+
+BOOL CardWindow::Create(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle, int x, int y, int width, int height)
+{
+    if(m_hWnd)
+        return FALSE;
+
+    //Create the window associated with this object
+    m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szCardName, 0, 
+        WS_CHILD | WS_VISIBLE,
+        0,0,100,100, 
+        hwndParent, 0, GetModuleHandle(0), this);
+
+    return TRUE;
+}
+
+BOOL CardWindow::Destroy()
+{
+    DestroyWindow(m_hWnd);
+    m_hWnd = 0;
+
+    return TRUE;
+}
+
+CardWindow::~CardWindow()
+{
+    if(m_hWnd)
+        DestroyWindow(m_hWnd);
+
+    DeleteAll();
+
+    if(0 == InterlockedDecrement(&uCardBitmapRef))
+    {
+        FreeCardBitmaps();
+
+        DeleteObject(__hbmPlaceHolder);
+        DeleteDC    (__hdcPlaceHolder);
+
+        RestorePalette(__hdcPlaceHolder, __holdplacepal);
+
+        if(__hPalette)
+            DeleteObject(__hPalette);
+    }
+}
+
+bool CardWindow::DeleteAll()
+{
+    int i;
+
+    for(i = 0; i < nNumCardRegions; i++)
+    {
+        delete Regions[i];
+    }
+
+    for(i = 0; i < nNumButtons; i++)
+    {
+        delete Buttons[i];
+    }
+
+    for(i = 0; i < nNumDropZones; i++)
+    {
+        delete dropzone[i];
+    }
+
+    nNumCardRegions = nNumButtons = nNumDropZones = 0;
+
+    return true;
+}
+
+void CardWindow::SetBackColor(COLORREF cr)
+{
+    crBackgnd = cr;
+    int i;
+    
+    //
+    // Create the exact palette we need to render the buttons/stacks
+    //
+    RestorePalette(__hdcPlaceHolder, __holdplacepal);
+
+    if(__hPalette)
+        DeleteObject(__hPalette);
+
+    __hPalette = CreateCardPalette();
+
+    //
+    // re-create the place-holder!
+    HDC hdc = GetDC(m_hWnd);
+
+    DeleteObject(__hbmPlaceHolder);
+
+    __holdplacepal = UseNicePalette(__hdcPlaceHolder, __hPalette);
+
+    __hbmPlaceHolder = CreateSinkBmp(hdc, __hdcPlaceHolder, crBackgnd, __cardwidth, __cardheight);
+    //SelectObject(__hdcPlaceHolder, __hbmPlaceHolder);
+
+    //reset all buttons to same colour
+    for(i = 0; i < nNumButtons; i++)
+    {
+        if(Buttons[i]->GetStyle() & CB_PUSHBUTTON)
+        {
+            Buttons[i]->SetBackColor(ColorScaleRGB(crBackgnd, RGB(255,255,255), 0.1));
+        }
+        else
+        {
+            Buttons[i]->SetBackColor(crBackgnd);
+        }
+    }
+
+    for(i = 0; i < nNumCardRegions; i++)
+    {
+        Regions[i]->SetBackColor(crBackgnd);
+    }
+
+
+    ReleaseDC(m_hWnd, hdc);
+}
+
+COLORREF CardWindow::GetBackColor()
+{
+    return crBackgnd;
+}
+
+CardButton* CardWindow::CardButtonFromPoint(int x, int y)
+{
+    CardButton *bptr = 0;
+
+    POINT pt;
+    pt.x = x;
+    pt.y = y;
+
+    //Search BACKWARDS...to reflect the implicit Z-order that
+    //the button creation provided
+    for(int i = nNumButtons - 1; i >= 0; i--)
+    {
+        bptr = Buttons[i];
+        if(PtInRect(&bptr->rect, pt) && bptr->fVisible)
+            return bptr;
+    }
+
+    return 0;    
+}
+
+CardRegion* CardWindow::CardRegionFromPoint(int x, int y)
+{
+    POINT pt;
+    pt.x = x;
+    pt.y = y;
+
+    //Search BACKWARDS...to reflect the implicit Z-order that
+    //the stack creation provided
+    for(int i = nNumCardRegions - 1; i >= 0; i--)
+    {
+        if(Regions[i]->IsPointInStack(x, y))
+            return Regions[i];
+    }
+
+    return 0;    
+}
+
+//
+//    Forward all window messages onto the appropriate
+//  class instance
+//
+LRESULT CALLBACK CardWindow::CardWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+    CardWindow *cw = (CardWindow *)GetWindowLong(hwnd, 0);
+    return cw->WndProc(hwnd, iMsg, wParam, lParam);
+}
+
+void CardWindow::Paint(HDC hdc)
+{
+    int i;
+    RECT rect;
+    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);
+}