[MSW] CommandLinkButton Gadget (Updated!)

Share your advanced PureBasic knowledge/code with the community.
Env
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 27, 2010 3:20 pm
Location: Wales, United Kingdom

[MSW] CommandLinkButton Gadget (Updated!)

Post by Env »

Hey there,

Here's a little piece of code that enables the user to create a CommandLink style Button for Windows operating systems (Vista and above). If the OS doesn't support the control, it will fall back and create a ButtonGadget with tooltip.

Preview
Image
  • Support Ansi/Unicode build. (Converts string automatically)
  • Fallback for non-compliant operating systems/OS versions.
  • Handles events like a normal ButtonGadget.
  • Supports #PB_Any parameter.
New Features
  • Apply custom icons to the buttons.
  • Enable/disable shield icon.
  • Set the appearance to look like a default button.
Code

Code: Select all

;------------------------------------------------------------------------------------------
; Title:        CommandLinkButton Implementation
; Description:  Provides access to the Command Link Button on Windows Systems (Vista+)
; Author(s):    Michael R. King (mrking2910@gmail.com)
; Revision:     6 April 2012
; Notes:        Will fall back to a ButtonGadget with ToolTip if control not available.
;------------------------------------------------------------------------------------------

; - Required Constants -
CompilerIf Defined(BCM_FIRST, #PB_Constant) = #False
    #BCM_FIRST = $1600
CompilerEndIf
CompilerIf Defined(BCM_SETNOTE, #PB_Constant) = #False
    #BCM_SETNOTE = (#BCM_FIRST + $0009)
CompilerEndIf
CompilerIf Defined(BCM_SETSHIELD , #PB_Constant) = #False
    #BCM_SETSHIELD = (#BCM_FIRST + $000C)
CompilerEndIf
CompilerIf Defined(BS_COMMANDLINK, #PB_Constant) = #False
    #BS_COMMANDLINK = $0000000E
    #BS_DEFCOMMANDLINK = $000000F
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    If OSVersion() > #PB_OS_Windows_XP
        #PB_CommandLink_Available = #True
    EndIf
CompilerEndIf
CompilerIf Defined(PB_CommandLink_Available, #PB_Constant) = #False
    #PB_CommandLink_Available = #False
CompilerEndIf

; - Creation Procedure -
Procedure CommandLinkButton(Gadget, X, Y, Width, Height, Text$, Note$ = "", MakeDefault = #False)
    Protected sNote.s
    Protected retVal
    CompilerIf #PB_CommandLink_Available = #True
        CompilerIf #PB_Compiler_Unicode = #False
            sNote = Space(255)
            MultiByteToWideChar_ ( #CP_ACP, 0, @Note$, Len(Note$), @sNote, Len(sNote)) 
            PokeL( @sNote + Len(Note$) * 2, 0)
        CompilerElse
            sNote = Note$
        CompilerEndIf
        If MakeDefault
            retVal = ButtonGadget(Gadget, X, Y, Width, Height, Text$, #BS_DEFCOMMANDLINK)
        Else
            retVal = ButtonGadget(Gadget, X, Y, Width, Height, Text$, #BS_COMMANDLINK)
        EndIf            
        If Gadget = #PB_Any
            SendMessage_(GadgetID(retVal), #BCM_SETNOTE, 0, @sNote)    
        Else
            SendMessage_(GadgetID(Gadget), #BCM_SETNOTE, 0, @sNote)
        EndIf
        ProcedureReturn retVal
    CompilerElse
        retVal = ButtonGadget(Gadget, X, Y, Width, Height, Text$)
        If Gadget = #PB_Any
            GadgetToolTip(retVal, Note$)
        Else
            GadgetToolTip(Gadget, Note$)
        EndIf
        ProcedureReturn retVal
    CompilerEndIf
EndProcedure

; - Personalisation Procedures -
Procedure SetCommandLinkIcon(Gadget, *ImageID)
    CompilerIf #PB_CommandLink_Available
        If IsGadget(Gadget)
            SendMessage_(GadgetID(Gadget), #BM_SETIMAGE, #Null, *ImageID)
        EndIf
    CompilerEndIf
EndProcedure

Procedure SetCommandLinkShield(Gadget, Enable = #True)
    CompilerIf #PB_CommandLink_Available
        If IsGadget(Gadget)
            SendMessage_(GadgetID(Gadget), #BCM_SETSHIELD, #Null, Enable)
        EndIf
    CompilerEndIf
EndProcedure

; ---- EXAMPLE ----

; - Initialise Decoders -
UsePNGImageDecoder()

; - Open Window
OpenWindow(0, 0, 0, 790, 150, "Command Link Button Test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)

; - Load Some Icons -
Define icon = LoadImage(#PB_Any, "J:\C++ Development\Resources\Icons\crystal_project\16x16\apps\amor.png")

; - Create Gadgets -
Define btnGadget = CommandLinkButton(#PB_Any, 10, 10, 380, 60, "Command Link Button", "Just an Example")
Define btnGadget2 = CommandLinkButton(#PB_Any, 10, 80, 380, 60, "Command Link Button", "With custom icon!")
Define btnGadget3 = CommandLinkButton(#PB_Any, 400, 10, 380, 60, "Command Link Button", "With 'MakeDefault' set to #True!", #True)
Define btnGadget4 = CommandLinkButton(#PB_Any, 400, 80, 380, 60, "Command Link Button", "With a Shield!")

; - Personalise Gadgets -
SetCommandLinkIcon(btnGadget2, ImageID(icon))
SetCommandLinkShield(btnGadget4, #True)

Repeat
    Select WindowEvent()
        Case #PB_Event_CloseWindow
            End
        Case #PB_Event_Gadget
            Select EventGadget()
                Case btnGadget
                    Debug "Pressed!"
            EndSelect
    EndSelect
ForEver
Note: It is highly recommended this gadget has a minimum height of 60 pixels.

Todo
  • Implement procedure to change text margins.
  • Detect version of CommCtrl32.dll to ensure it can support this control style. (Any suggestions would be grand!)
Thanks!
Last edited by Env on Fri Apr 06, 2012 11:24 am, edited 2 times in total.
Thanks!
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: [MSW] CommandLinkButton Gadget

Post by Kwai chang caine »

Just for information on VISTA, when i run the code i have a empty window
When i click a checkBox appear, and the debbuger write pressed.
No ToolTips too, apparently...
ImageThe happiness is a road...
Not a destination
Env
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 27, 2010 3:20 pm
Location: Wales, United Kingdom

Re: [MSW] CommandLinkButton Gadget

Post by Env »

... Bugger. Hmmm, I'll have to investigate that when I get home.

Thanks for the feedback :)
Thanks!
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: [MSW] CommandLinkButton Gadget

Post by c4s »

I currently don't have Vista to test but here is another implementation of the CommandLinkButton. It doesn't have all the fallbacks though: http://www.purebasic.fr/english/viewtop ... 12&t=40157
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Env
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 27, 2010 3:20 pm
Location: Wales, United Kingdom

Re: [MSW] CommandLinkButton Gadget

Post by Env »

@c4s - Funnily enough, I stumbled across that code about 10 minutes ago whilst researching more on the control style. There is no significant difference between that implementation and the one here though :?

@Kwai - I suspect it's down to the manifest the compiler is putting into the EXE... It has to specify 'Commctrl' 6.0 and above, so can I ask what version of the compiler you are using?


More features and what not to follow very soon!
Thanks!
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: [MSW] CommandLinkButton Gadget

Post by Kwai chang caine »

I have try with PB v4.51 :oops:
With XP i have a button and ToolTips, but i believe it's normal, because you say your code is for VISTA :wink:
ImageThe happiness is a road...
Not a destination
Env
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 27, 2010 3:20 pm
Location: Wales, United Kingdom

Re: [MSW] CommandLinkButton Gadget

Post by Env »

@Kwai - It must be to do with your version of CommCtrl then. I'll look into creating a way for the snippet to check to see the version of this library to prevent this problem. Thanks again for your feedback :)
Thanks!
Env
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 27, 2010 3:20 pm
Location: Wales, United Kingdom

Re: [MSW] CommandLinkButton Gadget (Updated!)

Post by Env »

Bit of an update to the snippet... More ability to personalise the buttons with icons, shields, default style. Have yet to find a solution to checking to ensure the version of CommCtrl32.dll is the correct version to support this style (any suggestions would be highly appreciated).

Preview
Image

Check first post for latest revision.

Enjoy!
Thanks!
criobot
User
User
Posts: 10
Joined: Sat Dec 27, 2008 9:42 pm
Location: Bulgaria
Contact:

Re: [MSW] CommandLinkButton Gadget (Updated!)

Post by criobot »

Thanks for that example. Below is a snippet which should help you get Comctl32's version. Many windows dlls have the DLLGetVersion function. :)

Code: Select all

dvi.DLLVERSIONINFO
    
    
    Library = OpenLibrary(#PB_Any, "Comctl32.dll")
    If IsLibrary(Library)
        
        dvi\cbSize = SizeOf(DLLVERSIONINFO)
         CallFunction(Library, "DllGetVersion", @dvi )
         
         Debug dvi\dwMajorVersion
         Debug dvi\dwMinorVersion
         Debug dvi\dwBuildNumber
         CloseLibrary(Library)
    EndIf
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: [MSW] CommandLinkButton Gadget (Updated!)

Post by SFSxOI »

Looks very nice....but do you mean true "Command Link" buttons in terms of Vista and above windows UI environment like with TaskDialog?
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Env
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 27, 2010 3:20 pm
Location: Wales, United Kingdom

Re: [MSW] CommandLinkButton Gadget (Updated!)

Post by Env »

@criobot - Thanks :) , When i get home tomorrow or sunday I'll give it a go!

@SFS - Yep
Thanks!
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: [MSW] CommandLinkButton Gadget (Updated!)

Post by SFSxOI »

Ok, thanks. I asked because of the use of the "icon" in the form of the .png.

It threw me off some when I saw the use of a .png. I'd never seen anyone use a .png on a command link button before, i wasn't aware that an icon could be put on a real command link button. When I get back to work Monday i'm going to ask our resident MS rep about how this is done, i'm interested in experimenting some with using different icons and .png's (I have a collection of icons in .png format i'd like to use on task dialogs) on the buttons in a Task Dialog so you bought up an interesting point for me as I use task dialogs a lot.

Good job though.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
bobobo
Enthusiast
Enthusiast
Posts: 206
Joined: Mon Jun 09, 2003 8:30 am

Re: [MSW] CommandLinkButton Gadget (Updated!)

Post by bobobo »

when running on win-xp it results in not button at all
this part wil set #PB_CommandLink_Available to #True
in either case. so no fallback

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    If OSVersion() > #PB_OS_Windows_XP
        #PB_CommandLink_Available = #True
    EndIf
CompilerEndIf
debug #PB_CommandLink_Available
i've made a version with variables that works under XP

Code: Select all

;------------------------------------------------------------------------------------------
; Title:        CommandLinkButton Implementation
; Description:  Provides access to the Command Link Button on Windows Systems (Vista+)
; Author(s):    Michael R. King (mrking2910@gmail.com) (tuned by bobobo)
; Revision:     6 April 2012
; Notes:        Will fall back to a ButtonGadget with ToolTip if control not available.
;------------------------------------------------------------------------------------------

; - Required Constants -

Global  PB_CommandLink_Available
If #PB_Compiler_OS = #PB_OS_Windows
  If OSVersion()>#PB_OS_Windows_XP
    PB_CommandLink_Available=#True
  Else
    PB_CommandLink_Available=#False
  EndIf
  
  CompilerIf Defined(BCM_FIRST, #PB_Constant) = #False
    #BCM_FIRST = $1600
  CompilerEndIf
  
  CompilerIf Defined(BCM_SETNOTE, #PB_Constant) = #False
    #BCM_SETNOTE = (#BCM_FIRST + $0009)
  CompilerEndIf
  
  CompilerIf Defined(BCM_SETSHIELD , #PB_Constant) = #False
    #BCM_SETSHIELD = (#BCM_FIRST + $000C)
  CompilerEndIf
  
  CompilerIf Defined(BS_COMMANDLINK, #PB_Constant) = #False
    #BS_COMMANDLINK = $0000000E
    #BS_DEFCOMMANDLINK = $000000F
  CompilerEndIf
  
Else
  ;No Windows no buttons
  End
EndIf

; - Creation Procedure -
Procedure CommandLinkButton(Gadget, X, Y, Width, Height, Text$, Note$ = "", MakeDefault = #False)
    Protected sNote.s
    Protected retVal
    If PB_CommandLink_Available = #True
        CompilerIf #PB_Compiler_Unicode = #False
            sNote = Space(255)
            MultiByteToWideChar_ ( #CP_ACP, 0, @Note$, Len(Note$), @sNote, Len(sNote)) 
            PokeL( @sNote + Len(Note$) * 2, 0)
        CompilerElse
            sNote = Note$
        CompilerEndIf
        If MakeDefault
            retVal = ButtonGadget(Gadget, X, Y, Width, Height, Text$, #BS_DEFCOMMANDLINK)
        Else
            retVal = ButtonGadget(Gadget, X, Y, Width, Height, Text$, #BS_COMMANDLINK)
        EndIf            
        If Gadget = #PB_Any
            SendMessage_(GadgetID(retVal), #BCM_SETNOTE, 0, @sNote)    
        Else
            SendMessage_(GadgetID(Gadget), #BCM_SETNOTE, 0, @sNote)
        EndIf
        ProcedureReturn retVal
    Else
        retVal = ButtonGadget(Gadget, X, Y, Width, Height, Text$)
        If Gadget = #PB_Any
            GadgetToolTip(retVal, Note$)
        Else
            GadgetToolTip(Gadget, Note$)
        EndIf
        ProcedureReturn retVal
    EndIf
EndProcedure

; - Personalisation Procedures -
Procedure SetCommandLinkIcon(Gadget, *ImageID)
    If PB_CommandLink_Available
        If IsGadget(Gadget)
            SendMessage_(GadgetID(Gadget), #BM_SETIMAGE, #Null, *ImageID)
        EndIf
    EndIf
EndProcedure

Procedure SetCommandLinkShield(Gadget, Enable = #True)
    If PB_CommandLink_Available
        If IsGadget(Gadget)
            SendMessage_(GadgetID(Gadget), #BCM_SETSHIELD, #Null, Enable)
        EndIf
    EndIf
EndProcedure

; ---- EXAMPLE ----

; - Initialise Decoders -
UsePNGImageDecoder()

; - Open Window
OpenWindow(0, 0, 0, 790, 150, "Command Link Button Test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)

; - Load Some Icons -
Define icon = LoadImage(#PB_Any, "D:\.....whatever.PNG")

; - Create Gadgets -
Define btnGadget = CommandLinkButton(#PB_Any, 10, 10, 380, 60, "Command Link Button", "Just an Example")
Define btnGadget2 = CommandLinkButton(#PB_Any, 10, 80, 380, 60, "Command Link Button", "With custom icon!")
Define btnGadget3 = CommandLinkButton(#PB_Any, 400, 10, 380, 60, "Command Link Button", "With 'MakeDefault' set to #True!", #True)
Define btnGadget4 = CommandLinkButton(#PB_Any, 400, 80, 380, 60, "Command Link Button", "With a Shield!")

; - Personalise Gadgets -
SetCommandLinkIcon(btnGadget2, ImageID(icon))
SetCommandLinkShield(btnGadget4, #True)

Repeat
    Select WindowEvent()
        Case #PB_Event_CloseWindow
            End
        Case #PB_Event_Gadget
            Select EventGadget()
                Case btnGadget
                    Debug "Pressed!"
            EndSelect
    EndSelect
ForEver
사십 둘 .
Post Reply