'https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/23540-ownerdraw-button-regions-demo
'--------------------------------------------------------------------------------
' Universal Button - beauty of HRGN
' Origional Author: Pavel A. Simakov
' Origional Code: 
'https://www.codeguru.com/cpp/controls/buttonctrl/non-rectangularbuttons/article.php/c2085/Universal-Button--beauty-of-HRGN.htm
'
' MFC C++ to PowerBasic Conversion by Jules Marchildon. FEB.15th,2001
'https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/23540-ownerdraw-button-regions-demo
'
' Ported to Oxygenbasic
' No warrenty applies, use at your own risk...
'--------------------------------------------------------------------------------

$ filename "t.exe"

'uses rtl32
'uses rtl64

uses corewin


% WM_DRAWITEM=43
% RGN_DIFF=4
% RGN_COPY=5
% COLOR_BTNFACE=15
% COLOR_3DSHADOW=16
% COLOR_BTNTEXT=18
% COLOR_3DHILIGHT=20
% COLOR_3DDKSHADOW=21
% COLOR_3DLIGHT=22
% WM_CAPTURECHANGED=533
% ODS_SELECTED=1
% ODS_DISABLED=4
% RDW_ALLCHILDREN=128
% RDW_ERASE=4
% RDW_INVALIDATE=1
% RDW_NOFRAME=2048
% RDW_UPDATENOW=256
% RGN_OR=2
% SRCCOPY=0x00CC0020
% TA_BOTTOM=8
% TA_CENTER=6


type NEWTEXTMETRIC
    long tmHeight
    long tmAscent
    long tmDescent
    long tmInternalLeading
    long tmExternalLeading
    long tmAveCharWidth
    long tmMaxCharWidth
    long tmWeight
    long tmOverhang
    long tmDigitizedAspectX
    long tmDigitizedAspectY
    byte tmFirstChar
    byte tmLastChar
    byte tmDefaultChar
    byte tmBreakChar
    byte tmItalic
    byte tmUnderlined
    byte tmStruckOut
    byte tmPitchAndFamily
    byte tmCharSet
    DWORD ntmFlags
    UINT ntmSizeEM
    UINT ntmCellHeight
    UINT ntmAvgWidth
end type


type DRAWITEMSTRUCT  
    UINT CtlType 
    UINT CtlID 
    UINT itemID 
    UINT itemAction 
    UINT itemState 
    sys  hwndItem 
    sys  hDC 
    RECT rcItem 
    sys  itemData        'ulong_ptr
end type 

macro RGB(r,g,b) {r+(g<<8)+(b<<16)}
macro MakeLong(lo,hi) { ( (lo) or ( (hi)<<16 ) ) }

% bTrue=1
'macro istrue(a)  { a != 0 }     '=0 -> false, <>0 -> true
'macro isfalse(a) { a == 0 }     '=0 -> true,  <>0 -> false
% istrue
% isfalse not

'---
% IDBTN1     = 1001    ' rectangular region
% IDBTN2     = 1002    ' elliptic region
% IDBTN3     = 1003    ' half ellipse
% IDBTN4     = 1004    ' half ellipse, disable button
% IDBTN5     = 1005    ' region from text "$"
% IDBTN6     = 1006    ' region from text "@"
% IDBTN7     = 1007    ' rectangle, "Save", overlapped
% IDBTN8     = 1008    ' corner, overlapped by IDBTN7
% IDBTN9     = 1009    ' simple Polyline region, arrow
% IDBTN10    = 1010    ' complex region
% IDBTN11    = 1011    ' stretched ellipse
% IDBTN12    = 1012    ' merged buttons... "File"
% IDBTN13    = 1013    ' merged buttons... "Edit"
% IDBTN14    = 1014    ' merged buttons... "View"
% IDBTN15    = 1015    ' merged buttons... "Insert"
% IDBTN16    = 1016    ' merged buttons... "Tools"
% IDBTN17    = 1017    ' merged buttons... "Help"
% IDBTN18    = 1018    ' merged buttons... "Exit"
% NUMBTN     = 18      ' number of buttons created


indexbase 0

'---
sys ghInst
sys ghMain
sys glpButtonProc
sys ghButton[NUMBTN]


'--- temp
' there are some variables that need intializing before we create
' the instance data for the button control...
sys   m_hRgn                'origional C++ button members
int   m_nColor              '           "
int   m_sColor              '           "
int   m_hColor              '           "
int   m_dColor              '           "
POINT m_CenterPoint         '           "
int   m_nBorder             '           "

 '---Private Button data per instance
type tagCTLDATA
int  nColor            'background color for button state: normal
int  sColor            'background color for button state: selected
int  hColor            'background color for button state: hover
int  dColor            'background color for button state: disabled
int  nBorder           'width of the border in pixels for 3D highlight
long lfEscapement      'orientation of the caption (in 1/10 degree as in LOGFONT)
sys  pNormal           'bitmap handle, button image: normal   state
sys  pSelected         'bitmap handle, button image: selected state
sys  pHover            'bitmap handle, button image: hover    state
sys  pDisabled         'bitmap handle, button image: disabled state
sys  hRgn              'region in screen coordinates
int  bHover            'indicates if mouse is over the button
int  bCapture          'indicates that mouse is captured in the buton
int  bMouseDown        'indicated that mouse is pressed down
int  bNeedBitmaps      'flag idicates that state bitmaps must be rebuild
POINT CenterPoint      'button caption will be centered around this point
sys  hButton           'button handle
int  idButton          'button ID
end type


#lookahead


