Page 1 of 1

Ownerdrawn resizable window frames

Posted: Mon Feb 18, 2008 12:33 am
by netmaestro
* Updated for PB 5.31 *

Here is a small demonstration of how you can tap into #WM_NCCALCSIZE to give your window a custom caption height and frame thickness while maintaining the ability to resize on demand. Unfortunately, when you custom-draw a window frame you are stuck with doing your own systemmenu buttons as well, which adds a lot of hassle to the job. I've included a close button, but you can use the same logic and add minimize and max/restore to it too if desired. There is a GDI objects count displayed at 0,0 of the client area of the window, this serves two purposes: One, I want to keep an eye on leaks with all this GDI activity happening and Two, I want to display something at 0,0 to make sure the client area is being readjusted properly after resizes. The Status Bar is to keep an eye on the bottom and right of the client area. If everything looks to be showing where it ought to be, the calculations are coming out right. You can do a lot more than just use a basic pattern brush, like my demo is doing. Once you have your hands on that frame DC the sky's the limit. You can do really cool custom window frames of your own design. Anyway, on to the demo:

Code: Select all


;=================================================================== 
; Program:            Ownerdrawn Resizable Window Frame Demo 
; Author:             Lloyd Gallant (netmaestro) 
; Date:               August 28, 2007 
; Target OS:          Microsoft Windows All (I think) 
; Target Compiler:    PureBasic 4.xx and later 
; License:            Free, unrestricted, no warranty
;=================================================================== 

; Adjust these for different Caption height and frame thicknesses
Global gCaptionHeight   = 60
Global gFrameWidth      = 20
Global buttonsize       = 18
Global gCaptionTxtColor = #White

Structure NCCALCSIZE_PARAMS2
  rgrc.RECT[3]
  *lppos.WINDOWPOS
EndStructure

; read in button images for the 3 states 

