ToggleButtonGadget

Share your advanced PureBasic knowledge/code with the community.
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

ToggleButtonGadget

Post by BasicallyPure »

Here is a button gadget that can use any color for the button and text.
As you know, a normal button does not allow you to choose the button color.
This can be an alternative to PureColor if you want to color your buttons.
It is designed to be used mainly as a toggle type button that can change color and/or text when you click it.
It is based on the ButtonImageGadget.
I used gradient colors for the button face to make it look cool.
There are no API calls used here, just native PureBasic code so it should work on all platforms.
I've only been able to test it on windows, my Linux pc died.

[EDIT1] added option to set text font.
[EDIT2] added option to disable gadget & major code rewrite.
[EDIT3] added option to use #PB_Ignore for many procedure parameters.
[EDIT4] fixed a bug with the disabled button colors

Save this with the name "ToggleButtonGadget.pbi"

Code: Select all

; ToggleButtonGadget.pbi
; by BasicallyPure 9.13.2012

;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;
; To use this custom gadget add the following line of code in your program.
; IncludeFile "ToggleButtonGadget.pbi"
;
; Syntax
; Result = ToggleButtonGadget(#Gadget, X, Y, Width, Height, TextOff$, [TextOn$], [State], [FontID])
;
; Description
; creates a custom toggle button with separate on/off colors and captions.
;
; #Gadget ---> Specifies a number to identify the new gadget. #PB_Any can be used.
; X, Y    ---> Specifies the position of the new gadget.
; Width   ---> Specifies the gadget width.
; Height  ---> Specifies the gadget height.
; TextOff$---> Specifies the gadget caption for the 'OFF' state.
; TextOn$ ---> (Optional) Specifies the gadget caption for the 'ON' state; default = TextOff$
; State   ---> (Optional) Specifies the initial gadget state, 0 = Off, 1 = On; default is 'OFF'.
; FontID  ---> (Optional) Specifies the font to use for the button text
;
; Return value >--- Returns nonzero on success And zero on failure. If #PB_Any was used
;   as the #Gadget parameter then the Return-value is the auto-generated gadget number.
;
; Use 'FlipButton(#Gadget)' in the event loop to toggle the button
;
; The following procedures can be used to control the gadget.
;
;     SetButtonText(#Gadget, OffText$, [OnText$])
;        ---> set the text To display in the 'On' And 'OFF' state; if OnText$ is not specified
;        then OnText$ is equal to OffText$.
;
;     SetButtonTextColor(#Gadget, OffTextColor, [OnTextColor])
;        ---> set button text color For On/Off States, #PB_Ignore can be used for either text color.
;             If OnTextColor is not specified then OnTextColor is equal to OffTextColor.
;
;     SetButtonColor(#Gadget, OffColor1, OffColor2, [OnColor1], [OnColor2])
;        ---> set the gradient colors for button On/Off states, #PB_Ignore can be used for any color.
;        If OnColor1 is not specified, OnColor1 is equal to OffColor1.
;        If OnColor2 is not specified, OnColor2 is equal to OffColor2.
;
;     GetButtonState(#Gadget) ---> Returns the toggle state of the button, 1 = 'ON', 0 = 'OFF'
;
;     GetButtonText(#Gadget, State) ---> Returns the button 'On' or 'Off' text.
;        if State = 0 the 'Off' text is returned; If State = 1 the 'On' text is returned.
;
;     DisableButton(#Gadget, State)
;        ---> Disable/Enable the button, (disable; State = 1), (enable; State = 0).
;
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

Structure TBtn
   Width.i     ; button width
   Height.i    ; button height
   OnText.s    ; caption for 'ON' state
   OffText.s   ; caption for 'OFF' state
   state.b     ; toggled on or off
   FontID.i    ; use this font for button caption
   OnC1.i      ; first color for 'ON' gradient
   OnC2.i      ; second color for 'ON' gradient
   OffC1.i     ; first color for 'OFF' gradient
   OffC2.i     ; second color for 'OFF' gradient
   OnTxtClr.i  ; 'ON' text color
   OffTxtClr.i ; "OFF' text color
   OnImage.i   ; image number for 'ON' state
   OffImage.i  ; image number for 'OFF' state
EndStructure

Dim ToggleButton.TBtn(0)

NewMap ButtonIndex() ; a Map to index ToggleButton() with gadget number

Declare BuildImage(ButtonNumber)

Macro CommonVariables
   Shared ToggleButton.TBtn() ; structured array
   Shared ButtonIndex() ; Map
   Protected ButtonNumber = ButtonIndex(Str(GadNum))
EndMacro

Procedure ToggleButtonGadget( GadNum, X, Y, Width, Height, TextOff.s, TextOn.s = "", State = 0, FontID = 0)
   ; create custom toggle button gadget
   
   Shared ToggleButton.TBtn() ; structured array
   Shared ButtonIndex() ; Map
   Static ButtonCount = 0
   
   ; default button colors
   Static OnC1  = $68FFFF ; gradient color 1 for 'ON' state
   Static OnC2  = $14FFC9 ; gradient color 2 for 'ON' state
   Static OffC1 = $C5B3A2 ; gradient color 1 for 'OFF' state
   Static OffC2 = $93765B ; gradient color 2 for 'OFF' state
   
   Protected ReturnValue, Image
   
   If X<0 Or Y<0 Or Width<1 Or Height<1 : ProcedureReturn 0 : EndIf
   
   If ButtonCount : ReDim ToggleButton.TBtn(ButtonCount) : EndIf
     
   If TextOn = "" : TextOn = TextOff : EndIf 
   
   With ToggleButton(ButtonCount)
      \Width     = Width
      \Height    = Height
      \OnText    = TextOn
      \OffText   = TextOff
      \state     = State
      \FontID    = FontID
      \OnC1      = OnC1
      \OnC2      = OnC2
      \OffC1     = OffC1
      \OffC2     = OffC2
      \OnTxtClr  = 0 ; Black by default
      \OffTxtClr = 0 ; Black by default
      \OnImage   = CreateImage(#PB_Any, Width, Height, 32)
      \OffImage  = CreateImage(#PB_Any, Width, Height, 32)
     
      If BuildImage(ButtonCount)
         ;
      Else
         ProcedureReturn #False
      EndIf
     
      If State & %01 : Image = \OnImage : Else : Image = \OffImage : EndIf
   EndWith
   
   If GadNum = #PB_Any
      ReturnValue = ButtonImageGadget(#PB_Any, X, Y, Width, Height, ImageID(Image))
      If ReturnValue
         SetGadgetAttribute(ReturnValue, #PB_Button_Image, ImageID(Image))
         ButtonIndex(Str(ReturnValue)) = ButtonCount
      EndIf
   Else
      ReturnValue = ButtonImageGadget(GadNum, X, Y, Width, Height, ImageID(Image))
      If ReturnValue
         SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(Image))
         ButtonIndex(Str(GadNum)) = ButtonCount
      EndIf
   EndIf
   
   If ReturnValue : ButtonCount + 1 : EndIf
   
   ProcedureReturn ReturnValue
EndProcedure

Procedure SetButtonText(GadNum, OffText.s, OnText.s = "")
   CommonVariables ; macro
   
   If OnText = "" : OnText = OffText : EndIf
   
   With ToggleButton(ButtonNumber)
      \OffText = OffText
      \OnText  =  OnText
     
      If BuildImage(ButtonNumber)
         If Not (\state & %01)
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OffImage))
         Else
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OnImage))
         EndIf
         ProcedureReturn #True
      Else
         ProcedureReturn #False
      EndIf
     
   EndWith
EndProcedure

Procedure.s GetButtonText(GadNum, State)
   CommonVariables ; macro
   If state = 0
      ProcedureReturn ToggleButton(ButtonNumber)\OffText
   Else
      ProcedureReturn ToggleButton(ButtonNumber)\OnText
   EndIf
EndProcedure

Procedure SetButtonTextColor(GadNum, OffTextColor, OnTextColor = -1)
   CommonVariables ; macro
   
   With ToggleButton(ButtonNumber)
      If OffTextColor <> #PB_Ignore : \OffTxtClr = OffTextColor : EndIf
      
      If OnTextColor = -1
         \OnTxtClr = \OffTxtClr
      ElseIf OnTextColor <> #PB_Ignore
         \OnTxtClr = OnTextColor
      EndIf
      
      If BuildImage(ButtonNumber)
         If Not (\state & %01)
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OffImage))
         Else
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OnImage))
         EndIf
         ProcedureReturn #True
      Else
         ProcedureReturn #False
      EndIf
   EndWith
EndProcedure

Procedure SetButtonColor(GadNum, OffColor1, OffColor2, OnColor1 = -1, OnColor2 = -1)
   CommonVariables ; macro
   
   With ToggleButton(ButtonNumber)
      If OffColor1 <> #PB_Ignore : \OffC1 = OffColor1 : EndIf
      If OffColor2 <> #PB_Ignore : \OffC2 = OffColor2 : EndIf
      
      If OnColor1 = -1
         \OnC1 = \OffC1
      ElseIf OnColor1 <> #PB_Ignore
         \OnC1 = OnColor1
      EndIf
      
      If OnColor2 = -1
         \OnC2 = \OffC2
      ElseIf OnColor2 <> #PB_Ignore
         \OnC2 = OnColor2
      EndIf
      
      If BuildImage(ButtonNumber)
         If \state & %01
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OnImage))
         Else
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OffImage))
         EndIf
         ProcedureReturn #True
      Else
         ProcedureReturn #False
      EndIf
   EndWith