'-----------------------------------------------------------------------------
' Create instance data for control
'-----------------------------------------------------------------------------
function CtlDataCreate(sys hCtl) as sys

    tagCTLDATA *ptCtlData  'Note: Pointer!

    'Reserve some new memory...
    sys pData=getmemory sizeof(tagCTLDATA)
    &ptCtlData=pData

    if istrue &ptCtlData then
     
      'load the default data...
      if istrue m_nColor then
         ptCtlData.nColor      = m_nColor           'pre
         m_nColor = 0
      else
         ptCtlData.nColor      = GetSysColor(COLOR_BTNFACE)
      end if
      if istrue m_sColor then
         ptCtlData.sColor      = m_sColor           'pre
         m_sColor = 0
      else
         ptCtlData.sColor      = GetSysColor(COLOR_BTNFACE)
      end if
      if istrue m_hColor then
         ptCtlData.hColor      = m_hColor           'pre
         m_hColor = 0
      else
         ptCtlData.hColor      = GetSysColor(COLOR_BTNFACE)
      end if
      if istrue m_dColor then
         ptCtlData.dColor      = m_dColor           'pre
         m_dColor = 0
      else
         ptCtlData.dColor      = GetSysColor(COLOR_BTNFACE)
      end if
      if istrue m_nBorder then
         ptCtlData.nBorder     = m_nBorder          'pre
         m_nBorder = 0
      else
        ptCtlData.nBorder     = 1
      end if
      ptCtlData.lfEscapement    = 0
      ptCtlData.pNormal         = null
      ptCtlData.pSelected       = null
      ptCtlData.pHover          = null
      ptCtlData.pDisabled       = null
      ptCtlData.hRgn            = m_hRgn             'pre
      ptCtlData.bHover          = false
      ptCtlData.bCapture        = false
      ptCtlData.bMouseDown      = false
      ptCtlData.bNeedBitmaps    = bTrue
      ptCtlData.CenterPoint.x   = m_CenterPoint.x    'pre
      ptCtlData.CenterPoint.y   = m_CenterPoint.y    'pre
      ptCtlData.hButton         = 0
      ptCtlData.idButton        = 0

      'NOTE:
      'There is no need to free memory that the system failed to allocate.

      'save pointer to the controls private UDT data
      SetProp(hCtl,"ptCTLDATA",  &ptCtlData)
      return &ptCtlData

    else
      return false
    end if
end function


'-----------------------------------------------------------------------------
' Free the instance data
'-----------------------------------------------------------------------------
sub CtlDataDelete(sys hCtl)

    tagCTLDATA *ptCD  'PTR

    'get the instance data for this control
    &ptCD = GetProp(hCtl,"ptCTLDATA")
    
    'free the memory...
    if istrue &ptCD then freememory(&ptCD)

    'free the instance data pointer property
    RemoveProp(hCtl,"ptCTLDATA")
 end sub


'------------------------------------------------------------------------------
' HitTest() -determines if point is inside the button region
'
'------------------------------------------------------------------------------
function HitTest(sys hWnd, POINT *pt) as sys

    sys  hRgn
    RECT rgnRect
    sys  lresult

    'create handle to a window region.
    hRgn = CreateRectRgn(0, 0, 0, 0)

    'copy this window region into it
    GetWindowRgn(hWnd,hRgn)

    'get the bounding rect of this region
    GetRgnBox(hRgn, &rgnRect)

    'First check if point is in region bounding rect.
    'Then check if point is in the region in addition
    'to being in the bounding rect.
    lresult = PtInRect(&rgnRect, pt.x, pt.y) AND PtInRegion(hRgn, pt.x, pt.y)

    'Clean up and exit.
    DeleteObject(hRgn)
 
    return lresult
end function

'------------------------------------------------------------------------------
' CheckHover() -is mouse hover inside region, display Hover bmp
'
'------------------------------------------------------------------------------
sub CheckHover(POINT *pt, tagCTLDATA *ptCD)

    uint RFLAG = RDW_INVALIDATE or %RDW_ERASE or RDW_UPDATENOW or RDW_ALLCHILDREN

    if HitTest(ptCD.hButton,pt)= bTrue then    
       if ptCD.bCapture = false then
         SetCapture(ptCD.hButton)
         ptCD.bCapture = bTrue
       end if
       if ptCD.bHover = false then
         ptCD.bHover = bTrue
         RedrawWindow(ptCD.hButton,  null, null, RFLAG)
       end if
     else
       if ptCD.bCapture = bTrue then       
         ReleaseCapture()
         ptCD.bCapture = false
       end if
 
       ptCD.bHover = false
       RedrawWindow(ptCD.hButton,  null, null, RFLAG)
    end if
end sub

'-------------------------------------------------------------------------
' Button SubClassed procedure
'
'-------------------------------------------------------------------------
function ButtonProc(sys hWnd, uint wMsg, sys wParam, lParam) as sys callback

   POINT pt
   tagCTLDATA *ptCD  'PTR

   'get the instance data
   &ptCD = GetProp(hWnd,"ptCTLDATA")

   select case wMsg

     case WM_LBUTTONDBLCLK
        'forward this for rapid button clicking...
        SendMessage(hWnd,WM_LBUTTONDOWN,wParam,lParam)
        return 0

     case WM_ERASEBKGND
        return 1

     case WM_MOUSEMOVE     
        pt.x = loword(lParam)
        pt.y = hiword(lParam)
        if isfalse ptCD.bMouseDown then               
          CheckHover( pt, ptCD)
        end if

     case WM_LBUTTONDOWN     
       'record that mouse is down
        ptCD.bMouseDown = bTrue
        if isfalse ptCD.bCapture then
           SetCapture(hWnd)
           ptCD.bCapture = bTrue
        end if

     case WM_LBUTTONUP
         'record that mouse is released, this allows BN_CLICKED to fire!
        CallWindowProc(glpButtonProc, hWnd, wMsg, wParam, lParam)
        pt.x = loword(lParam)
        pt.y = hiword(lParam)
        ptCD.bMouseDown = false
        if istrue ptCD.bCapture then
           ReleaseCapture()
           ptCD.bCapture = false
        end if
        CheckHover(pt, ptCD)

    case WM_CAPTURECHANGED :  '<ToDo: add SafeCaptureExit()>

     'case WM_DESTROY   '<-- we will let the parent clean up for us...

   end select
   
   return CallWindowProc(glpButtonProc, hWnd, wMsg, wParam, lParam)
end function



'==============================================================================
' Main function
'
'-------------------------------------------------------------------------------
  dim lpszCmdLine as asciiz ptr, hCurInstance as sys
  @lpszCmdLine=GetCommandLine
  hCurInstance=GetModuleHandle 0


