CustomButtons sourcecode released

Share your advanced PureBasic knowledge/code with the community.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

CustomButtons sourcecode released

Post by netmaestro »

Current version: 1.1 November 24, 2007

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)
Last edited by netmaestro on Sat Nov 24, 2007 3:19 pm, edited 2 times in total.
BERESHEIT
Flaming Amoeba

Post by Flaming Amoeba »

Thank you a million times over Bossman!
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

WOW!

:shock:

cheers
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

I'm going to move away from compiled libs and post mostly source from here on. It's too much trouble to keep up with recompiling libs every time new versions of PB are released, and if people want to tailbite the code they can always do that. The whole point of a coding forum is to provide a place where people can learn new skills through the sharing of others, so source is the best way to do that.
BERESHEIT
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Thank you.
Dare2 cut down to size
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

Too cool 8)
You are a very large frog :lol:
ImageThe happiness is a road...
Not a destination
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

netmaestro wrote:I'm going to move away from compiled libs and post mostly source from here on. It's too much trouble to keep up with recompiling libs every time new versions of PB are released, and if people want to tailbite the code they can always do that. The whole point of a coding forum is to provide a place where people can learn new skills through the sharing of others, so source is the best way to do that.
thank you to share your code.
(same opinion as i have)
SPAMINATOR NR.1
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Ah! This is funny casual.
Just yesterday i was porting this your custombuttons stuff to 4.10 and was playing with it. And now you repost it!
Thanks!
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
eJan
Enthusiast
Enthusiast
Posts: 366
Joined: Sun May 21, 2006 11:22 pm
Location: Sankt Veit am Flaum

Post by eJan »

Yes sources...
Thanks a lot!
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Re: CustomButtons sourcecode released

Post by NoahPhense »

Very nice.. thanks for the share.

- np
Micko
Enthusiast
Enthusiast
Posts: 244
Joined: Thu May 24, 2007 7:36 pm
Location: Senegal
Contact:

Post by Micko »

i like it netmaestro :D
kinglestat
Enthusiast
Enthusiast
Posts: 746
Joined: Fri Jul 14, 2006 8:53 pm
Location: Malta
Contact:

Post by kinglestat »

really awesome
great work and much appreciated
I may not help with your coding
Just ask about mental issues!

http://www.lulu.com/spotlight/kingwolf
http://www.sen3.net
Flaming Amoeba

Post by Flaming Amoeba »

We ought to all give Netmaestro a big wet sloppy kiss for releasing this. But hopefully he will settle for our ocular thanks.



Thank You, Netmaestro!
byo
Enthusiast
Enthusiast
Posts: 635
Joined: Mon Apr 02, 2007 1:43 am
Location: Brazil

Post by byo »

Thanks a lot for that!
Really great!

Maybe someone can implement these sugestions (because I can't):

- Transparent background (rounded shapes);

- a #PB_Button_Toggle equivalent button type.

8)
Proud registered Purebasic user.
Because programming should be fun.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Bug fixed causing problems when added to multiple windows. Code updated in first post.
BERESHEIT
Post Reply