UseJCALG1Packer()
*unpacked = AllocateMemory(3008)
UncompressMemory(?closebuttons, ?closebuttonsend-?closebuttons, *unpacked, MemorySize(*unpacked))
img0 = CatchImage(#PB_Any, *unpacked, 3008)
FreeMemory(*unpacked)

Global CB_Normal   = GrabImage(img0, #PB_Any,0,0,18,18) 
Global CB_Selected = GrabImage(img0, #PB_Any,18,0,18,18) 
Global CB_Pressed  = GrabImage(img0, #PB_Any,36,0,18,18) 

If buttonsize<>18
  ResizeImage(CB_Normal, buttonsize,buttonsize)
  ResizeImage(CB_Selected, buttonsize,buttonsize)
  ResizeImage(CB_Pressed, buttonsize,buttonsize)
EndIf

StartDrawing(ImageOutput(img0)) 
  Global gTranscolor = Point(0,0) 
StopDrawing() 
FreeImage(img0) 

Global gFrameTexture = CatchImage(#PB_Any, ?backbrush) 
Global hBrush = CreatePatternBrush_(ImageID(gFrameTexture))

Global gCloseButton_State = CB_Normal 

ProcedureDLL TransBlit(hdc, hBitmap, xStart, yStart, TransColor) 
  ; by netmaestro based on http://support.microsoft.com/kb/79212/EN-US/ 
  Define.POINT  ptSize 
  hdcTemp = CreateCompatibleDC_(hdc) 
  SelectObject_(hdcTemp, hBitmap) 
  GetObject_(hBitmap, SizeOf(BITMAP), bm.BITMAP) 
  ptSize\x = bm\bmWidth 
  ptSize\y = bm\bmHeight 
  DPtoLP_(hdcTemp, @ptSize, 1) 
  hdcBack   = CreateCompatibleDC_(hdc) 
  hdcObject = CreateCompatibleDC_(hdc) 
  hdcMem    = CreateCompatibleDC_(hdc) 
  hdcSave   = CreateCompatibleDC_(hdc) 
  bmAndBack   = CreateBitmap_(ptSize\x, ptSize\y, 1, 1, #Null) 
  bmAndObject = CreateBitmap_(ptSize\x, ptSize\y, 1, 1, #Null) 
  bmAndMem    = CreateCompatibleBitmap_(hdc, ptSize\x, ptSize\y) 
  bmSave      = CreateCompatibleBitmap_(hdc, ptSize\x, ptSize\y) 
  bmBackOld   = SelectObject_(hdcBack, bmAndBack) 
  bmObjectOld = SelectObject_(hdcObject, bmAndObject) 
  bmMemOld    = SelectObject_(hdcMem, bmAndMem) 
  bmSaveOld   = SelectObject_(hdcSave, bmSave) 
  SetMapMode_(hdcTemp, GetMapMode_(hdc)) 
  BitBlt_(hdcSave, 0, 0, ptSize\x, ptSize\y, hdcTemp, 0, 0, #SRCCOPY) 
  cColor = SetBkColor_(hdcTemp, TransColor) 
  BitBlt_(hdcObject, 0, 0, ptSize\x, ptSize\y, hdcTemp, 0, 0, #SRCCOPY) 
  SetBkColor_(hdcTemp, cColor) 
  BitBlt_(hdcBack, 0, 0, ptSize\x, ptSize\y, hdcObject, 0, 0, #NOTSRCCOPY) 
  BitBlt_(hdcMem, 0, 0, ptSize\x, ptSize\y, hdc, xStart, yStart, #SRCCOPY) 
  BitBlt_(hdcMem, 0, 0, ptSize\x, ptSize\y, hdcObject, 0, 0, #SRCAND) 
  BitBlt_(hdcTemp, 0, 0, ptSize\x, ptSize\y, hdcBack, 0, 0, #SRCAND) 
  BitBlt_(hdcMem, 0, 0, ptSize\x, ptSize\y, hdcTemp, 0, 0, #SRCPAINT) 
  BitBlt_(hdc, xStart, yStart, ptSize\x, ptSize\y, hdcMem, 0, 0, #SRCCOPY) 
  BitBlt_(hdcTemp, 0, 0, ptSize\x, ptSize\y, hdcSave, 0, 0, #SRCCOPY) 
  DeleteObject_(SelectObject_(hdcBack, bmBackOld)) 
  DeleteObject_(SelectObject_(hdcObject, bmObjectOld)) 
  DeleteObject_(SelectObject_(hdcMem, bmMemOld)) 
  DeleteObject_(SelectObject_(hdcSave, bmSaveOld)) 
  DeleteDC_(hdcMem) 
  DeleteDC_(hdcBack) 
  DeleteDC_(hdcObject) 
  DeleteDC_(hdcSave) 
  DeleteDC_(hdcTemp) 
EndProcedure 

Procedure WindowProc(hwnd, msg, wParam, lParam) 
    
  Static frameW 
  Static captionH
  Static buttonT

  oldproc = GetProp_(hwnd, "oldproc")
  result = oldproc

  Select msg 
    
    Case #WM_NCDESTROY
      RemoveProp_(hwnd, "oldproc")

    Case #WM_MOUSEMOVE 
      If gCloseButton_State <> CB_Normal 
        gCloseButton_State = CB_Normal 
        SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
      EndIf 
      
    Case #WM_NCLBUTTONDOWN 
      GetWindowRect_(hwnd, wr.RECT) 
      cp.POINT 
      cp\x = lparam & $FFFF - wr\left 
      cp\y = lparam >> 16 - wr\top 

      br.RECT 
      br\left = wr\right-wr\left - frameW-buttonsize
      br\right = br\left+buttonsize 
      br\top = buttonT 
      br\bottom = br\top + buttonsize 
      
      If PtInRect_(br, cp\x|(cp\y<<32)) 
        gCloseButton_State = CB_Pressed 
        SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
        result = 0 
      EndIf 
      
    Case #WM_NCLBUTTONUP 
      GetWindowRect_(hwnd, wr.RECT) 
      cp.POINT 
      cp\x = lparam & $FFFF - wr\left 
      cp\y = lparam >> 16 - wr\top 
            
      br.RECT 
      br\left = wr\right-wr\left - frameW-buttonsize
      br\right = br\left+buttonsize 
      br\top = buttonT 
      br\bottom = br\top + buttonsize 
      
      If PtInRect_(br, cp\x|(cp\y<<32)) 
        If gCloseButton_State = CB_Pressed 
          SendMessage_(hwnd, #WM_SYSCOMMAND, #SC_CLOSE, 0) 
        EndIf 
      Else 
        gCloseButton_State = CB_Normal 
        SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
        result = 0 
      EndIf 
      
    Case #WM_NCMOUSEMOVE 
      GetWindowRect_(hwnd, wr.RECT) 
      cp.POINT 
      cp\x = lparam & $FFFF - wr\left 
      cp\y = lparam >> 16 - wr\top 
      
      br.RECT 
      br\left = wr\right-wr\left - frameW-buttonsize 
      br\right = br\left+buttonsize 
      br\top = buttonT 
      br\bottom = br\top + buttonsize 
      
      If PtInRect_(br, cp\x|(cp\y<<32)) 
        If GetAsyncKeyState_(#VK_LBUTTON) & 32768 
          If gCloseButton_State = CB_Pressed 
            SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
          Else 
            If gCloseButton_State <> CB_Selected 
              gCloseButton_State = CB_Selected 
              SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
            EndIf 
          EndIf 
        Else 
          If gCloseButton_State <> CB_Selected 
            gCloseButton_State = CB_Selected 
            SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
          EndIf 
        EndIf 
      Else 
        If gCloseButton_State <> CB_Normal 
          gCloseButton_State = CB_Normal 
          SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
        EndIf 
      EndIf    
      result = 0 
          
     Case #WM_NCCALCSIZE

       *np.NCCALCSIZE_PARAMS2 = lparam
    
        With *np\rgrc[0]
          \left    = *np\lppos\x + gFrameWidth
          \top     = *np\lppos\y + gCaptionHeight
          \right   = *np\lppos\x + *np\lppos\cx - gFrameWidth
          \bottom  = *np\lppos\y + *np\lppos\cy - gFrameWidth
        EndWith     

       captionH = *np\rgrc[0]\top - *np\lppos\y 
       frameW   = *np\rgrc[0]\left - *np\lppos\x
       buttonT = (captionH - buttonsize)/2

     
     If wparam=0
       result=0
     Else
       result =  #WVR_VALIDRECTS | #WVR_REDRAW 
     EndIf
          
    Case #WM_NCPAINT, #WM_NCACTIVATE 
      
      GetWindowRect_(hwnd, wr.RECT)
      new_w = wr\right - wr\left 
      new_h = wr\bottom - wr\top 
      hdc = GetWindowDC_(hwnd) 
      hdctemp = CreateCompatibleDC_(hdc)
      hrgn = CreateRectRgn_(-1,-1,new_w+1, new_h+1) 
      hrgn2 = CreateRectRgn_(frameW,captionH,new_w-frameW,new_h-frameW) 
      CombineRgn_(hrgn, hrgn, hrgn2, #RGN_XOR) 
      SelectClipRgn_(hdc, hrgn) 
      imgtemp = CreateImage(#PB_Any, new_w+2,new_h+2, #PB_Image_DisplayFormat)
      hBitmap = ImageID(imgtemp)
      SelectObject_(hdctemp, hBitmap)
      SelectObject_(hdctemp, hBrush) 
      Rectangle_(hdctemp,-1,-1,new_w+1, new_h+1) 
      ; Window title
      wt$ = Space(100)
      GetWindowText_(hwnd, @wt$, 99)
      SetBkMode_(hdctemp, #TRANSPARENT)
      SetTextColor_(hdctemp, gCaptionTxtColor)
      TextOut_(hdctemp, frameW,captionH/2-7,wt$, Len(wt$))
      ; Buttons
      If IsImage(gCloseButton_State) 
        TransBlit(hdctemp, ImageID(gCloseButton_State), new_w - frameW-buttonsize, buttonT, gTranscolor) 
        DeleteDC_(buttondc) 
      EndIf 
      BitBlt_(hdc,0,0,new_w+1, new_h+1,hdctemp,0,0,#SRCCOPY)
      DeleteObject_(hBitmap)
      DeleteDC_(hdctemp)
      ReleaseDC_(hwnd, hdc) 
      DeleteObject_(hrgn) 
      DeleteObject_(hrgn2) 
      result = 0 

  EndSelect 
  
  If result = oldproc
    ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
  Else
    ProcedureReturn result
  EndIf
  
EndProcedure 

Procedure MonitorButtons(hwnd) 
  Repeat 
    GetWindowRect_(hwnd, @wr.RECT) 
    GetCursorPos_(@cp.POINT) 
    ; if the cursor is outside the window, the CloseButton 
    ; must show normal. All other cases are covered in the callback. 
    If Not PtInRect_(wr, cp\x|(cp\y<<32)) 
      If gCloseButton_State <> CB_Normal 
        gCloseButton_State = CB_Normal 
        SendMessage_(hwnd, #WM_NCPAINT, 0,0) 
      EndIf 
    EndIf 
    Delay(15) 
  ForEver 
EndProcedure 

Procedure cb(hwnd, msg, wparam, lparam)
  result = #PB_ProcessPureBasicEvents

  ProcedureReturn result
EndProcedure

OpenWindow(0,0,0,320,240,"Ownerdrawn Frame",#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
StickyWindow(0,1)
TextGadget(0,0,0,150,20,"")
SetGadgetColor(0,#PB_Gadget_BackColor, #White) 
SetWindowColor(0, #White)
SetProp_(WindowID(0), "oldproc", SetWindowLong_(WindowID(0), #GWL_WNDPROC, @WindowProc())) 
CreateStatusBar(0, WindowID(0))

; dry-fire the WM_NCCALCSIZE and WM_NCPAINT events:
SetWindowPos_(WindowID(0),0,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE|#SWP_NOZORDER|#SWP_FRAMECHANGED)

; a thread ensures no mistakes in resetting the CloseButton image to normal 
CreateThread(@MonitorButtons(), WindowID(0)) 

ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS,#False,GetCurrentProcessId_());

lastgdicount = 0
Repeat 
  ev = WaitWindowEvent()
  gdicount = GetGuiResources_(ProcessHandle, 0) ; 0 = #GR_GDIOBJECTS
  If gdicount <> lastgdicount
    lastgdicount = gdicount
    SetGadgetText(0,"GDI Object Count: "+Str(gdicount))
  EndIf
Until ev=#PB_Event_CloseWindow 

DeleteObject_(hBrush)

DataSection 
  backbrush:         
  IncludeBinary #PB_Compiler_Home+"Examples\Sources\Data\Background.bmp"
  closebuttons:      
  Data.b $4A,$43,$C0,$0B,$00,$00,$72,$EC,$2F,$DE,$BC,$A9,$D0,$20,$69,$14,$59,$08,$18,$CA
  Data.b $08,$B0,$01,$25,$89,$22,$3C,$06,$18,$23,$98,$C4,$40,$50,$FF,$14,$60,$12,$79,$E2
  Data.b $7C,$80,$D2,$15,$A3,$B1,$CC,$74,$4E,$A2,$C0,$48,$30,$0D,$FD,$EF,$04,$6E,$65,$03
  Data.b $D0,$8C,$F4,$5C,$2E,$D4,$60,$15,$F5,$96,$27,$65,$63,$9D,$36,$AD,$9E,$F5,$57,$29
  Data.b $C7,$AD,$00,$2B,$53,$E3,$81,$15,$5D,$18,$14,$42,$1B,$50,$01,$C0,$58,$27,$67,$FB
  Data.b $04,$7A,$6A,$EC,$A1,$59,$4F,$42,$1B,$E0,$D0,$09,$84,$60,$6C,$B2,$63,$B5,$A3,$4F
  Data.b $99,$77,$19,$A0,$69,$F2,$27,$50,$45,$4E,$8A,$8D,$D5,$42,$B6,$D3,$F3,$ED,$77,$DC
  Data.b $19,$E8,$45,$7D,$6E,$4A,$A0,$3F,$E7,$36,$97,$60,$FE,$1F,$42,$21,$B4,$81,$91,$5A
  Data.b $2D,$74,$5B,$A1,$23,$A7,$55,$CA,$ED,$A4,$C7,$CA,$15,$B9,$60,$59,$BB,$2E,$09,$85
  Data.b $40,$3D,$CF,$9B,$B5,$D0,$27,$FA,$92,$B6,$E8,$4E,$A5,$32,$E2,$1D,$6C,$55,$66,$1D
  Data.b $4F,$96,$59,$AD,$E6,$CD,$E9,$06,$AC,$FC,$82,$F8,$B2,$58,$B4,$65,$2D,$74,$A7,$E2
  Data.b $64,$2E,$3F,$ED,$CB,$D6,$4C,$41,$1D,$F9,$93,$A6,$EC,$F6,$C0,$46,$53,$92,$10,$DA
  Data.b $C0,$6B,$B3,$16,$3A,$A1,$42,$6A,$CC,$90,$D7,$D5,$3E,$91,$52,$B3,$D2,$87,$CE,$2B
  Data.b $97,$E4,$95,$F9,$D3,$AA,$24,$D0,$61,$1A,$4C,$EB,$D7,$E7,$0A,$7A,$80,$07,$A1,$10
  Data.b $DA,$A0,$79,$94,$16,$3C,$44,$7F,$AE,$EE,$DE,$AC,$56,$E1,$C5,$87,$B5,$5A,$EA,$79
  Data.b $B4,$5B,$3E,$45,$0F,$56,$A7,$9D,$50,$BA,$02,$6F,$C0,$D2,$97,$C0,$4E,$AD,$D6,$42
  Data.b $27,$9C,$13,$E1,$43,$7D,$59,$B0,$71,$A5,$40,$23,$FE,$BF,$99,$19,$8B,$3E,$71,$4C
  Data.b $91,$3D,$74,$67,$F6,$7F,$7C,$C0,$34,$5F,$0D,$AA,$A0,$07,$A1,$13,$0A,$A1,$F1,$A5
  Data.b $44,$6B,$56,$1C,$90,$DA,$8E,$B5,$AB,$89,$D2,$A5,$5E,$6D,$BD,$BD,$ED,$DB,$B9,$CE
  Data.b $A7,$5E,$AD,$5F,$35,$59,$80,$0D,$D8,$F4,$B4,$41,$15,$F4,$2D,$74,$42,$21,$C7,$48
  Data.b $CD,$68,$DD,$AA,$7E,$6D,$B2,$55,$D1,$9F,$EF,$DB,$F6,$FB,$FA,$B1,$53,$CF,$B5,$3D
  Data.b $5B,$AE,$80,$B9,$77,$EB,$54,$41,$0F,$D8,$27,$14,$42,$1B,$2A,$A9,$D5,$42,$79,$8D
  Data.b $23,$15,$99,$EF,$7F,$C8,$A1,$BC,$97,$12,$C7,$CD,$52,$4E,$01,$53,$D0,$87,$32,$93
  Data.b $68,$97,$A0,$07,$78,$C0,$0A,$A1,$0D,$AA,$43,$6B,$A1,$13,$D6,$22,$B5,$A4,$5F,$72
  Data.b $07,$4B,$B8,$F0,$C4,$30,$09,$00,$33,$8A,$69,$F6,$25,$D9,$AE,$60,$AB,$B3,$81,$12
  Data.b $70,$00,$68,$83,$2A,$E8,$52,$EB,$84,$42,$1A,$0A,$F1,$24,$86,$55,$AF,$16,$CD,$9D
  Data.b $F8,$E5,$9C,$A3,$3C,$F4,$FF,$EE,$DA,$D0,$85,$DF,$D6,$2B,$00,$F1,$DD,$7E,$D0,$03
  Data.b $25,$D0,$85,$D0,$06,$55,$6A,$B5,$D0,$09,$E3,$47,$83,$4A,$EF,$FF,$C4,$1C,$52,$94
  Data.b $22,$19,$FB,$3E,$8E,$5A,$EF,$BD,$10,$98,$1F,$7E,$4B,$19,$00,$C4,$70,$FD,$E8,$81
  Data.b $12,$70,$42,$68,$83,$02,$B6,$5A,$E8,$84,$C4,$4E,$7D,$B8,$DD,$6B,$58,$D6,$96,$F2
  Data.b $95,$72,$61,$7E,$27,$5B,$F8,$70,$BC,$32,$EC,$99,$80,$9C,$AB,$D7,$FA,$1F,$09,$34
  Data.b $80,$85,$41,$15,$F4,$40,$74,$42,$21,$B4,$D6,$5C,$5B,$2D,$31,$BC,$28,$50,$AE,$58
  Data.b $F9,$E8,$AF,$D7,$2C,$65,$39,$C6,$D9,$C9,$EC,$C6,$01,$A3,$B8,$60,$C1,$34,$D3,$34
  Data.b $00,$FD,$1B,$30,$F7,$50,$42,$27,$14,$42,$87,$B3,$47,$D5,$6D,$71,$A3,$40,$BF,$ED
  Data.b $2F,$D8,$E2,$B8,$FC,$09,$E6,$39,$34,$3F,$E5,$C1,$93,$43,$C2,$6F,$EF,$84,$FF,$7F
  Data.b $D5,$52,$80,$12,$68,$00,$68,$83,$2A,$28,$5A,$E8,$84,$42,$44,$A2,$BC,$B6,$CD,$2E
  Data.b $91,$D4,$CA,$6E,$97,$90,$B4,$6A,$BB,$4B,$36,$13,$A6,$F9,$2F,$49,$EE,$A7,$0F,$B5
  Data.b $06,$98,$84,$36,$A0,$02,$AD,$85,$4E,$28,$E5,$18,$A9,$19,$BC,$67,$EB,$DF,$CF,$17
  Data.b $AD,$FD,$FF,$03,$B3,$C5,$F4,$8B,$75,$6A,$D4,$1A,$80,$3F,$42,$68,$03,$2B,$7D,$5A
  Data.b $E8,$84,$A4,$56,$F4,$27,$B6,$3F,$8C,$46,$76,$4B,$09,$DC,$3A,$CC,$A9,$01,$1F,$EB
  Data.b $84,$84,$D7,$86,$E0,$CA,$00,$FD,$A5,$2F,$C0,$03,$DA,$D0,$85,$D0,$06,$55,$6A,$B5
  Data.b $D0,$09,$4E,$76,$2C,$45,$DE,$CD,$96,$E5,$D9,$F0,$68,$27,$36,$ED,$77,$CA,$7A,$AF
  Data.b $A7,$A6,$FE,$DB,$46,$7D,$07,$4A,$E0,$00,$A1,$0D,$AA,$A0,$6B,$A1,$13,$0A,$B8,$C1
  Data.b $0C,$46,$5F,$EF,$D9,$E1,$F5,$F7,$45,$7B,$06,$28,$C0,$69,$B6,$76,$BF,$5F,$9C,$F3
  Data.b $27,$8C,$BD,$4F,$C3,$96,$40,$09,$60,$63,$B3,$41,$15,$F4,$FF,$BF,$69,$F3,$16,$F6
  Data.b $73,$02,$28,$71,$48,$AD,$BF,$69,$19,$00,$9A,$01,$AD,$7E,$D0,$C0,$80,$01,$3D,$FF
  Data.b $0B,$66,$F4,$00,$67,$63,$21,$B8,$41,$15,$5A,$2D,$74,$02,$48,$A1,$E2,$90,$B6,$6C
  Data.b $EB,$9F,$3E,$2D,$80,$76,$05,$BF,$76,$12,$58,$8D,$03,$A0,$93,$1A,$30,$94,$50,$05
  Data.b $3D,$40,$9D,$50,$08,$6D,$31,$3B,$55,$0B,$0F,$66,$8B,$9B,$FC,$05,$53,$FE,$66,$A1
  Data.b $37,$B5,$B9,$59,$FE,$BD,$40,$05,$3D,$40,$C7,$7E,$C1,$78,$9F,$13,$FA,$43,$19,$6A
  Data.b $B5,$F0,$4B,$DA,$E6,$A9,$AE,$ED,$D2,$E1,$29,$8B,$01,$14,$EF,$86,$E5,$4F,$00,$65
  Data.b $63,$F7,$E1,$6C,$15,$F4,$68,$C1,$13,$0E,$89,$D4,$DC,$A3,$F1,$90,$50,$AE,$09,$65
  Data.b $AD,$5A,$E3,$38,$00,$DB,$F7,$DE,$1D,$43,$9A,$75,$32,$E8,$81,$06,$D0,$ED,$AB,$82
  Data.b $1E,$28,$16,$3A,$01,$0F,$35,$7B,$54,$87,$52,$C4,$D9,$A1,$FC,$D6,$BF,$D9,$D4,$FE
  Data.b $0C,$10,$41,$DE,$BB,$4B,$38,$6B,$DA,$A2,$6C,$E0,$1A,$20,$0D,$AA,$80,$07,$B2,$A5
  Data.b $1E,$A0,$62,$FD,$CC,$0D,$7A,$21,$BC,$2C,$AC,$E6,$C2,$00,$D5,$9D,$42,$B7,$19,$6A
  Data.b $13,$A1,$0F,$6C,$03,$85,$42,$1B,$54,$41,$D5,$42,$27,$14,$80,$92,$1A,$A9,$E0,$6D
  Data.b $DB,$FA,$19,$F2,$70,$19,$4B,$B8,$53,$2A,$FE,$3B,$16,$F0,$3C,$73,$12,$07,$12,$68
  Data.b $00,$C4,$83,$2A,$E8,$81,$E8,$84,$42,$68,$41,$25,$B5,$5A,$0A,$EB,$6F,$41,$FF,$86
  Data.b $E1,$52,$66,$94,$C1,$1A,$E4,$BD,$8D,$B3,$F0,$99,$E8,$D1,$71,$56,$02,$0D,$42,$21
  Data.b $B4,$01,$91,$5A,$2D,$74,$21,$35,$8E,$28,$EF,$96,$8D,$4F,$4A,$DD,$B1,$F4,$D4,$DF
  Data.b $BB,$76,$55,$EE,$FB,$B8,$00,$9B,$7D,$06,$D0,$03,$25,$D0,$85,$D0,$06,$55,$6A,$B5
  Data.b $D0,$09,$B7,$AE,$2F,$4C,$B9,$14,$F3,$9C,$BC,$D9,$B1,$94,$D7,$00,$FF,$7D,$E6,$71
  Data.b $49,$70,$C6,$DD,$8B,$93,$D0,$00,$ED,$ED,$55,$D0,$03,$25,$09,$85,$D0,$06,$4F,$A4
  Data.b $B5,$D0,$CF,$13,$CB,$B5,$5F,$F1,$87,$0C,$9D,$42,$25,$E5,$71,$6D,$30,$EF,$1C,$BA
  Data.b $FC,$F7,$C7,$74,$21,$FF,$09,$34,$00,$7F,$BB,$E5,$F5,$40,$7F,$CF,$52,$CE,$5A,$E8
  Data.b $04,$FF,$9E,$4F,$FC,$AD,$B3,$FD,$4A,$B2,$7B,$B1,$53,$DB,$FB,$FF,$5D,$FB,$9A,$3E
  Data.b $AD,$D3,$3F,$77,$2C,$E3,$2B,$81,$06,$D0,$A1,$0D,$EC,$D8,$6A,$A1,$13,$0A,$14,$52
  Data.b $F3,$DA,$E7,$BE,$0E,$AA,$29,$74,$39,$77,$7D,$DD,$B8,$E8,$CD,$5C,$92,$FA,$3C,$71
  Data.b $DB,$BE,$38,$B0,$5F,$A1,$07,$F3,$9D,$9F,$F4,$84,$29,$EA,$27,$7D,$C4,$9A,$2A,$F0
  Data.b $1B,$94,$21,$B4,$41,$6E,$3D,$2D,$74,$42,$22,$D4,$0F,$2B,$12,$46,$55,$BC,$CC,$97
  Data.b $01,$F4,$FE,$01,$C9,$92,$4E,$64,$FB,$AE,$86,$37,$48,$99,$66,$C1,$9D,$D1,$38,$6C
  Data.b $87,$95,$2A,$E8,$01,$12,$5B,$FD,$35,$EC,$82,$27,$54,$E6,$D3,$38,$33,$D4,$CD,$2A
  Data.b $BC,$D2,$B4,$5C,$CF,$97,$FE,$85,$6A,$FA,$4B,$47,$AD,$1A,$CF,$E0,$BC,$89,$15,$DB
  Data.b $F8,$A6,$B8,$60,$F5,$D7,$09,$34,$00,$7C,$41,$15,$F4,$40,$74,$42,$21,$B4,$6A,$5C
  Data.b $5B,$2D,$BD,$5F,$BB,$4C,$BB,$0F,$CC,$F7,$53,$FF,$93,$15,$DD,$D9,$39,$6B,$D5,$97
  Data.b $F7,$1E,$7F,$9A,$32,$7D,$EE,$49,$4B,$66,$4F,$56,$8F,$01,$A9,$2F,$5F,$4A,$17,$E9
  Data.b $CE,$FA,$50,$08,$6D,$80,$EA,$53,$0B,$9D,$4F,$3A,$94,$3D,$FF,$9C,$07,$17,$37,$33
  Data.b $80,$E1,$B3,$61,$29,$B4,$DC,$94,$69,$EB,$6B,$7E,$63,$76,$17,$FF,$BA,$2F,$97,$CA
  Data.b $97,$DC,$93,$40,$E6,$FE,$49,$35,$BE,$35,$B4,$01,$63,$A6,$2D,$74,$42,$21,$4B,$89
  Data.b $36,$43,$7C,$C2,$73,$29,$B5,$FB,$54,$8B,$67,$BA,$07,$4B,$23,$CA,$CF,$2C,$97,$BD
  Data.b $5A,$78,$EB,$3B,$55,$E9,$31,$62,$CF,$00,$50,$05,$3D,$A0,$9D,$50,$08,$6D,$37,$35
  Data.b $5A,$0B,$FA,$84,$D4,$90,$E4,$C1,$BE,$93,$0C,$05,$78,$3F,$E7,$73,$76,$0C,$F4,$7F
  Data.b $DD,$A2,$DD,$99,$02,$FC,$4F,$03,$C0,$AF,$31,$20,$3E,$ED,$A8,$3B,$46,$EF,$B4,$C1
  Data.b $FF,$E0,$2D,$74,$42,$21,$F4,$6D,$74,$67,$5E,$D3,$A3,$DE,$69,$E1,$B4,$1E,$E9,$AA
  Data.b $29,$B8,$CA,$F5,$D6,$14,$21,$21,$79,$68,$01,$14,$FF,$C8,$32,$1A,$02,$8D,$EB,$AA
  Data.b $7D,$E0,$84,$42,$70,$83,$EA,$CD,$5A,$E8,$1F,$85,$69,$5D,$79,$BE,$77,$9D,$9E,$9F
  Data.b $7A,$71,$CE,$F4,$89,$67,$F9,$67,$84,$2C,$2F,$5C,$33,$45,$86,$9F,$D2,$C9,$05,$3D
  Data.b $60,$03,$50,$08,$6D,$50,$9D,$59,$0B,$9D,$60,$E8,$9E,$27,$67,$3F,$6B,$95,$AF,$33
  Data.b $AE,$33,$79,$DC,$FD,$3D,$2F,$5F,$7B,$BF,$B8,$90,$A7,$F0,$6C,$60,$9A,$07,$D0,$06
  Data.b $94,$F2,$B5,$D0,$09,$85,$A2,$5B,$66,$74,$E8,$28,$EB,$8D,$CD,$E8,$A8,$C0,$8A,$6E
  Data.b $B4,$DE,$E8,$CD,$06,$70,$BF,$75,$EB,$9C,$F4,$BC,$71,$AB,$49,$BA,$5D,$CB,$3A,$A1
  Data.b $10,$BC,$6E,$F7,$BF,$16,$0D,$75,$A8,$45,$CA,$A6,$50,$FD,$33,$60,$53,$AB,$81,$69
  Data.b $8C,$62,$14,$82,$09,$B8,$BD,$AB,$5D,$27,$53,$25,$03,$E6,$6D,$DE,$4C,$CE,$B0,$27
  Data.b $9C,$BC,$18,$EB,$84,$42,$88,$44,$08,$00,$00,$00,$00,$00
  closebuttonsend:
EndDataSection 

Posted: Mon Feb 18, 2008 2:23 am
by Dare
Very nice!

Posted: Mon Feb 18, 2008 2:46 am
by rsts
Another lesson from the maestro :D

Thanks.

Posted: Mon Feb 18, 2008 7:55 am
by Mistrel
Impressive! With a web gadget inside you can make something really unique.

Posted: Mon Feb 18, 2008 9:06 am
by gnozal
Yes, very impressive.
Be aware that it will not work with Win NT4/9x/Me because of GetGuiResources_().

Posted: Tue Feb 19, 2008 9:05 pm
by Nico
For have the system menu:

Code: Select all

OpenWindow(0,0,0,320,240,"Ownerdrawn Frame",#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
and

Code: Select all

    Case #WM_NCHITTEST 
        #HTCLOSE=20
        #HTCAPTION=2
        #HTMAXBUTTON=9
        #HTMINBUTTON=8
        result=DefWindowProc_(hwnd, msg, wparam, lparam)
        Debug "----------------------"
        Debug result
        If result=#HTCLOSE Or result=#HTMAXBUTTON  Or result=#HTMINBUTTON
          result=#HTCAPTION
        EndIf 

Posted: Tue Feb 19, 2008 10:35 pm
by netmaestro
It's not that easy, unfortunately. When you ownerdraw the frame, the buttons don't show through. I originally thought I could solve it by cutting rectangles out of the frame region to let the buttons show through, but then I realized that the button sizes and locations are different depending on which theme if any is being used on the system. Of all the options available I judged that the easiest way in the end is to just use some CustomButtons code and do it myself.

Posted: Tue Feb 19, 2008 11:11 pm
by Nico
It's just a trick to have the system menu, if you don't track the message #WM_NCHITTEST, buttons system will appear; sure is needed CustomButtons.

Posted: Tue Feb 19, 2008 11:52 pm
by DoubleDutch
Looks great, works with vista no problems. :)

Posted: Thu Feb 21, 2008 3:37 am
by Sparkie
Nice work netmaestro 8)

Re: Ownerdrawn resizable window frames

Posted: Mon Sep 28, 2009 1:58 pm
by klaver
Sorry for bumping this thread, but I get a (false) positive from my Avast when compiled with PB 4.31.
Avast 4.8.1351.0 2009.09.27 Win32:SkiMorph
Any ideas why this happens?

Re: Ownerdrawn resizable window frames

Posted: Mon Sep 28, 2009 2:30 pm
by PB
Don't know, but the code doesn't compile with v4.40 B3 at all.

Re: Ownerdrawn resizable window frames

Posted: Mon Sep 28, 2009 2:48 pm
by Hroudtwolf
Take this.... :)

Code: Select all

;===================================================================
; Program:              Ownerdrawn Resizable Window Frame Demo
; Author:               Lloyd Gallant (netmaestro)
; Date:                 August 28, 2007
; Target OS:            Microsoft Windows All (I think)
; Target Compiler:      PureBasic 4.xx and later
; License:              Free, unrestricted, no warranty
; Modified for PB4.4x:  Hroudtwolf
;===================================================================

; Adjust these for different Caption height and frame thicknesses
Global gCaptionHeight   = 60
Global gFrameWidth      = 20
Global buttonsize       = 18
Global gCaptionTxtColor = #White



; read in button images for the 3 states

img0 = CatchImage(#PB_Any, ?closebuttons, 3008)

*unpacked = AllocateMemory(3008)
UnpackMemory(?closebuttons, *unpacked)
img0 = CatchImage(#PB_Any, *unpacked, 3008)
FreeMemory(*unpacked)

Global CB_Normal   = GrabImage(img0, #PB_Any,0,0,18,18)
Global CB_Selected = GrabImage(img0, #PB_Any,18,0,18,18)
Global CB_Pressed  = GrabImage(img0, #PB_Any,36,0,18,18)

If buttonsize<>18
  ResizeImage(CB_Normal, buttonsize,buttonsize)
  ResizeImage(CB_Selected, buttonsize,buttonsize)
  ResizeImage(CB_Pressed, buttonsize,buttonsize)
EndIf

StartDrawing(ImageOutput(img0))
  Global gTranscolor = Point(0,0)
StopDrawing()
FreeImage(img0)

Global gFrameTexture = CatchImage(#PB_Any, ?backbrush)
Global hBrush = CreatePatternBrush_(ImageID(gFrameTexture))

Global gCloseButton_State = CB_Normal

ProcedureDLL TransBlit(hdc, hBitmap, xStart, yStart, TransColor)
  ; by netmaestro based on http://support.microsoft.com/kb/79212/EN-US/
  Define.POINT  ptSize
  hdcTemp = CreateCompatibleDC_(hdc)
  SelectObject_(hdcTemp, hBitmap)
  GetObject_(hBitmap, SizeOf(BITMAP), bm.BITMAP)
  ptSize\x = bm\bmWidth
  ptSize\y = bm\bmHeight
  DPtoLP_(hdcTemp, @ptSize, 1)
  hdcBack   = CreateCompatibleDC_(hdc)
  hdcObject = CreateCompatibleDC_(hdc)
  hdcMem    = CreateCompatibleDC_(hdc)
  hdcSave   = CreateCompatibleDC_(hdc)
  bmAndBack   = CreateBitmap_(ptSize\x, ptSize\y, 1, 1, #Null)
  bmAndObject = CreateBitmap_(ptSize\x, ptSize\y, 1, 1, #Null)
  bmAndMem    = CreateCompatibleBitmap_(hdc, ptSize\x, ptSize\y)
  bmSave      = CreateCompatibleBitmap_(hdc, ptSize\x, ptSize\y)
  bmBackOld   = SelectObject_(hdcBack, bmAndBack)
  bmObjectOld = SelectObject_(hdcObject, bmAndObject)
  bmMemOld    = SelectObject_(hdcMem, bmAndMem)
  bmSaveOld   = SelectObject_(hdcSave, bmSave)
  SetMapMode_(hdcTemp, GetMapMode_(hdc))
  BitBlt_(hdcSave, 0, 0, ptSize\x, ptSize\y, hdcTemp, 0, 0, #SRCCOPY)
  cColor = SetBkColor_(hdcTemp, TransColor)
  BitBlt_(hdcObject, 0, 0, ptSize\x, ptSize\y, hdcTemp, 0, 0, #SRCCOPY)
  SetBkColor_(hdcTemp, cColor)
  BitBlt_(hdcBack, 0, 0, ptSize\x, ptSize\y, hdcObject, 0, 0, #NOTSRCCOPY)
  BitBlt_(hdcMem, 0, 0, ptSize\x, ptSize\y, hdc, xStart, yStart, #SRCCOPY)
  BitBlt_(hdcMem, 0, 0, ptSize\x, ptSize\y, hdcObject, 0, 0, #SRCAND)
  BitBlt_(hdcTemp, 0, 0, ptSize\x, ptSize\y, hdcBack, 0, 0, #SRCAND)
  BitBlt_(hdcMem, 0, 0, ptSize\x, ptSize\y, hdcTemp, 0, 0, #SRCPAINT)
  BitBlt_(hdc, xStart, yStart, ptSize\x, ptSize\y, hdcMem, 0, 0, #SRCCOPY)
  BitBlt_(hdcTemp, 0, 0, ptSize\x, ptSize\y, hdcSave, 0, 0, #SRCCOPY)
  DeleteObject_(SelectObject_(hdcBack, bmBackOld))
  DeleteObject_(SelectObject_(hdcObject, bmObjectOld))
  DeleteObject_(SelectObject_(hdcMem, bmMemOld))
  DeleteObject_(SelectObject_(hdcSave, bmSaveOld))
  DeleteDC_(hdcMem)
  DeleteDC_(hdcBack)
  DeleteDC_(hdcObject)
  DeleteDC_(hdcSave)
  DeleteDC_(hdcTemp)
EndProcedure

Procedure WindowProc(hwnd, msg, wParam, lParam)
   
  Static frameW
  Static captionH
  Static buttonT

  oldproc = GetProp_(hwnd, "oldproc")
  result = oldproc

  Select msg
   
    Case #WM_NCDESTROY
      RemoveProp_(hwnd, "oldproc")

    Case #WM_MOUSEMOVE
      If gCloseButton_State <> CB_Normal
        gCloseButton_State = CB_Normal
        SendMessage_(hwnd, #WM_NCPAINT, 0,0)
      EndIf
     
    Case #WM_NCLBUTTONDOWN
      GetWindowRect_(hwnd, wr.RECT)
      cp.POINT
      cp\x = lparam & $FFFF - wr\left
      cp\y = lparam >> 16 - wr\top

      br.RECT
      br\left = wr\right-wr\left - frameW-buttonsize
      br\right = br\left+buttonsize
      br\top = buttonT
      br\bottom = br\top + buttonsize
     
      If PtInRect_(br, cp)
        gCloseButton_State = CB_Pressed
        SendMessage_(hwnd, #WM_NCPAINT, 0,0)
        result = 0
      EndIf
     
    Case #WM_NCLBUTTONUP
      GetWindowRect_(hwnd, wr.RECT)
      cp.POINT
      cp\x = lparam & $FFFF - wr\left
      cp\y = lparam >> 16 - wr\top
           
      br.RECT
      br\left = wr\right-wr\left - frameW-buttonsize
      br\right = br\left+buttonsize
      br\top = buttonT
      br\bottom = br\top + buttonsize
     
      If PtInRect_(br, cp)
        If gCloseButton_State = CB_Pressed
          SendMessage_(hwnd, #WM_SYSCOMMAND, #SC_CLOSE, 0)
        EndIf
      Else
        gCloseButton_State = CB_Normal
        SendMessage_(hwnd, #WM_NCPAINT, 0,0)
        result = 0
      EndIf
     
    Case #WM_NCMOUSEMOVE
      GetWindowRect_(hwnd, wr.RECT)
      cp.POINT
      cp\x = lparam & $FFFF - wr\left
      cp\y = lparam >> 16 - wr\top
     
      br.RECT
      br\left = wr\right-wr\left - frameW-buttonsize
      br\right = br\left+buttonsize
      br\top = buttonT
      br\bottom = br\top + buttonsize
     
      If PtInRect_(br, cp)
        If GetAsyncKeyState_(#VK_LBUTTON) & 32768
          If gCloseButton_State = CB_Pressed
            SendMessage_(hwnd, #WM_NCPAINT, 0,0)
          Else
            If gCloseButton_State <> CB_Selected
              gCloseButton_State = CB_Selected
              SendMessage_(hwnd, #WM_NCPAINT, 0,0)
            EndIf
          EndIf
        Else
          If gCloseButton_State <> CB_Selected
            gCloseButton_State = CB_Selected
            SendMessage_(hwnd, #WM_NCPAINT, 0,0)
          EndIf
        EndIf
      Else
        If gCloseButton_State <> CB_Normal
          gCloseButton_State = CB_Normal
          SendMessage_(hwnd, #WM_NCPAINT, 0,0)
        EndIf
      EndIf   
      result = 0
         
     Case #WM_NCCALCSIZE
       *np.NCCALCSIZE_PARAMS = lparam
 
        With *np\rgrc[0]
          \left    = *np\lppos\x + gFrameWidth
          \top     = *np\lppos\y + gCaptionHeight
          \right   = *np\lppos\x + *np\lppos\cx - gFrameWidth
          \bottom  = *np\lppos\y + *np\lppos\cy - gFrameWidth
        EndWith     
       
       captionH = *np\rgrc[0]\top - *np\lppos\y
       frameW   = *np\rgrc[0]\left - *np\lppos\x
       buttonT = (captionH - buttonsize)/2
       
     result =  #WVR_VALIDRECTS | #WVR_REDRAW
         
    Case #WM_NCPAINT, #WM_NCACTIVATE
     
      GetWindowRect_(hwnd, wr.RECT)
      new_w = wr\right - wr\left
      new_h = wr\bottom - wr\top
      hdc = GetWindowDC_(hwnd)
      hdctemp = CreateCompatibleDC_(hdc)
      hrgn = CreateRectRgn_(-1,-1,new_w+1, new_h+1)
      hrgn2 = CreateRectRgn_(frameW,captionH,new_w-frameW,new_h-frameW)
      CombineRgn_(hrgn, hrgn, hrgn2, #RGN_XOR)
      SelectClipRgn_(hdc, hrgn)
      imgtemp = CreateImage(#PB_Any, new_w+2,new_h+2, #PB_Image_DisplayFormat)
      hBitmap = ImageID(imgtemp)
      SelectObject_(hdctemp, hBitmap)
      SelectObject_(hdctemp, hBrush)
      Rectangle_(hdctemp,-1,-1,new_w+1, new_h+1)
      ; Window title
      wt$ = Space(100)
      GetWindowText_(hwnd, @wt$, 99)
      SetBkMode_(hdctemp, #TRANSPARENT)
      SetTextColor_(hdctemp, gCaptionTxtColor)
      TextOut_(hdctemp, frameW,captionH/2-7,wt$, Len(wt$))
      ; Buttons
      If IsImage(gCloseButton_State)
        TransBlit(hdctemp, ImageID(gCloseButton_State), new_w - frameW-buttonsize, buttonT, gTranscolor)
        DeleteDC_(buttondc)
      EndIf
      BitBlt_(hdc,0,0,new_w+1, new_h+1,hdctemp,0,0,#SRCCOPY)
      DeleteObject_(hBitmap)
      DeleteDC_(hdctemp)
      ReleaseDC_(hwnd, hdc)
      DeleteObject_(hrgn)
      DeleteObject_(hrgn2)
      result = 0

  EndSelect
 
  If result = oldproc
    ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
  Else
    ProcedureReturn result
  EndIf
 
EndProcedure

Procedure MonitorButtons(hwnd)
  Repeat
    GetWindowRect_(hwnd, @wr.RECT)
    GetCursorPos_(@cp.POINT)
    ; if the cursor is outside the window, the CloseButton
    ; must show normal. All other cases are covered in the callback.
    If Not PtInRect_(wr, cp)
      If gCloseButton_State <> CB_Normal
        gCloseButton_State = CB_Normal
        SendMessage_(hwnd, #WM_NCPAINT, 0,0)
      EndIf
    EndIf
    Delay(15)
  ForEver
EndProcedure

Procedure cb(hwnd, msg, wparam, lparam)
  result = #PB_ProcessPureBasicEvents

  ProcedureReturn result
EndProcedure

OpenWindow(0,0,0,320,240,"Ownerdrawn Frame",#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
CreateGadgetList(WindowID(0))
TextGadget(0,0,0,150,20,"")
SetGadgetColor(0,#PB_Gadget_BackColor, #White)
SetWindowColor(0, #White)
SetProp_(WindowID(0), "oldproc", SetWindowLong_(WindowID(0), #GWL_WNDPROC, @WindowProc()))
CreateStatusBar(0, WindowID(0))

; dry-fire the WM_NCCALCSIZE and WM_NCPAINT events:
SetWindowPos_(WindowID(0),0,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE|#SWP_NOZORDER|#SWP_FRAMECHANGED)

; a thread ensures no mistakes in resetting the CloseButton image to normal
CreateThread(@MonitorButtons(), WindowID(0))

ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS,#False,GetCurrentProcessId_());

lastgdicount = 0
Repeat
  ev = WaitWindowEvent()
  gdicount = GetGuiResources_(ProcessHandle, 0) ; 0 = #GR_GDIOBJECTS
  If gdicount <> lastgdicount
    lastgdicount = gdicount
    SetGadgetText(0,"GDI Object Count: "+Str(gdicount))
  EndIf
Until ev=#PB_Event_CloseWindow

DeleteObject_(hBrush)

DataSection
  backbrush:         IncludeBinary #PB_Compiler_Home+"Examples\Sources\Data\Background.bmp"
  closebuttons:     
  Data.b $4A,$43,$C0,$0B,$00,$00,$72,$EC,$2F,$DE,$BC,$A9,$D0,$20,$69,$14,$59,$08,$18,$CA
  Data.b $08,$B0,$01,$25,$89,$22,$3C,$06,$18,$23,$98,$C4,$40,$50,$FF,$14,$60,$12,$79,$E2
  Data.b $7C,$80,$D2,$15,$A3,$B1,$CC,$74,$4E,$A2,$C0,$48,$30,$0D,$FD,$EF,$04,$6E,$65,$03
  Data.b $D0,$8C,$F4,$5C,$2E,$D4,$60,$15,$F5,$96,$27,$65,$63,$9D,$36,$AD,$9E,$F5,$57,$29
  Data.b $C7,$AD,$00,$2B,$53,$E3,$81,$15,$5D,$18,$14,$42,$1B,$50,$01,$C0,$58,$27,$67,$FB
  Data.b $04,$7A,$6A,$EC,$A1,$59,$4F,$42,$1B,$E0,$D0,$09,$84,$60,$6C,$B2,$63,$B5,$A3,$4F
  Data.b $99,$77,$19,$A0,$69,$F2,$27,$50,$45,$4E,$8A,$8D,$D5,$42,$B6,$D3,$F3,$ED,$77,$DC
  Data.b $19,$E8,$45,$7D,$6E,$4A,$A0,$3F,$E7,$36,$97,$60,$FE,$1F,$42,$21,$B4,$81,$91,$5A
  Data.b $2D,$74,$5B,$A1,$23,$A7,$55,$CA,$ED,$A4,$C7,$CA,$15,$B9,$60,$59,$BB,$2E,$09,$85
  Data.b $40,$3D,$CF,$9B,$B5,$D0,$27,$FA,$92,$B6,$E8,$4E,$A5,$32,$E2,$1D,$6C,$55,$66,$1D
  Data.b $4F,$96,$59,$AD,$E6,$CD,$E9,$06,$AC,$FC,$82,$F8,$B2,$58,$B4,$65,$2D,$74,$A7,$E2
  Data.b $64,$2E,$3F,$ED,$CB,$D6,$4C,$41,$1D,$F9,$93,$A6,$EC,$F6,$C0,$46,$53,$92,$10,$DA
  Data.b $C0,$6B,$B3,$16,$3A,$A1,$42,$6A,$CC,$90,$D7,$D5,$3E,$91,$52,$B3,$D2,$87,$CE,$2B
  Data.b $97,$E4,$95,$F9,$D3,$AA,$24,$D0,$61,$1A,$4C,$EB,$D7,$E7,$0A,$7A,$80,$07,$A1,$10
  Data.b $DA,$A0,$79,$94,$16,$3C,$44,$7F,$AE,$EE,$DE,$AC,$56,$E1,$C5,$87,$B5,$5A,$EA,$79
  Data.b $B4,$5B,$3E,$45,$0F,$56,$A7,$9D,$50,$BA,$02,$6F,$C0,$D2,$97,$C0,$4E,$AD,$D6,$42
  Data.b $27,$9C,$13,$E1,$43,$7D,$59,$B0,$71,$A5,$40,$23,$FE,$BF,$99,$19,$8B,$3E,$71,$4C
  Data.b $91,$3D,$74,$67,$F6,$7F,$7C,$C0,$34,$5F,$0D,$AA,$A0,$07,$A1,$13,$0A,$A1,$F1,$A5
  Data.b $44,$6B,$56,$1C,$90,$DA,$8E,$B5,$AB,$89,$D2,$A5,$5E,$6D,$BD,$BD,$ED,$DB,$B9,$CE
  Data.b $A7,$5E,$AD,$5F,$35,$59,$80,$0D,$D8,$F4,$B4,$41,$15,$F4,$2D,$74,$42,$21,$C7,$48
  Data.b $CD,$68,$DD,$AA,$7E,$6D,$B2,$55,$D1,$9F,$EF,$DB,$F6,$FB,$FA,$B1,$53,$CF,$B5,$3D
  Data.b $5B,$AE,$80,$B9,$77,$EB,$54,$41,$0F,$D8,$27,$14,$42,$1B,$2A,$A9,$D5,$42,$79,$8D
  Data.b $23,$15,$99,$EF,$7F,$C8,$A1,$BC,$97,$12,$C7,$CD,$52,$4E,$01,$53,$D0,$87,$32,$93
  Data.b $68,$97,$A0,$07,$78,$C0,$0A,$A1,$0D,$AA,$43,$6B,$A1,$13,$D6,$22,$B5,$A4,$5F,$72
  Data.b $07,$4B,$B8,$F0,$C4,$30,$09,$00,$33,$8A,$69,$F6,$25,$D9,$AE,$60,$AB,$B3,$81,$12
  Data.b $70,$00,$68,$83,$2A,$E8,$52,$EB,$84,$42,$1A,$0A,$F1,$24,$86,$55,$AF,$16,$CD,$9D
  Data.b $F8,$E5,$9C,$A3,$3C,$F4,$FF,$EE,$DA,$D0,$85,$DF,$D6,$2B,$00,$F1,$DD,$7E,$D0,$03
  Data.b $25,$D0,$85,$D0,$06,$55,$6A,$B5,$D0,$09,$E3,$47,$83,$4A,$EF,$FF,$C4,$1C,$52,$94
  Data.b $22,$19,$FB,$3E,$8E,$5A,$EF,$BD,$10,$98,$1F,$7E,$4B,$19,$00,$C4,$70,$FD,$E8,$81
  Data.b $12,$70,$42,$68,$83,$02,$B6,$5A,$E8,$84,$C4,$4E,$7D,$B8,$DD,$6B,$58,$D6,$96,$F2
  Data.b $95,$72,$61,$7E,$27,$5B,$F8,$70,$BC,$32,$EC,$99,$80,$9C,$AB,$D7,$FA,$1F,$09,$34
  Data.b $80,$85,$41,$15,$F4,$40,$74,$42,$21,$B4,$D6,$5C,$5B,$2D,$31,$BC,$28,$50,$AE,$58
  Data.b $F9,$E8,$AF,$D7,$2C,$65,$39,$C6,$D9,$C9,$EC,$C6,$01,$A3,$B8,$60,$C1,$34,$D3,$34
  Data.b $00,$FD,$1B,$30,$F7,$50,$42,$27,$14,$42,$87,$B3,$47,$D5,$6D,$71,$A3,$40,$BF,$ED
  Data.b $2F,$D8,$E2,$B8,$FC,$09,$E6,$39,$34,$3F,$E5,$C1,$93,$43,$C2,$6F,$EF,$84,$FF,$7F
  Data.b $D5,$52,$80,$12,$68,$00,$68,$83,$2A,$28,$5A,$E8,$84,$42,$44,$A2,$BC,$B6,$CD,$2E
  Data.b $91,$D4,$CA,$6E,$97,$90,$B4,$6A,$BB,$4B,$36,$13,$A6,$F9,$2F,$49,$EE,$A7,$0F,$B5
  Data.b $06,$98,$84,$36,$A0,$02,$AD,$85,$4E,$28,$E5,$18,$A9,$19,$BC,$67,$EB,$DF,$CF,$17
  Data.b $AD,$FD,$FF,$03,$B3,$C5,$F4,$8B,$75,$6A,$D4,$1A,$80,$3F,$42,$68,$03,$2B,$7D,$5A
  Data.b $E8,$84,$A4,$56,$F4,$27,$B6,$3F,$8C,$46,$76,$4B,$09,$DC,$3A,$CC,$A9,$01,$1F,$EB
  Data.b $84,$84,$D7,$86,$E0,$CA,$00,$FD,$A5,$2F,$C0,$03,$DA,$D0,$85,$D0,$06,$55,$6A,$B5
  Data.b $D0,$09,$4E,$76,$2C,$45,$DE,$CD,$96,$E5,$D9,$F0,$68,$27,$36,$ED,$77,$CA,$7A,$AF
  Data.b $A7,$A6,$FE,$DB,$46,$7D,$07,$4A,$E0,$00,$A1,$0D,$AA,$A0,$6B,$A1,$13,$0A,$B8,$C1
  Data.b $0C,$46,$5F,$EF,$D9,$E1,$F5,$F7,$45,$7B,$06,$28,$C0,$69,$B6,$76,$BF,$5F,$9C,$F3
  Data.b $27,$8C,$BD,$4F,$C3,$96,$40,$09,$60,$63,$B3,$41,$15,$F4,$FF,$BF,$69,$F3,$16,$F6
  Data.b $73,$02,$28,$71,$48,$AD,$BF,$69,$19,$00,$9A,$01,$AD,$7E,$D0,$C0,$80,$01,$3D,$FF
  Data.b $0B,$66,$F4,$00,$67,$63,$21,$B8,$41,$15,$5A,$2D,$74,$02,$48,$A1,$E2,$90,$B6,$6C
  Data.b $EB,$9F,$3E,$2D,$80,$76,$05,$BF,$76,$12,$58,$8D,$03,$A0,$93,$1A,$30,$94,$50,$05
  Data.b $3D,$40,$9D,$50,$08,$6D,$31,$3B,$55,$0B,$0F,$66,$8B,$9B,$FC,$05,$53,$FE,$66,$A1
  Data.b $37,$B5,$B9,$59,$FE,$BD,$40,$05,$3D,$40,$C7,$7E,$C1,$78,$9F,$13,$FA,$43,$19,$6A
  Data.b $B5,$F0,$4B,$DA,$E6,$A9,$AE,$ED,$D2,$E1,$29,$8B,$01,$14,$EF,$86,$E5,$4F,$00,$65
  Data.b $63,$F7,$E1,$6C,$15,$F4,$68,$C1,$13,$0E,$89,$D4,$DC,$A3,$F1,$90,$50,$AE,$09,$65
  Data.b $AD,$5A,$E3,$38,$00,$DB,$F7,$DE,$1D,$43,$9A,$75,$32,$E8,$81,$06,$D0,$ED,$AB,$82
  Data.b $1E,$28,$16,$3A,$01,$0F,$35,$7B,$54,$87,$52,$C4,$D9,$A1,$FC,$D6,$BF,$D9,$D4,$FE
  Data.b $0C,$10,$41,$DE,$BB,$4B,$38,$6B,$DA,$A2,$6C,$E0,$1A,$20,$0D,$AA,$80,$07,$B2,$A5
  Data.b $1E,$A0,$62,$FD,$CC,$0D,$7A,$21,$BC,$2C,$AC,$E6,$C2,$00,$D5,$9D,$42,$B7,$19,$6A
  Data.b $13,$A1,$0F,$6C,$03,$85,$42,$1B,$54,$41,$D5,$42,$27,$14,$80,$92,$1A,$A9,$E0,$6D
  Data.b $DB,$FA,$19,$F2,$70,$19,$4B,$B8,$53,$2A,$FE,$3B,$16,$F0,$3C,$73,$12,$07,$12,$68
  Data.b $00,$C4,$83,$2A,$E8,$81,$E8,$84,$42,$68,$41,$25,$B5,$5A,$0A,$EB,$6F,$41,$FF,$86
  Data.b $E1,$52,$66,$94,$C1,$1A,$E4,$BD,$8D,$B3,$F0,$99,$E8,$D1,$71,$56,$02,$0D,$42,$21
  Data.b $B4,$01,$91,$5A,$2D,$74,$21,$35,$8E,$28,$EF,$96,$8D,$4F,$4A,$DD,$B1,$F4,$D4,$DF
  Data.b $BB,$76,$55,$EE,$FB,$B8,$00,$9B,$7D,$06,$D0,$03,$25,$D0,$85,$D0,$06,$55,$6A,$B5
  Data.b $D0,$09,$B7,$AE,$2F,$4C,$B9,$14,$F3,$9C,$BC,$D9,$B1,$94,$D7,$00,$FF,$7D,$E6,$71
  Data.b $49,$70,$C6,$DD,$8B,$93,$D0,$00,$ED,$ED,$55,$D0,$03,$25,$09,$85,$D0,$06,$4F,$A4
  Data.b $B5,$D0,$CF,$13,$CB,$B5,$5F,$F1,$87,$0C,$9D,$42,$25,$E5,$71,$6D,$30,$EF,$1C,$BA
  Data.b $FC,$F7,$C7,$74,$21,$FF,$09,$34,$00,$7F,$BB,$E5,$F5,$40,$7F,$CF,$52,$CE,$5A,$E8
  Data.b $04,$FF,$9E,$4F,$FC,$AD,$B3,$FD,$4A,$B2,$7B,$B1,$53,$DB,$FB,$FF,$5D,$FB,$9A,$3E
  Data.b $AD,$D3,$3F,$77,$2C,$E3,$2B,$81,$06,$D0,$A1,$0D,$EC,$D8,$6A,$A1,$13,$0A,$14,$52
  Data.b $F3,$DA,$E7,$BE,$0E,$AA,$29,$74,$39,$77,$7D,$DD,$B8,$E8,$CD,$5C,$92,$FA,$3C,$71
  Data.b $DB,$BE,$38,$B0,$5F,$A1,$07,$F3,$9D,$9F,$F4,$84,$29,$EA,$27,$7D,$C4,$9A,$2A,$F0
  Data.b $1B,$94,$21,$B4,$41,$6E,$3D,$2D,$74,$42,$22,$D4,$0F,$2B,$12,$46,$55,$BC,$CC,$97
  Data.b $01,$F4,$FE,$01,$C9,$92,$4E,$64,$FB,$AE,$86,$37,$48,$99,$66,$C1,$9D,$D1,$38,$6C
  Data.b $87,$95,$2A,$E8,$01,$12,$5B,$FD,$35,$EC,$82,$27,$54,$E6,$D3,$38,$33,$D4,$CD,$2A
  Data.b $BC,$D2,$B4,$5C,$CF,$97,$FE,$85,$6A,$FA,$4B,$47,$AD,$1A,$CF,$E0,$BC,$89,$15,$DB
  Data.b $F8,$A6,$B8,$60,$F5,$D7,$09,$34,$00,$7C,$41,$15,$F4,$40,$74,$42,$21,$B4,$6A,$5C
  Data.b $5B,$2D,$BD,$5F,$BB,$4C,$BB,$0F,$CC,$F7,$53,$FF,$93,$15,$DD,$D9,$39,$6B,$D5,$97
  Data.b $F7,$1E,$7F,$9A,$32,$7D,$EE,$49,$4B,$66,$4F,$56,$8F,$01,$A9,$2F,$5F,$4A,$17,$E9
  Data.b $CE,$FA,$50,$08,$6D,$80,$EA,$53,$0B,$9D,$4F,$3A,$94,$3D,$FF,$9C,$07,$17,$37,$33
  Data.b $80,$E1,$B3,$61,$29,$B4,$DC,$94,$69,$EB,$6B,$7E,$63,$76,$17,$FF,$BA,$2F,$97,$CA
  Data.b $97,$DC,$93,$40,$E6,$FE,$49,$35,$BE,$35,$B4,$01,$63,$A6,$2D,$74,$42,$21,$4B,$89
  Data.b $36,$43,$7C,$C2,$73,$29,$B5,$FB,$54,$8B,$67,$BA,$07,$4B,$23,$CA,$CF,$2C,$97,$BD
  Data.b $5A,$78,$EB,$3B,$55,$E9,$31,$62,$CF,$00,$50,$05,$3D,$A0,$9D,$50,$08,$6D,$37,$35
  Data.b $5A,$0B,$FA,$84,$D4,$90,$E4,$C1,$BE,$93,$0C,$05,$78,$3F,$E7,$73,$76,$0C,$F4,$7F
  Data.b $DD,$A2,$DD,$99,$02,$FC,$4F,$03,$C0,$AF,$31,$20,$3E,$ED,$A8,$3B,$46,$EF,$B4,$C1
  Data.b $FF,$E0,$2D,$74,$42,$21,$F4,$6D,$74,$67,$5E,$D3,$A3,$DE,$69,$E1,$B4,$1E,$E9,$AA
  Data.b $29,$B8,$CA,$F5,$D6,$14,$21,$21,$79,$68,$01,$14,$FF,$C8,$32,$1A,$02,$8D,$EB,$AA
  Data.b $7D,$E0,$84,$42,$70,$83,$EA,$CD,$5A,$E8,$1F,$85,$69,$5D,$79,$BE,$77,$9D,$9E,$9F
  Data.b $7A,$71,$CE,$F4,$89,$67,$F9,$67,$84,$2C,$2F,$5C,$33,$45,$86,$9F,$D2,$C9,$05,$3D
  Data.b $60,$03,$50,$08,$6D,$50,$9D,$59,$0B,$9D,$60,$E8,$9E,$27,$67,$3F,$6B,$95,$AF,$33
  Data.b $AE,$33,$79,$DC,$FD,$3D,$2F,$5F,$7B,$BF,$B8,$90,$A7,$F0,$6C,$60,$9A,$07,$D0,$06
  Data.b $94,$F2,$B5,$D0,$09,$85,$A2,$5B,$66,$74,$E8,$28,$EB,$8D,$CD,$E8,$A8,$C0,$8A,$6E
  Data.b $B4,$DE,$E8,$CD,$06,$70,$BF,$75,$EB,$9C,$F4,$BC,$71,$AB,$49,$BA,$5D,$CB,$3A,$A1
  Data.b $10,$BC,$6E,$F7,$BF,$16,$0D,$75,$A8,$45,$CA,$A6,$50,$FD,$33,$60,$53,$AB,$81,$69
  Data.b $8C,$62,$14,$82,$09,$B8,$BD,$AB,$5D,$27,$53,$25,$03,$E6,$6D,$DE,$4C,$CE,$B0,$27
  Data.b $9C,$BC,$18,$EB,$84,$42,$88,$44,$08,$00,$00,$00,$00,$00
  closebuttonsend:
EndDataSection