sub WinMain()

    string szAppName
    MSG tMsg
    sys lhWnd
    WNDCLASSEX twndClass
    
    ghInst                  = hCurInstance
    szAppName               = "ODBTNHRGNS"

    twndClass.cbSize        = sizeof(twndClass)
    twndClass.style         = CS_HREDRAW or CS_VREDRAW
    twndClass.lpfnWndProc   = @WndMainProc
    twndClass.cbClsExtra    = 0
    twndclass.cbWndExtra    = 0
    twndClass.hInstance     = hCurInstance
    twndClass.hIcon         = LoadIcon(null,  IDI_APPLICATION)
    tWndClass.hIconsm       = LoadIcon(null,  IDI_APPLICATION)
    twndClass.hCursor       = LoadCursor (null,  IDC_ARROW)
    twndClass.hbrBackground = GetStockObject (LTGRAY_BRUSH)
    twndClass.lpszMenuName  = null
    twndClass.lpszClassName = strptr szAppName
    if RegisterClassEx(&tWndClass) = null then mbox "Error: Cannot RegisterClassEx Main Window"
    
    lhWnd = CreateWindowEX(0,
                           szAppName,
                           "OwnerDraw Button with Regions:",
                           WS_OVERLAPPEDWINDOW,
                           300,
                           200,
                           400,
                           400,
                           null, null,
                           hCurInstance, null)
     if lhWnd = 0 then mbox "Error: Cannot create Main Window"
     
     ShowWindow(lhWnd, SW_SHOW)
     UpdateWindow(lhWnd)
     
     ghMain = lhWnd
     
     while GetMessage(&tMsg, null, 0, 0)
       if isfalse IsDialogMessage(lhWnd, &tMsg) then
         TranslateMessage(&tMsg)
         DispatchMessage(&tMsg)
       end if
    wend
    
end sub


'------------------------------------------------------------------------------
'
'
'------------------------------------------------------------------------------
function WndMainProc (sys hWnd, uint wMsg, sys wParam,  lParam) as sys callback

    tagCTLDATA *ptCD
    DRAWITEMSTRUCT *ptDrawItem 
   
    select case(wMsg)
       case WM_CREATE
          'Create the Owner-Draw/Regions button Demo...
           CreateButtonRegionDemo(hWnd)
           return 0

       case WM_COMMAND
          select case loword(wParam)
             case IDBTN1 :if hiword(wParam) = BN_CLICKED then mbox "Button 1"
             case IDBTN2
             case IDBTN3
             case IDBTN4
             case IDBTN5
             case IDBTN6
             case IDBTN7
             case IDBTN8
             case IDBTN9
             case IDBTN10
             case IDBTN11
             case IDBTN12
             case IDBTN13
             case IDBTN14
             case IDBTN15
             case IDBTN16
             case IDBTN17
             case IDBTN18 : if hiword(wParam) = BN_CLICKED then SendMessage(hWnd, WM_CLOSE, 0,0)                   
          end select

       case WM_DRAWITEM           
          'get the pointer to the item-drawing info
           &ptDrawItem=lParam
              
           'get a pointer to the controls instance data
           &ptCD = GetProp(GetDlgItem(hWnd,wParam),"ptCTLDATA")

           RECT *rc
           'GetClientRect(GetDlgItem(hWnd,wParam),&rc)              
           &rc = &ptDrawItem.rcItem

           'prepare bitmaps if they need to be prepared
           if istrue ptCD.bNeedBitmaps  then
              PrepareStateBitmaps(ptDrawItem.hDC, rc, ptCD)
           end if
           
           'draw the button to the screen
           DrawButton(GetDlgItem(hWnd,wParam), ptDrawItem.hDC, rc, ptDrawItem.itemState, ptCD)
           return 0

       case WM_CLOSE
           DestroyWindow(hWnd)
 
             
       case WM_DESTROY
           'Clean up buttons demo...
           int i 
           for i = 0 TO NUMBTN -1
              if istrue ghButton[i] then
                'get the controls instance data...
                 &ptCD = GetProp(ghButton(i),"ptCTLDATA")
                 
                'Delete all bitmap objects...
                 DeleteObject(ptCD.pNormal)
                 DeleteObject(ptCD.pSelected)
                 DeleteObject(ptCD.pHover)
                 DeleteObject(ptCD.pDisabled)
                 DeleteObject(ptCD.hRgn)
                 
                'Free instance data memory...
                 CtlDataDelete(ghButton[i])
                 
                 'UnSubclass the buttons...
                 if istrue glpButtonProc then
                    SetWindowLongPtr(ghButton(i), GWL_WNDPROC,glpButtonProc)
                 end if
              end if
           next i
           PostQuitMessage(0)
           return 0

    end select
    return DefWindowProc(hWnd, wMsg, wParam, lParam)
end function