EndProcedure

Procedure SetButtonState(GadNum, state)
   CommonVariables ; macro
   
   With ToggleButton(ButtonNumber)
      If state ; turn on
         SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OnImage))
         \state = (\state & %10) | %01
      Else ; turn off
         SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OffImage))
         \state = \state & %10
      EndIf
   EndWith
   
EndProcedure

Procedure GetButtonState(GadNum)
   CommonVariables ; macro
   ProcedureReturn ToggleButton(ButtonNumber)\state & %01
EndProcedure

Procedure DisableButton(GadNum, Disable)
   CommonVariables ; macro
   
   With ToggleButton(ButtonNumber)
      If Disable
         \state | %10
         DisableGadget(GadNum, 1)
      Else
         \state & %01
         DisableGadget(GadNum, 0)
      EndIf
     
      If BuildImage(ButtonNumber)
         If \state & %01
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OnImage))
         Else
            SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OffImage))
         EndIf
         ProcedureReturn #True
      Else
         ProcedureReturn #False
      EndIf
     
   EndWith
EndProcedure

Procedure BuildImage(ButtonNumber)
   Shared ToggleButton.TBtn() ; structured array
   
   Static DisabledTextColor = $D0D0D0
   Static DisabledC1 = $A0A0A0
   Static DisabledC2 = $808080
   
   Protected Image, C1, C2, Tx, Ty, Text.s, TextColor
   
   With ToggleButton(ButtonNumber)
     
      Image = \OnImage
      Text = \OnText
      If \state & %10 ; use disabled colors
         C1 = DisabledC1
         C2 = DisabledC2
         TextColor = DisabledTextColor
      Else ; use normal colors
         C1 = \OnC1
         C2 = \OnC2
         TextColor = \OnTxtClr
      EndIf
      
      Repeat
         If StartDrawing(ImageOutput(Image))
           
            ; draw button face
            DrawingMode(#PB_2DDrawing_Gradient)
            FrontColor(C1) : BackColor(C2)
            LinearGradient(0, \Height, 0, 0)
            Box(0, 0, \Width, \Height)
            
            ; draw caption
            If \FontID : DrawingFont(\FontID) : EndIf
            DrawingMode(#PB_2DDrawing_Transparent)
            FrontColor(TextColor)
            Ty = (\Height - TextHeight(Text)) / 2
            Tx = (\Width  - TextWidth(Text)) / 2
            DrawText(Tx, Ty, Text)
            
            StopDrawing()
         Else
            ProcedureReturn #False
         EndIf
         
         If Image = \OffImage
            Break
         EndIf
         
         Image = \OffImage
         Text = \OffText
         
         If \state & %10 = 0
            TextColor = \OFFTxtClr
            C1 = \OffC1
            C2 = \OffC2
         EndIf
         
      ForEver
   EndWith
   
   ProcedureReturn #True
EndProcedure

Procedure FlipButton(GadNum)
   CommonVariables ; macro
   
   With ToggleButton(ButtonNumber)
      If \state & %01
         \state & %10
         SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OffImage))
      Else
         \state | %01
         SetGadgetAttribute(GadNum, #PB_Button_Image, ImageID(\OnImage))
      EndIf
   EndWith
EndProcedure
Last edited by BasicallyPure on Thu Sep 13, 2012 3:06 pm, edited 10 times in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: ToggleButtonGadget

Post by BasicallyPure »

Here is an example.

Code: Select all

;ToggleButtonTest.pb

EnableExplicit

IncludeFile "ToggleButtonGadget.pbi"

Declare Verify(Result, text.s)

Verify(ExamineDesktops(), "ExamineDesktops")

; constants
#PrimaryMonitor = 0
#MenuItemExit = 0

;variables
Global Quit
Define Event, Gadget, MainWin, MainMenu, ButtonExit
Define ButtonOne, ButtonTwo, ButtonThree, ButtonFour, ButtonFive
Define BtnW = 90, BtnH = 30
Define WinWidth  = DesktopWidth(#PrimaryMonitor) / 2
Define WinHeight = DesktopHeight(#PrimaryMonitor) / 2 + MenuHeight()

Define Flags = #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget
Define Text.s = "ToggleButtonGadget Demo"

MainWin  = Verify(OpenWindow(#PB_Any, 0, 0, WinWidth, WinHeight, Text, Flags), "OpenWindow")
SetWindowColor(MainWin, $C5B2A1)

MainMenu = Verify(CreateMenu(#PB_Any, WindowID(MainWin)), "CreateMenu")
MenuTitle("File")
MenuItem(#MenuItemExit, "Exit")

Define MyFont = FontID(LoadFont(#PB_Any,"Bookman Old Style",14))

; ******* create custom toggle buttons *******

Define BtnX = 20, BtnY = 20 ;locate the first button
ButtonOne = ToggleButtonGadget(#PB_Any, BtnX, BtnY, BtnW, BtnH, "Btn 1 Off", "Btn 1 On")
DisableButton(ButtonOne, 1)

BtnY + 50
ButtonTwo = ToggleButtonGadget(#PB_Any, BtnX, BtnY, BtnW, BtnH, "Enable 1", "Disable 1")
SetButtonColor(ButtonTwo, #PB_Ignore, #PB_Ignore)

BtnY + 50
ButtonThree = ToggleButtonGadget(#PB_Any, BtnX, BtnY, BtnW+50, BtnH+10, "Move 1 right", "Move 1 left", 0, MyFont)
SetButtonTextColor(ButtonThree, $FF0000) ;change text color
SetButtonColor(ButtonThree, $1A0DEA, $E5F29F, $E5F29F, $1A0DEA) ;change the button colors

BtnY + 60
ButtonFour = ToggleButtonGadget(#PB_Any, BtnX, BtnY, BtnW, BtnH, "Four Off", "Four On")
SetButtonColor(ButtonFour, $ADADAB, $5E5F5F, $30E02B, $30702B) ;change the button colors

BtnY + 50
ButtonFive = ToggleButtonGadget(#PB_Any, BtnX, BtnY, BtnW, BtnH, "Flip 4")
SetButtonColor(ButtonFive, #PB_Ignore, #PB_Ignore)
SetButtonTextColor(ButtonFive, #PB_Ignore, $FFFFFF)

; ********************************************

Repeat ;event loop
   Event = WaitWindowEvent()
   
   Select Event
      Case #PB_Event_CloseWindow
         Quit = #True
         
      Case #PB_Event_Menu
         Select EventMenu()
            Case #MenuItemExit
               Quit = #True
         EndSelect
         
      Case #PB_Event_Gadget
         Gadget = EventGadget()
         Select Gadget
            Case ButtonOne
               FlipButton(Gadget) ;call this procedure for every custom toggle button
               
            Case ButtonTwo
               FlipButton(Gadget)
               If GetButtonState(Gadget)
                  DisableButton(ButtonOne, 0)
               Else
                  DisableButton(ButtonOne, 1)
               EndIf
               
            Case ButtonThree
               FlipButton(Gadget)
               If GetButtonState(Gadget)
                  ResizeGadget(ButtonOne, BtnX + 100, #PB_Ignore, #PB_Ignore, #PB_Ignore)
               Else 
                  ResizeGadget(ButtonOne, BtnX, #PB_Ignore, #PB_Ignore, #PB_Ignore)
               EndIf
               
            Case ButtonFour
               FlipButton(Gadget)
               
            Case ButtonFive
               FlipButton(Gadget)
               FlipButton(ButtonFour)
               
         EndSelect
   EndSelect
   
Until Quit

End

Procedure Verify(result, text.s)
   ;display message and terminate on error
   If result = 0
      MessageRequester("Error!", text + " failed to initalize")
      Quit = #True
   EndIf
   ProcedureReturn result
EndProcedure
Last edited by BasicallyPure on Thu Sep 13, 2012 3:23 am, edited 5 times in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 794
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: ToggleButtonGadget

Post by Zebuddi123 »

Thank you BasicallyPure nice !!!

Zebuddi :D .
malleo, caput, bang. Ego, comprehendunt in tempore
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: ToggleButtonGadget

Post by IdeasVacuum »

Very neat solution, thanks for sharing 8)
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: ToggleButtonGadget

Post by rsts »

IdeasVacuum wrote:Very neat solution, thanks for sharing 8)
+ 1

Nice one.
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: ToggleButtonGadget

Post by BasicallyPure »

Update: I have add the 'DisableButton' option, also did a major rewrite of the code.

I should point out that if you don't need a toggle button it can be used just like a regular button.
Just omit the 'FlipButton(#Gadget)' from your event loop and you have a regular button but you can still
set the color of the button face and caption text.

B.P.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: ToggleButtonGadget

Post by Kwai chang caine »

A "little bit" late, i don't see this thread in 2012 :oops:
Very very nice buttons
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
doctorized
Addict
Addict
Posts: 854
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: ToggleButtonGadget

Post by doctorized »

Is there a way to add multiline support?
Post Reply