Changes this version:
-bug fixed which caused CustomButtons to malfunction when instances were attached to multiple windows in the application
Test prog button images and help .chm: http://www.greatlakescode.com/custombuttonfiles.zip
Code: Select all
;============================================================
; Program: CustomButton.pbi
; Author: Network Maestro
; Date: October 21,2006
; Target OS: Microsoft Windows All
; Target Compiler: PureBasic 4.10
; License: Free, unrestricted, credit appreciated
; but not required
;============================================================
#Enter = #WM_APP+$100
#Leave = #WM_APP+$101
#CB_Button_Click = #WM_APP+$102
#CB_SolidBrush = -2
Global lastbutton
Procedure Monitor(hwnd)
Protected cp1.POINT
Protected cp2.POINT
Repeat
If IsWindowEnabled_(hwnd)
If GetProp_(hwnd,"cb_status") = 2
SetProp_(hwnd,"cb_status",0)
If IsImage(GetProp_(hwnd,"cb_disab"))
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_cold")))
EndIf
EndIf
hRgn = GetProp_(hwnd,"cb_region")
GetCursorPos_(@cp1)
GetCursorPos_(@cp2)
MapWindowPoints_(0,hwnd,@cp1,1)
If WindowFromPoint_(cp2\x,cp2\y) = hwnd
If PtInRegion_(hRgn,cp1\x,cp1\y)
If GetProp_(hwnd,"cb_status") = 0
SetProp_(hwnd,"cb_status", 1)
If lastbutton = 0 Or lastbutton = hwnd Or GetAsyncKeyState_(#VK_LBUTTON) & 32768 = 0
PostMessage_(hwnd,#Enter,0,0)
lastbutton = 0
EndIf
EndIf
Else
If GetProp_(hwnd,"cb_status") = 1
SetProp_(hwnd,"cb_status", 0)
PostMessage_(hwnd,#Leave,0,0)
If GetAsyncKeyState_(#VK_LBUTTON) & 32768
If lastbutton = 0
lastbutton = hwnd
EndIf
Else
lastbutton = 0
EndIf
EndIf
EndIf
Else
If GetProp_(hwnd,"cb_status") = 1
SetProp_(hwnd,"cb_status", 0)
PostMessage_(hwnd,#Leave,0,0)
If GetAsyncKeyState_(#VK_LBUTTON) & 32768
If lastbutton = 0
lastbutton = hwnd
EndIf
Else
lastbutton = 0
EndIf
EndIf
EndIf
Else
If IsWindow_(hwnd)
If IsWindowEnabled_(hwnd)=0
SetProp_(hwnd,"cb_status",2)
If IsImage(GetProp_(hwnd,"cb_disab"))
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_disab")))
EndIf
EndIf
EndIf
EndIf
Delay(10)
ForEver
EndProcedure
Procedure CustomButtonProc(hwnd, msg, wparam, lparam)
Protected cp1.POINT
Protected oldproc = GetProp_(hwnd,"cb_oldproc")
Protected monitor_tid = GetProp_(hwnd, "cb_monitor_tid")
hRgn = GetProp_(hwnd, "cb_region")
GetCursorPos_(@cp1)
MapWindowPoints_(0,hwnd,@cp1,1)
Select msg
Case #WM_NCDESTROY
If IsThread(monitor_tid)
KillThread(monitor_tid)
WaitThread(monitor_tid)
EndIf
RemoveProp_(hwnd, "cb_status")
RemoveProp_(hwnd, "cb_disab")
RemoveProp_(hwnd, "cb_cold")
RemoveProp_(hwnd, "cb_warm")
RemoveProp_(hwnd, "cb_hot")
RemoveProp_(hwnd, "cb_parent")
RemoveProp_(hwnd, "cb_oldproc")
RemoveProp_(hwnd, "cb_region")
RemoveProp_(hwnd, "cb_monitor_tid")
Case #WM_LBUTTONDOWN
If PtInRegion_(hRgn,cp1\x,cp1\y)
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_hot")))
EndIf
Case #WM_LBUTTONUP
If PtInRegion_(hRgn,cp1\x,cp1\y)
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_warm")))
If lastbutton = 0 Or lastbutton= hwnd
PostMessage_(GetProp_(hwnd,"cb_parent"), #CB_Button_Click, GetDlgCtrlID_(hwnd), 0)
EndIf
lastbutton = 0
EndIf
Case #Enter
If GetAsyncKeyState_(#VK_LBUTTON) & 32768
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_hot")))
Else
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_warm")))
EndIf
Case #Leave
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(GetProp_(hwnd,"cb_cold")))
EndSelect
ProcedureReturn CallWindowProc_(oldproc,hwnd,msg,wparam,lparam)
EndProcedure
Procedure 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
ProcedureDLL GrabRegion(ImageID, transcolor) ; HBITMAP ImageID, COLORREF transcolor
;=======================================================
; =
; Very fast bitmap -> region creator =
; =
; Version 1.0 Release =
; =
; By netmaestro =
; =
; Contributors: eesau, nico, flype, rescator =
; =
; June 26, 2007 =
; =
;=======================================================
Structure RECTARRAY
rect.RECT[0]
EndStructure
Protected bmp.BITMAP,width.l,height.l,hVisibleRgn.l,combineresult.l=0, returnvalue.l = 0
Protected BmiInfo.BITMAPINFOHEADER,rowbytes.l,*ColorBits,hDC.l,iRes.l,Structure_Max.l
Protected *Buffer.RGNDATAHEADER,*rd.RECTARRAY,rectcount.l,y.l,x.l,pxcount.l,*px.LONG
Protected transcount.l,firsttrans.l,regionSize.l,hTransparentRgn.l
If GetObject_(ImageID, SizeOf(BITMAP), @bmp.BITMAP) And bmp
width = bmp\bmWidth
height = bmp\bmHeight
hVisibleRgn=CreateRectRgn_(0, 0, width, height)
If hVisibleRgn
With BmiInfo
\biSize = SizeOf(BITMAPINFOHEADER)
\biWidth = width
\biHeight = -height
\biPlanes = 1
\biBitCount = 32
\biCompression = #BI_RGB
EndWith
rowbytes = SizeOf(LONG)*width
*ColorBits = AllocateMemory(rowbytes*height)
If *ColorBits
hDC = GetWindowDC_(#Null)
If hDC
iRes = GetDIBits_(hDC, ImageID, 0, height, *ColorBits, @bmiInfo, #DIB_RGB_COLORS)
If iRes
ReleaseDC_(#Null, hDC)
Structure_Max=(width*height*16)+SizeOf(RGNDATAHEADER)
*Buffer=AllocateMemory(Structure_Max)
If *Buffer
*rd=*Buffer+SizeOf(RGNDATAHEADER)
rectcount = 0
For y=0 To height-1
pxcount=0
For x=0 To rowbytes-1 Step 4
*px = *ColorBits + rowbytes * y + x
If *px\l = transcolor
transcount = 1 : firsttrans = pxcount
x+SizeOf(LONG) : *px.LONG = *ColorBits + rowbytes * y + x
While *px\l = transcolor And x <= rowbytes-1
transcount+1 : pxcount+1 : x+SizeOf(LONG)
*px = *ColorBits + rowbytes * y + x
Wend
x-SizeOf(LONG) : *px.LONG = *ColorBits + rowbytes * y + x
With *rd\rect[rectcount]
\left = firsttrans
\top = y
\right = firsttrans+transcount
\bottom = y+1
EndWith
rectcount+1
EndIf
pxcount+1
Next
Next
With *Buffer
\dwSize = SizeOf(RGNDATAHEADER)
\iType = #RDH_RECTANGLES
\nCount = rectcount
\nRgnSize = rectcount * SizeOf(RECT)
\rcBound\left = 0
\rcBound\top = 0
\rcBound\right = width
\rcBound\bottom = height
EndWith
RegionSize=SizeOf(RGNDATAHEADER)+(rectcount * SizeOf(RECT))
hTransparentRgn = ExtCreateRegion_(0, RegionSize, *Buffer)
If hTransparentRgn
combineresult = CombineRgn_(hVisibleRgn, hVisibleRgn, hTransparentRgn, #RGN_XOR)
If combineresult = #SIMPLEREGION Or combineresult = #COMPLEXREGION
returnvalue = hVisibleRgn
Else
returnvalue = 0
EndIf
DeleteObject_(hTransparentRgn)
EndIf
FreeMemory(*Buffer)
EndIf
EndIf
EndIf
FreeMemory(*ColorBits)
EndIf
EndIf
DeleteObject_(bmp)
EndIf
ProcedureReturn returnvalue
EndProcedure
ProcedureDLL CustomButton(parent, button, x, y, w, h, image, bkgimage, tcolr)
disab=GrabImage(image,#PB_Any, 0, 0, w, h)
cold=GrabImage(image,#PB_Any, w, 0, w, h)
warm=GrabImage(image, #PB_Any, w*2, 0, w, h)
hot=GrabImage(image, #PB_Any, w*3, 0, w, h)
; Define clipping region
If w*5 = ImageWidth(image)
mask=GrabImage(image, #PB_Any, w*4, 0, w, h)
region = GrabRegion(ImageID(mask), #Black)
EndIf
If Not region
region = CreateRectRgn_(0,0,w,h)
EndIf
; Apply transparency if requested
If IsImage(bkgimage)
tmp1=GrabImage(bkgimage, #PB_Any, x, y, w, h)
tmp2=CreateImage(#PB_Any, w, h)
dc = StartDrawing(ImageOutput(tmp2))
DrawImage(ImageID(tmp1),0,0)
TransBlit(dc,ImageID(disab),0,0,tcolr)
StopDrawing()
StartDrawing(ImageOutput(disab))
DrawImage(ImageID(tmp2),0,0)
StopDrawing()
dc = StartDrawing(ImageOutput(tmp2))
DrawImage(ImageID(tmp1),0,0)
TransBlit(dc,ImageID(cold),0,0,tcolr)
StopDrawing()
StartDrawing(ImageOutput(cold))
DrawImage(ImageID(tmp2),0,0)
StopDrawing()
dc = StartDrawing(ImageOutput(tmp2))
DrawImage(ImageID(tmp1),0,0)
TransBlit(dc,ImageID(warm),0,0,tcolr)
StopDrawing()
StartDrawing(ImageOutput(warm))
DrawImage(ImageID(tmp2),0,0)
StopDrawing()
dc = StartDrawing(ImageOutput(tmp2))
DrawImage(ImageID(tmp1),0,0)
TransBlit(dc,ImageID(hot),0,0,tcolr)
StopDrawing()
StartDrawing(ImageOutput(hot))
DrawImage(ImageID(tmp2),0,0)
StopDrawing()
FreeImage(tmp1)
FreeImage(tmp2)
EndIf
CustomButtonID = ImageGadget(button,x,y,w,h,ImageID(cold))
If button=#PB_Any
handle = GadgetID(CustomButtonID)
Else
handle = CustomButtonID
EndIf
old = SetWindowLong_(handle, #GWL_WNDPROC, @CustomButtonProc())
SetProp_(handle,"cb_oldproc", old)
SetProp_(handle,"cb_status",0)
SetProp_(handle,"cb_disab",disab)
SetProp_(handle,"cb_cold",cold)
SetProp_(handle,"cb_warm",warm)
SetProp_(handle,"cb_hot",hot)
SetProp_(handle,"cb_parent",parent)
SetProp_(handle,"cb_region",region)
monitor_tid = CreateThread(@Monitor(),handle)
SetProp_(handle,"cb_monitor_tid",monitor_tid)
ProcedureReturn CustomButtonID
EndProcedure
ProcedureDLL.s CustomButton_GetVersion()
ProcedureReturn "Release 1.1"
EndProcedure
Code: Select all
;=================================
; test1.pb: Solid-color window
;=================================
IncludeFile "custombutton.pbi"
LoadImage(0,"buttons2.bmp")
Transcolor = RGB(224,223,227) ; Background color of buttons2.bmp
windowcolor=GetSysColor_(#COLOR_BTNFACE) ; Background color of the window
OpenWindow(0,0,0,300,200,"",$C80001)
CreateGadgetList(WindowID(0))
mygadget = CustomButton(WindowID(0),#PB_Any,40,20,60,60,0,#CB_SolidBrush,Transcolor)
CustomButton(WindowID(0),1,120,20,60,60,0,#CB_SolidBrush,Transcolor)
CustomButton(WindowID(0),2,200,20,60,60,0,#CB_SolidBrush,Transcolor)
DisableGadget(mygadget,1)
Repeat
EventID=WaitWindowEvent()
If EventID = #CB_Button_Click ; This is how you check for button clicks
If EventwParam()=1 ; You don't use #PB_Event_Gadget, EventGadget()
DisableGadget(mygadget,0) ; or EventType(). They don't apply to
ElseIf EventwParam()=2 ; CustomButtons.
DisableGadget(mygadget,1)
EndIf
EndIf
Until EventID=#WM_CLOSE
Code: Select all
;===============================================
; test2.pb: Image-background or skinned window
;===============================================
IncludeFile "custombutton.pbi"
LoadImage(0,"buttons.bmp")
CreateImage(33,300,200) ;========================================
StartDrawing(ImageOutput(33)) ; Image to use for window background
For i = 3 To 229 ; Included to demonstrate transparent
Line(0,i-30,300,1,RGB(150,60,i)) ; capabilities of CustomButtons
Next ; You can load an image or use the image
StopDrawing() ; you're skinning the window with
brush=CreatePatternBrush_(ImageID(33)) ; It must be the same size as the window
;========================================
Transcolor = RGB(64,64,64) ; Background color of buttons.bmp
OpenWindow(0,0,0,300,200,"",$CF0001)
CreateGadgetList(WindowID(0))
CustomButton(WindowID(0),0,40,20,60,60,0,33,Transcolor)
CustomButton(WindowID(0),1,120,20,60,60,0,33,Transcolor)
CustomButton(WindowID(0),2,200,20,60,60,0,33,Transcolor)
DisableGadget(0,1)
SetClassLong_(WindowID(0),#GCL_HBRBACKGROUND,brush)
InvalidateRect_(WindowID(0),0,1)
Repeat
EventID=WaitWindowEvent()
If EventID = #CB_Button_Click
If EventwParam()=1
DisableGadget(0,0)
ElseIf EventwParam()=2
DisableGadget(0,1)
EndIf
EndIf
Until EventID=#WM_CLOSE
DeleteObject_(brush)