'------------------------------------------------------------------------------
' Create the Owner-Draw push buttons using specified Region types
'
'------------------------------------------------------------------------------
sub CreateButtonRegionDemo(sys hParent)
     '----IDBTN1  ' rectangular region
    sys r           'region
    POINT pt
    int clr
    
    r    = CreateRectRgn(0,0,63,31)
    pt.x = 15
    pt.y = 15
    clr  = RGB(255,255,0)  'Hover state Color
    m_nBorder = 1

    ghButton(0) = InitPreCreateTheButton("Btn 1",                 ' caption
                                         WS_CHILD or WS_VISIBLE,  ' style
                                         pt,                      ' top/left corner
                                         r,                       ' region
                                         hParent,                 ' parent hWnd
                                         IDBTN1,                  ' ID
                                         clr)                     ' color

      DeleteObject(r)
    ':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    '----IDBTN2  ' elliptic region
    int nclr   
    int sclr   
    int hclr   
    int dclr   
    int BORDER 

    r    = CreateEllipticRgn(0,0,63,31)
    pt.x = 95
    pt.y = 15
    nclr = GetSysColor(COLOR_BTNFACE)  'normal state
    sclr = RGB(0,255,0)                'selected state
    hclr = RGB(0,255,0)                'hover state
    dclr = nclr                        'disabled state
    BORDER = 2

    ghButton(1) = Init2PreCreateTheButton("Btn 2",                  ' caption
                                          WS_CHILD or WS_VISIBLE,   ' style
                                          pt,                       ' top/left corner
                                          r,                        ' region
                                          hParent,                  ' parent hWnd
                                          IDBTN2,                   ' ID
                                          BORDER,                   ' border width
                                          nclr,                     ' normal color
                                          sclr,                     ' selected color
                                          hclr,                     ' hover color
                                          dclr )                    ' disabled color

     DeleteObject(r)
    '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    '----IDBTN3  ' half ellipse, left and right buttons splitting ellipse in half
    sys rgnR
    sys rgnE

    rgnR = CreateRectRgn(0,0,127,31)
    rgnE = CreateEllipticRgn(0,0,127,31)
    OffsetRgn(rgnR, 63, 0)
    CombineRgn(rgnE,rgnE,rgnR, RGN_DIFF)

    pt.x = 175
    pt.y = 15
    nclr = GetSysColor(COLOR_BTNFACE)  'normal state
    sclr = RGB(156,175,194)            'selected state
    hclr = RGB(237,175,15)             'hover state
    dclr = nclr                        'disabled state
    BORDER = 2

    ghButton(2) = Init2PreCreateTheButton("Btn 3",                ' caption
                                          WS_CHILD or WS_VISIBLE, ' style
                                          pt,                     ' top/left corner
                                          rgnE,                   ' region
                                          hParent,                ' parent hWnd
                                          IDBTN3,                 ' ID
                                          BORDER,                 ' border width
                                          nclr,                   ' normal color
                                          sclr,                   ' selected color
                                          hclr,                   ' hover color
                                          dclr )                  ' disabled color

    '----IDBTN4 continued...  ' half ellipse, disabled button

    rgnR = CreateRectRgn(0,0,127,31)
    rgnE = CreateEllipticRgn(0,0,127,31)
    OffsetRgn(rgnR,-63,0)
    CombineRgn(rgnE,rgnE,rgnR,RGN_DIFF)

    pt.x = 175+64
    pt.y = 15

    ghButton(3) = Init2PreCreateTheButton("Btn 4  ",                ' caption
                             WS_DISABLED or WS_CHILD or WS_VISIBLE, ' style
                                          pt,                       ' top/left corner
                                          rgnE,                     ' region
                                          hParent,                  ' parent hWnd
                                          IDBTN4,                   ' ID
                                          BORDER,                   ' border width
                                          nclr,                     ' normal color
                                          sclr,                     ' selected color
                                          hclr,                     ' hover color
                                          dclr )                    ' disabled color

     DeleteObject(rgnE)
     DeleteObject(rgnR)
    ':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    '----IDBTN5  ' region from text "$"
    sys hDC
    LOGFONT lf
    sys rgnC
    sys hFont
    sys hOldFont
    int nOldMode

    hDC = CreateCompatibleDC(GetDC(ghMain))

    GetObject(GetStockObject(ANSI_VAR_FONT),sizeof(LOGFONT),&lf)
    lf.lfHeight = -100
    lf.lfWidth  =  70
    lf.lfWeight =  1000
    hFont = CreateFontIndirect (&lf)
    hOldFont = SelectObject(hDC, hFont)

    rgnC = CreateRectRgn(0,0,0,0)

    nOldMode = SetBkMode(hDC, TRANSPARENT)

    BeginPath(hDC)
    string szChar
    szChar = "$"
    TextOut(hDC, 0 , 0 , szChar, LEN(szChar))
    EndPath(hDC)

    rgnC = PathToRegion(hDC)
    SetBkMode(hDC, nOldMode)

    pt.x = 15
    pt.y = 63
    hclr =  RGB(255,255,0)

    ghButton(4) =  InitPreCreateTheButton("$",
                                         WS_CHILD or WS_VISIBLE,
                                         pt,
                                         rgnC,
                                         hParent,
                                         IDBTN5,
                                         hclr )

    '----IDBTN6  continued... ' region from text "@"

    'rgnC = CreateRectRgn(0,0,0,0)
    nOldMode = SetBkMode(hDC, TRANSPARENT)

    BeginPath(hDC)
   'LOCAL szChar AS ASCIIZ*2
    szChar = "@"
    TextOut(hDC, 0 , 0 , szChar, LEN(szChar))
    EndPath(hDC)

    rgnC = PathToRegion(hDC)
    SetBkMode(hDC, nOldMode)

    pt.x = 15+84
    pt.y = 63
    hclr =  RGB(255,0,255)

    ghButton(5) =  InitPreCreateTheButton("@",
                                          WS_CHILD or WS_VISIBLE,
                                          pt,
                                          rgnC,
                                          hParent,
                                          IDBTN6,
                                          hclr )

    '*note: hDC is still Valid, allow to flow down

     SelectObject(hDC, hOldFont)
     DeleteObject(hFont)
     DeleteObject(rgnC)
    ':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


    '----IDBTN7  ' rectangle, "Save", overlapped
    sys rgnCR

    BeginPath(hDC) '<--'*note, hDC already created above
    MoveToEx(hDC, 0, 0,  null)
    LineTo(hDC, 64, 0)
    LineTo(hDC, 64, 16)
    LineTo(hDC, 48, 32)
    LineTo(hDC, 0, 32)
    LineTo(hDC, 0, 0)
    EndPath(hDC)
    rgnCR = CreateRectRgn(0, 0, 63, 63)
    rgnCR = PathToRegion(hDC)

    pt.x = 55 + 64 + 128
    pt.y = 63

    ghButton(6)= Init2PreCreateTheButton("Save  ",
                                WS_CHILD or WS_VISIBLE,
                                pt,
                                rgnCR,
                                hParent,
                                IDBTN7,
                                1,
                                RGB(254, 247, 211),
                                RGB(211, 247, 254),
                                RGB(211, 247, 254),
                                GetSysColor(COLOR_BTNFACE))

    '----IDBTN8  continued... ' corner, overlapped by IDBTN7

    BeginPath(hDC)
    MoveToEx(hDC, 64, 16, null)
    LineTo(hDC, 64, 32)
    LineTo(hDC, 48, 32)
    LineTo(hDC, 64, 16)
    EndPath(hDC)
    rgnCR = PathToRegion(hDC)

    pt.x =  55 + 64 + 128 + 48
    pt.y =  63 + 16

    ghButton(7) = Init2PreCreateTheButton("",
                                WS_CHILD or WS_VISIBLE,
                                pt,
                                rgnCR,
                                hParent,
                                IDBTN8,
                                1,
                                RGB(247, 211, 254),
                                RGB(211, 247, 254),
                                RGB(211, 247, 254),
                                GetSysColor(COLOR_BTNFACE))


    DeleteObject(rgnCR)
    ':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



    '----IDBTN9  ' simple Polyline region, arrow


    BeginPath(hDC) '*note: hDC is still Valid from above
    MoveToEx(hDC, 0, 32,  null)
    LineTo(hDC, 48, 32)
    LineTo(hDC, 48, 16)
    LineTo(hDC, 96, 48)
    LineTo(hDC, 48, 80)
    LineTo(hDC, 48, 64)
    LineTo(hDC, 0, 64)
    LineTo(hDC, 0, 32)
    EndPath(hDC)
    rgnCR = CreateRectRgn(0, 0, 63, 63)
    rgnCR = PathToRegion(hDC)

    pt.x = 32 + 64 + 96
    pt.y = 63 + 16 + 128

    ghButton(8) = Init2PreCreateTheButton("Btn 9",
                                    WS_CHILD or WS_VISIBLE,
                                    pt,
                                    rgnCR,
                                    hParent,
                                    IDBTN9,
                                    2,
                                    RGB(250, 207, 194),
                                    RGB(255, 0, 0),
                                    RGB(255, 0, 0),
                                    GetSysColor(COLOR_BTNFACE))

    DeleteObject(rgnCR)
    DeleteObject(hDC)
    ':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    '----IDBTN10 ' complex region

    hDC = CreateCompatibleDC(GetDC(ghMain))

    BeginPath(hDC)
    MoveToEx(hDC, 31, 15,  null)

    POINT cpt[7]                  'CPoint p[7]
    cpt(0).x = 5  : cpt(0).y = 0  'CPoint(5, 0)
    cpt(1).x = 0  : cpt(1).y = 55 'CPoint(0, 55)
    cpt(2).x = 0  : cpt(2).y = 28 'CPoint(0, 28)
    cpt(3).x = 31 : cpt(3).y = 64 'CPoint(31, 64)
    cpt(4).x = 59 : cpt(4).y = 55 'CPoint(59, 55)
    cpt(5).x = 59 : cpt(5).y = 0  'CPoint(59, 0)
    cpt(6).x = 31 : cpt(6).y = 15 'CPoint(31, 15)

    PolyBezier(hDC, cpt(0), 7)
    EndPath(hDC)

    rgnCR = CreateRectRgn(0, 0, 63, 63)
    rgnCR = PathToRegion(hDC)

    pt.x = 15
    pt.y = 63 + 16 + 64 + 64

    ghButton(9) = Init2PreCreateTheButton("Btn 10",
                                   WS_CHILD or WS_VISIBLE,
                                   pt,
                                   rgnCR,
                                   hParent,
                                   IDBTN10,
                                   2,
                                   RGB(151, 244, 219),
                                   RGB(211, 247, 254),
                                   RGB(211, 247, 254),
                                   GetSysColor(COLOR_BTNFACE))

    DeleteObject(rgnCR)
    DeleteObject(hDC)
    '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    '----IDBTN11 ' stretched ellipse
    sys rgn1
    sys rgn2

    rgnC = CreateRectRgn(16, 0, 80, 31)
    rgn1 = CreateEllipticRgn(0, 0, 32, 32)
    rgn2 = CreateEllipticRgn(64, 0, 96, 32)
    CombineRgn(rgnC, rgnC, rgn1, RGN_OR)
    CombineRgn(rgnC, rgnC, rgn2, RGN_OR)

    pt.x =  15 + 64
    pt.y =  63 + 32 + 64 + 64

    ghButton(10) = Init2PreCreateTheButton("Btn 11",
                                  WS_CHILD or WS_VISIBLE,
                                  pt,
                                  rgnC,
                                  hParent,
                                  IDBTN11,
                                  2,
                                  GetSysColor(COLOR_BTNFACE),
                                  RGB(211, 247, 254),
                                  RGB(211, 247, 254),
                                  GetSysColor(COLOR_BTNFACE))

    DeleteObject(rgnC)
    DeleteObject(rgn1)
    DeleteObject(rgn2)
    '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    '----IDBTN12 ' merged buttons... "File"
    sys hr1
    sys hr2
    sys hc

    hc = CreateRectRgn(8, 0, 55, 31)
    hr1 = CreateEllipticRgn(48, 8, 15 + 48, 15 + 8)
    CombineRgn(hc, hc, hr1, RGN_OR)

    pt.x = 16 : pt.y = 63 + 32 + 64 + 128
    ghButton(11) = Init2PreCreateTheButton("File", WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN12, 1, RGB(151, 219, 244), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))

    '----IDBTN13 ' merged buttons... "Edit"

    hr1 = CreateEllipticRgn(0, 8, 15, 15 + 8)
    CombineRgn(hc, hc, hr1, RGN_DIFF)

    pt.x = 16 + 48 : pt.y = 63 + 32 + 64 + 128
    ghButton(12) = Init2PreCreateTheButton("Edit", WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN13, 1, RGB(151, 219, 244), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))


    '----IDBTN14 ' merged buttons... "View"

    pt.x = 16 + 48 + 48 : pt.y = 63 + 32 + 64 + 128
    ghButton(13) = Init2PreCreateTheButton("View", WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN14, 1, RGB(151, 219, 244), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))

    '----IDBTN15 ' merged buttons... "Insert"

    pt.x = 16 + 48 + 48 + 48 : pt.y = 63 + 32 + 64 + 128
    ghButton(14) = Init2PreCreateTheButton("Insert",WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN15, 1, RGB(151, 219, 244), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))


    '----IDBTN16 ' merged buttons... "Tools"

    pt.x =  16 + 48 + 48 + 48 + 48 : pt.y = 63 + 32 + 64 + 128
    ghButton(15) = Init2PreCreateTheButton("Tools", WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN16, 1, RGB(151, 219, 244), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))


    '----IDBTN17 ' merged buttons... "Help"

    pt.x = 16 + 48 + 48 + 48 + 48 + 48 : pt.y = 63 + 32 + 64 + 128
    ghButton(16) = Init2PreCreateTheButton("Help",  WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN17, 1, RGB(151, 244, 219), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))

    '----IDBTN18 ' merged buttons... "Exit"

    hc = CreateRectRgn(8, 0, 63, 31)
    hr1 = CreateEllipticRgn(0, 8, 15, 15 + 8)
    CombineRgn(hc, hc, hr1, RGN_DIFF)

    pt.x = 16 + 48 + 48 + 48 + 48 + 48 + 48 : pt.y =  63 + 32 + 64 + 128
    ghButton(17) = Init2PreCreateTheButton("Exit",  WS_CHILD or WS_VISIBLE, pt, hc, hParent, IDBTN18, 1, RGB(244, 151, 219), RGB(211, 247, 254), RGB(211, 247, 254), GetSysColor(COLOR_BTNFACE))

    DeleteObject(hc)
    DeleteObject(hr1)
    '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

end sub


'-----------------------------------------------------------------------------
' Step One: <<Version 1>> Button region creation.
'
'-----------------------------------------------------------------------------
function InitPreCreateTheButton(string szCaption,      ' caption
                                dword Wstyle,          ' sytle                
                                point *pt,             ' top/left corner
                                sys hrgn,              ' region
                                sys hparent,           ' parent hWnd
                                int ID,                ' ID
                                int clr) as sys        ' color

    sys hButton
     
    m_sColor = RGB(255,250,120)  'selected state color
    m_hColor = clr               'Hover state color
     
    hbutton = PreCreateTheButton(szCaption,
                                 Wstyle,
                                 pt,
                                 hrgn,
                                 hparent,
                                 ID )
    if hbutton = 0 then mbox "Error: PreCreateTheButton failed"

    return hButton 'function = hButton     'return the handle
end function

'-----------------------------------------------------------------------------
' Step One: <<Version 2>> Button region creation.
' This is based on origional C++ code, <ToDo: optimize nested creates>
'-----------------------------------------------------------------------------
function Init2PreCreateTheButton(string szCaption,      ' caption
                                 dword Wstyle,          ' sytle
                                 POINT *pt,             ' top/left corner
                                 sys hrgn,              ' region
                                 sys hparent,           ' parent hWnd
                                 int ID,                ' ID
                                 int BORDER,            ' border width
                                 int nclr,              ' normal color
                                 int sclr,              ' selected color
                                 int hclr,              ' hover color
                                 int dclr) as sys       ' disabled color

    sys hButton

    'change default data...
    m_nBorder =  BORDER
    m_nColor  =  nclr
    m_sColor  =  sclr
    m_hColor  =  hclr
    m_dColor  =  dclr

    hbutton = PreCreateTheButton(szCaption,
                                 Wstyle,
                                 pt,
                                 hrgn,
                                 hparent,
                                 ID )
    if hbutton = 0 then mbox "Error Init2PrecreateTheButton: Cannot PreCreateTheButton "
    return hButton     'return the handle

end function

'-----------------------------------------------------------------------------
' Step Two: Button region creation.
'
'-----------------------------------------------------------------------------
function PreCreateTheButton(string szCaption,     ' caption
                            dword Wstyle,         ' sytle                
                            point *pt,            ' top/left corner
                            sys hRgn,             ' region
                            sys hparent,          ' parent hWnd
                            int ID) as sys        ' ID

    sys hButton
    RECT rc
    
    'store region in member variable
    DeleteObject(m_hRgn)
    m_hRgn = CreateRectRgn(0,0,31,31) 'not sure what effect 31,31 has ???
 
    if m_hRgn <> 0 then  CombineRgn(m_hRgn, hRgn ,0, RGN_COPY)

    'make sure that region bounding Rect is located in (0,0)
    GetRgnBox(m_hRgn, &rc)
    OffsetRgn(m_hRgn, -rc.Left, -rc.Top)
    GetRgnBox(m_hRgn, &rc)
    
    'update position of region center for caption output
    int w = rc.Right  - rc.Left
    int h = rc.Bottom - rc.Top
    m_CenterPoint.x = (rc.Left + w) \2
    m_CenterPoint.y = (rc.Top  + h) \2

    OffsetRect(&rc,pt.x,pt.y)

    hbutton = FinalCreateTheButton(szCaption,
                                   Wstyle,
                                   rc,
                                   hparent,
                                   ID )
    if hbutton = 0 then mbox "Error PreCreateTheButton: Cannot finalCreateTheButton"
    return hbutton   'return the handle
 end function

'-----------------------------------------------------------------------------
' Step Three: -Create the button, Subclass it,
'             -Create the instance data,
'             -and Return the new buttons handle.
'-----------------------------------------------------------------------------
function FinalCreateTheButton(string szCaption,   ' caption
                              dword Wstyle,       ' style                     
                              RECT *rc,           ' top/left corner
                              sys hparent,        ' parent hWnd
                              int ID) as sys      ' ID

    sys hButton
    dword dWstyle
   
    tagCTLDATA *ptCD  'PTR

    'default style...
    dWstyle = BS_OWNERDRAW or WS_TABSTOP or _
              BS_PUSHBUTTON or BS_NOTIFY 'or WS_DISABLED
    dwstyle = dWstyle or Wstyle

    'Create the owner-draw push button...
    hButton  =  CreateWindowEx(0,"BUTTON",
                               szCaption,
                               dWstyle,
                               rc.Left, rc.Top,
                               rc.Right, rc.Bottom,
                               hparent, ID,
                               ghInst,  null )
    if hButton = 0 then mbox "Error in FinalCreateTheButton: Cannot CreateWindowEx hbutton"

    'Subclass all the buttons to the same procedure...
    glpButtonProc = GetWindowLongPtr(hButton, GWL_WNDPROC)
 
    SetWindowLongPtr(hButton, GWL_WNDPROC, @ButtonProc)

    'assign new region to a window
    SetWindowRgn(hButton, m_hRgn, bTrue)

    'create this controls instance data...
    CtlDataCreate(hButton)

    'add the final updates to instance data
    &ptCD = GetProp(hButton,"ptCTLDATA")
    ptCD.hButton  = hButton
    ptCD.idbutton = ID

    return hButton  'return the handle
 end function


'-----------------------------------------------------------------------------
' PrepareStateBitmaps() -prepares bitmaps for button states
'
'-----------------------------------------------------------------------------
sub PrepareStateBitmaps(sys pDC, RECT *pRect, tagCTLDATA *ptCD)

    sys pMemDC

    'prepare memory DC
    pMemDC = CreateCompatibleDC(pDC)

    'prepare bitmaps for all button states and for the mask          
    PrepareNormalState(pDC, pMemDC, pRect, ptCD)     
    PrepareSelectedState(pDC, pMemDC,  pRect, ptCD)
    PrepareHoverState(pDC, pMemDC, pRect, ptCD)
    PrepareDisabledState(pDC, pMemDC, pRect, ptCD)

    'clean up
    DeleteDC(pMemDC)
    ptCD.bNeedBitmaps = false     
end sub

'-----------------------------------------------------------------------------
' PrepareNormalState() -prepare normal state button bitmap
'
'-----------------------------------------------------------------------------
sub PrepareNormalState(sys pDC, sys pMemDC, RECT *pRect, tagCTLDATA *ptCD)

    'prepare MYBS_NORMAL state bitmap
    if istrue ptCD.pNormal then DeleteObject(ptCD.pNormal)

    ptCD.pNormal = 0 'new CBitmap
    ptCD.pNormal = odPaintRgn(pDC,pMemDC, ptCD.pNormal, ptCD.nColor, pRect, bTrue, false, ptCD)
end sub

'-----------------------------------------------------------------------------
' PrepareSelectedState() -prepare selectedstate button bitmap
'
'-----------------------------------------------------------------------------
sub PrepareSelectedState(sys pDC, pMemDC, RECT *pRect, tagCTLDATA *ptCD)

    'prepare MYBS_SELECTED state bitmap
    if istrue ptCD.pSelected then DeleteObject(ptCD.pSelected)

    ptCD.pSelected = 0 'new CBitmap

    odPaintRgn(pDC,pMemDC,ptCD.pSelected,ptCD.sColor,pRect,bTrue,bTrue, ptCD)
end sub

'-----------------------------------------------------------------------------
' PrepareHoverState()   -prepare hover state button bitmap
'
'-----------------------------------------------------------------------------
sub PrepareHoverState(sys pDC, pMemDC, RECT *pRect, tagCTLDATA *ptCD )

    'prepare MYBS_HOVER state bitmap
    if istrue ptCD.pHover then DeleteObject(ptCD.pHover)

    ptCD.pHover = 0 'new CBitmap

    odPaintRgn(pDC,pMemDC, ptCD.pHover, ptCD.hColor,pRect,bTrue,false, ptCD)
end sub

'-----------------------------------------------------------------------------
' PrepareDisabledState() - prepare disabled state button bitmap
'
'-----------------------------------------------------------------------------
sub PrepareDisabledState(sys pDC, pMemDC, RECT *pRect, tagCTLDATA *ptCD)

    'prepare MYBS_DISABLED state bitmap
    if istrue ptCD.pDisabled then DeleteObject(ptCD.pDisabled)
    ptCD.pDisabled = 0 'new CBitmap

    odPaintRgn(pDC,pMemDC, ptCD.pDisabled, ptCD.dColor,pRect,false,false, ptCD)
end sub

'-----------------------------------------------------------------------------
' odPaintRgn() -paint button
' This was origionally named PainRgn(), but conflicts with API PaintRgn() so
' I renamed to odPaintRgn, od = Owner-Draw.
'-----------------------------------------------------------------------------
function odPaintRgn(sys pDC, pMemDC,
                    sys *pBitmap, int pcolor,                   'Note: pBitmap Pointer
                    RECT *pRect, int bEnabled,
                    int bSunken,tagCTLDATA *ptCD) as sys
                    
    sys hRgn
    sys hBrush
    sys pOldBitmap
    int pWidth
    int pHeight

    'create bitmap
    pWidth  = pRect.Right  - pRect.Left
    pHeight = pRect.Bottom - pRect.Top

    pBitmap    = CreateCompatibleBitmap(pDC, pWidth, pHeight)
    pOldBitmap = SelectObject(pMemDC,pBitmap)

    'prepare region
    hRgn = CreateRectRgn(0, 0, 0, 0)    
    GetWindowRgn(ptCD.hButton,hRgn)

    'fill rect with transparent color and fill rgn
    hBrush = CreateSolidBrush(pcolor)

    FillRect(pMemDC, &pRect, RGB(0, 0, 0))
    FillRgn(pMemDC, hRgn, hBrush)
    DeleteObject(hBrush)

    'draw 3D border and text
    DrawButtonCaption(pMemDC, pRect, bEnabled, bSunken, ptCD)

    FrameRgn3D(pMemDC, hRgn, bSunken, ptCD)

    'clean up
    DeleteObject(hRgn)
    SelectObject(pMemDC,pOldBitmap)
     
    return pBitmap
 end function

'-----------------------------------------------------------------------------
' DrawButtonCaption() -draws button caption
'
'-----------------------------------------------------------------------------
sub DrawButtonCaption(sys hDC, RECT *pRect, int bEnabled, bSunken, tagCTLDATA *ptCD)

    int nOldMode
    string stext
    POINT pt
    sys hFont
    sys hOldFont
    LOGFONT lf
    NEWTEXTMETRIC tm
    int nLen

    'select parent font
    nOldMode = SetBkMode(hDC, TRANSPARENT)

    nLen = GetWindowTextLength(ptCD.hButton)
    sText = SPACE(nLen + 1) 'create a buffer...
    GetWindowText(ptCD.hButton, strptr(sText), nLen + 1)

    GetObject(GetStockObject(ANSI_VAR_FONT),sizeof(LOGFONT),&lf)
    hFont = CreateFontIndirect (&lf)

    hOldFont = SelectObject(hDC, hFont)

    'determine point where to output text
    GetTextMetrics(hDC, &tm)

    pt.x = ptCD.CenterPoint.x
    pt.y = ptCD.CenterPoint.y + tm.tmHeight \ 2
    
    if bSunken = bTrue  then
       pt.x = pt.x + ptCD.nBorder
       pt.y = pt.y + ptCD.nBorder
    end if

    'draw button caption depending upon button state
    if bEnabled = bTrue then
       SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT))
       SetTextAlign(hDC, TA_CENTER or TA_BOTTOM)
       TextOut(hDC, pt.x, pt.y,  strptr(stext), nLen)
    else
       SetTextColor(hDC, GetSysColor(COLOR_3DHILIGHT))
       TextOut(hDC, pt.x + 1, pt.y + 1,  strptr(stext), nLen)
       SetTextColor(hDC, GetSysColor(COLOR_3DSHADOW))
       TextOut(hDC, pt.x, pt.y,  strptr(stext), nLen)
    end if
    SelectObject(hDC, hOldFont)
    DeleteObject(hFont)
    SetBkMode(hDC, nOldMode)     
end sub

'-----------------------------------------------------------------------------
'  FrameRgn3D() -frames region to show 3D shadows
'
'-----------------------------------------------------------------------------
sub FrameRgn3D(sys hDC, hRgn, int bSunken, tagCTLDATA *ptCD)
 
    'we need two different regions to keep base region and border region
    sys hBrush
    sys hBaseRgn

    hBaseRgn = CreateRectRgn(0, 0, 0, 0)

    'colors of inner and outer shadow for top-left and right-bottom corners
    int ltOuter
    int ltInner
    int rbOuter
    int rbInner

    'decide on color scheme
    if isfalse bSunken then                  '!bSunken = NOT(bSunken)
       ltOuter = GetSysColor(COLOR_3DLIGHT)
       ltInner = GetSysColor(COLOR_3DHILIGHT)
       rbOuter = GetSysColor(COLOR_3DDKSHADOW)
       rbInner = GetSysColor(COLOR_3DSHADOW)
    else
       rbInner = GetSysColor(COLOR_3DLIGHT)
       rbOuter = GetSysColor(COLOR_3DHILIGHT)
       ltInner = GetSysColor(COLOR_3DDKSHADOW)
       ltOuter = GetSysColor(COLOR_3DSHADOW)
    end if

    'offset highlight and shadow regions
    'substract them from the base region
    select case  ptCD.nBorder
         case 2        
            CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY)
            OffsetRgn(hBaseRgn, 2, 2)
            CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF)
            hBrush = CreateSolidBrush(ltInner)
            FillRgn(hDC, hBaseRgn, hBrush)
            DeleteObject(hBrush)
            CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY)
            OffsetRgn(hBaseRgn, -2, -2)
            CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF)
            hBrush = CreateSolidBrush(rbInner)
            FillRgn(hDC, hBaseRgn, hBrush)
            DeleteObject(hBrush)
            CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY)
            OffsetRgn(hBaseRgn, 1, 1)
            CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF)
            hBrush = CreateSolidBrush(ltOuter)
            FillRgn(hDC, hBaseRgn, hBrush)
            DeleteObject(hBrush)
            CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY)
            OffsetRgn(hBaseRgn, -1, -1)
            CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF)
            hBrush = CreateSolidBrush(rbOuter)
            FillRgn(hDC, hBaseRgn, hBrush)
            DeleteObject(hBrush)
 
         'default:
         case else       
            CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY)
            OffsetRgn(hBaseRgn, 1, 1)
            CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF)
            hBrush = CreateSolidBrush(ltInner)
            FillRgn(hDC, hBaseRgn, hBrush)
            DeleteObject(hBrush)
            CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY)
            OffsetRgn(hBaseRgn, -1, -1)
            CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF)
            hBrush = CreateSolidBrush(rbOuter)
            FillRgn(hDC, hBaseRgn, hBrush)
            DeleteObject(hBrush)

         end select

     'clean up regions
     DeleteObject(hBaseRgn)
end sub

'-----------------------------------------------------------------------------
' DrawButton() -draws button to the screen
' note: wstate =  ptDrawItem.itemState
'-----------------------------------------------------------------------------
sub DrawButton(sys hWnd, pDC, RECT *pRect, uint wstate, tagCTLDATA *ptCD)

    int pWidth
    int pHeight
    sys pOldBitmap
    sys pMemDC
    sys hRgn
   
    'create memory DC
    pMemDC = CreateCompatibleDC(pDC)    

    'get region
    hRgn = CreateRectRgn(0, 0, 0, 0)
    GetWindowRgn(hWnd,hRgn)

    'select bitmap to paint depending upon button state
    if (wstate and ODS_DISABLED)  then
       pOldBitmap = SelectObject(pMemDC, ptCD.pDisabled)     
    else
       if (wstate and ODS_SELECTED)   then
          pOldBitmap = SelectObject(pMemDC, ptCD.pSelected)
       else
          if ptCD.bHover = bTrue then
             pOldBitmap = SelectObject(pMemDC, ptCD.pHover)
          else
             pOldBitmap = SelectObject(pMemDC, ptCD.pNormal)
          end if
       end if
    end if

    'paint using region for clipping
    SelectClipRgn(pDC, hRgn)

    pWidth  = pRect.Right  - pRect.Left
    pHeight = pRect.Bottom - pRect.Top

    BitBlt(pDC,0,0,pWidth,pHeight,pMemDC,0,0,SRCCOPY)

    'remove a device-context's clipping region,
    SelectClipRgn(pDC, null)

    'clean up...
    ReleaseDC( ptCD.hButton,pMemDC)
    DeleteObject(hRgn)
    SelectObject(pMemDC,pOldBitmap)
    DeleteDC(pMemDC)
end sub

'--------------------------------------------------------

WinMain()

