Results 1 to 11 of 11

Thread: Grdient Button

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2002
    Posts
    481

    Grdient Button

    Hello Group,

    Using vbRichClient I want to simply fill a picturebox with a themed color and create a modern looking button based on a theme color. SO the fill will have shades of that color as a gradient.

    What is the easiest way to do this with vbrichlient cairo engine? Is thera another way?

    I am currently just rendering the button using a jpg like the one attached, but need to make the color configurable.

    Name:  gradient48x48.bmp
Views: 430
Size:  6.8 KB

    WP

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Grdient Button

    "Modern looking???"

    I think the word is "gauche and non-Windows looking."

  3. #3
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Grdient Button

    BTW Cairo-Gradients are explained (linear and radial ones) in detail in the Cairo-Tutorial -
    (where they reside in a dedicated Project in a separate SubFolder).

    But well, a "boiled down" version for first experiments would be (starting with an empty VB-Project and an empty Form1)...

    Every Drawing-Op in Cairo needs a "Surface" first, here's what I often do for a fast test, to visualize such a Surface in the Form.Picture:
    Code:
    Private Sub Form_Load()
      Set Me.Picture = CreateButtonSurface(150, 30).Picture
    End Sub
    The above assuming, that the CreateButtonSurface-Function will create and return a cCairoSurface-Object
    (which in turn can hand-out also a normal VB-StdPicture-Object, above placed in the Forms "Me.Picture"-Prop).

    Ok, here's the Function, which creates this Surface-Object
    (not drawing anything so far, so you will see only a black Rectangle, in the above given Surface-Dimensions of 150x30 Pixels).

    Code:
    Function CreateButtonSurface(dx, dy) As cCairoSurface
      Dim Srf As cCairoSurface
      Set Srf = Cairo.CreateSurface(dx, dy)
      
          '...draw something on the Cairo-Surface
          
      Set CreateButtonSurface = Srf 'return the Surface-Object
    End Function
    With that little "Base-Setup" in your Form, you can now add a Sub-Routine (or two) below the Comment-Line,
    as e.g. one, that is added and called this way from within the above Function:
    Code:
          '...draw something on the Cairo-Surface
          DrawButtonFace Srf.CreateContext
    Note, that Cairo-Drawing needs to happen on a so called "Cairo-Context"-Object,
    which any Surface will happily provide at any time, per oSurface.CreateContext (as the above line shows).

    Within the Drawing-Functions of most of the RichClient-Demos, I use CC as the Parameter-Name of the ContextObject -
    so the SubRoutine we already named above could look this way:

    Code:
    Sub DrawButtonFace(CC As cCairoContext)
      Dim Pat As cCairoPattern 'to draw Gradients, we need a cCairoPattern-Type
      'create and set up a linear Gradient (using X0,Y0 and X1,Y1 to describe its direction)
      Set Pat = Cairo.CreateLinearPattern(0, 0, 0, CC.Surface.Height)
          Pat.AddColorStop 0, vbBlue
          Pat.AddColorStop 1, vbBlack
      'render the Pattern
      CC.Paint 1, Pat '<- the first Parameter '1' is an Alpha-Value
    End Sub
    Putting all of the above together, you will end up with this:


    Olaf

  4. #4

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2002
    Posts
    481

    Re: Grdient Button

    Thanks Olaf,

    Looking at the tutorials, I thought this would be the approach, I just wanted to make sure. I just was not sure about the first part 'CreateButtonSurface'

    Thanks for the detailed help

    WP

  5. #5
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Grdient Button

    Quote Originally Posted by axisdj View Post
    Looking at the tutorials, I thought this would be the approach, I just wanted to make sure. I just was not sure about the first part 'CreateButtonSurface'
    Ok - you can alternatively make use of the built-in Cairo-Theme-Engine of course, which already encapsulates
    a whole lot of GUI-rendering-tasks (for Button-Faces, ScrollBar-Faces, ProgressBar-Faces, etc.)

    Here the basic-construct from above again, this time with a Cairo-themed Button-Rendering-Routine:
    Code:
    Option Explicit
    
    Private W As cWidgetBase 'we need a cWidgetBase, to make use of the Theme-Engine...
    
    Private Sub Form_Load()
      Set W = Cairo.WidgetBase '<- and so we instantiate it here with Form-wide scope
     
      Set Me.Picture = CreateButtonSurface(150, 30).Picture
    End Sub
    
    Function CreateButtonSurface(dx, dy) As cCairoSurface
      Dim Srf As cCairoSurface
      Set Srf = Cairo.CreateSurface(dx, dy)
      
          '...draw something on the Cairo-Surface
          DrawThemedButtonFace Srf.CreateContext, dx, dy 'use the default-theme-color (leaving out the optional BackColor-Param)
    
      Set CreateButtonSurface = Srf 'return the Surface-Object
    End Function
     
    Sub DrawThemedButtonFace(CC As cCairoContext, dx, dy, _
                              Optional ByVal BackColor As Long = -1, _
                              Optional ByVal State As enmThemeDrawingState, _
                              Optional ByVal Radius As Double)
      With Cairo.Theme '<- let's make use of the Cairo-Theme-Engine
        W.BackColor = IIf(BackColor = -1, .GetThemeColor(thmBackColor), BackColor) 'override the the default-Theme-BC if needed
        
        .DrawTo CC, W, thmTypeButtonFace, State, 0, 0, dx, dy, Radius 'render the themed Button-Face
     
        CC.SetLineWidth 1 'finally draw a themed Border with LineWidth=1
        .DrawTo CC, W, thmTypeBorder, State, 0, 0, dx, dy, Radius
      End With
    End Sub
    The above default-Cairo-theme (with thmTypeButtonFace) produces this output:


    The Theme-Eingine is overridable of course (with your own "general ideas") - but it is also flexible enough,
    to allow "individual exceptions" (whilst keeping up the general "rendering-idea").

    To check-out what I mean, you could call the above DrawThemedButtonFace with these alternatives:
    Code:
          ' individual (the theme-color-ignoring) BackColor-overrides can be done this way
          DrawThemedButtonFace Srf.CreateContext, dx, dy, RGB(77, 244, 77) 'light green
    '      DrawThemedButtonFace Srf.CreateContext, dx, dy, RGB(244, 244, 77) 'light yellow
    '      DrawThemedButtonFace Srf.CreateContext, dx, dy, RGB(244, 77, 244) 'light magenta
    The above Line which I've left uncommented draws the themed ButtonFace in a light-green then:


    But once you work at that level alread - the question arises, why you want to render your Button-Ctl
    in a VB.PictureBox... - instead of directly implementing a true Cairo-Widget-Ctl (using less code).

    Olaf

  6. #6

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2002
    Posts
    481

    Re: Grdient Button

    There ya go, now you are talking... THANK you!

  7. #7
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Grdient Button

    Quote Originally Posted by axisdj View Post
    There ya go, now you are talking... THANK you!
    That still leaves my question unanswered, why you want to make your own Button.

    Whilst nice Button-Faces are easy to draw with Cairo, one tends to
    forget a whole lot of other things we'd expect from a proper Button-Ctl as e.g.:
    - correct behaviour with Tabbing
    - Focus-Visualizing
    - Button-Caption definable Access-Keys (as e.g. with "&The Caption")
    - Button- Default and Cancel-Properties, which raise the Click-Event, when Return or Esc is pressed
    - Click-Event-Raising when Focused and the Space-Key is pressed
    - proper Button-Image-Rendering

    If you want to implement all that yourself, you will basically end up with the same Code,
    which exists already encapsulated within the vbWidgets-Project.

    Below some Form-Code, which shows how "visually adaptable" the cwButton-Widget-Implementation is.

    To work with RC5-Cairo-Widgets on a normal VB-Form (interacting with "old" VB-Controls on that Form),
    one has to add a normal "StdExe-Project-Private-UserControl" first, which I usually name 'ucPanel':
    Code:
    Option Explicit 'just a generic Helper-Control, to make Cairo-Widgets usable on normal VB-Forms
     
    Public Root As cWidgetRoot
     
    Public Property Get Widgets() As cWidgets
      If Root Is Nothing Then Set Root = Cairo.WidgetRoot: Root.RenderContentIn Me
      Set Widgets = Root.Widgets
    End Property
     
    Private Sub UserControl_Show()
      If Not Root Is Nothing Then Root.Widget.Refresh
    End Sub
    
    Public Sub Cleanup()
      If Not Root Is Nothing Then Root.Widgets.RemoveAll: Root.Disconnect
    End Sub
    The above will allow us, to add Cairo-Widgets to it, which you can of course implement yourself
    (in your own cwClasses), or you make use of the already implemented ones of vbWidgets.dll.

    As said, the following Form-Code demonstrates the cwButton-Widget in action:
    (your Test-Project will need references to vbRichClient5 and vbWidgets) - and the above 'ucPanel' as a UserControl-Module)
    Code:
    Option Explicit
     
    Private WithEvents B1 As cwButton, WithEvents B2 As cwButton, WithEvents B3 As cwButton
    
    Private Sub Form_Load()
      Cairo.ImageList.AddIconFromResourceFile "icoB3", "shell32.dll", 167, 48, 48
     
      Set B1 = ucPanel1.Widgets.Add(New cwButton, "B1", 20, 15, 145, 27)
          B1.Caption = "&Normal with Image"
          B1.Widget.ImageKey = "icoB3"
          
      Set B2 = ucPanel1.Widgets.Add(New cwButton, "B2", 20, 55, 90, 27)
          B2.Caption = "&Rectangular"
          B2.BorderRadius = 0
          B2.Widget.BackColor = vbYellow
          
      Set B3 = ucPanel1.Widgets.Add(New cwButton, "B3", 20, 95, 65, 65)
          B3.Caption = "&Circular"
          B3.BorderRadius = B3.Widget.Height / 2
          B3.Widget.BackColor = vbMagenta
    End Sub
    
    Private Sub B1_Click()
      MsgBox "Hello From Button1"
    End Sub
    Private Sub B2_Click()
      MsgBox "Hello From Button2"
    End Sub
    Private Sub B3_Click()
      MsgBox "Hello From Button3"
    End Sub
    
    Private Sub Form_Resize() 'resize the Panel to cover the entire Form
      ucPanel1.Move 0, 0, ScaleWidth, ScaleHeight
    End Sub
    
    Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
      ucPanel1.Cleanup 'cleanup the Panel and its Widgets
    End Sub
    
    Private Sub Form_Terminate()
      If Forms.Count = 0 Then New_c.CleanupRichClientDll 'cleanup the RC5-lib when the App terminates
    End Sub


    Olaf

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2002
    Posts
    481

    Re: Grdient Button

    Ok got that working, but the gradient does not seem apparent enough on certain colors... is there a way to amplify the effect?

    Also I need to print text on button, is there an auto align way of doing that?

    I will look at the example in tutorial, but I thought I would ask here.. sorry it must appear im a bit lazy.

  9. #9

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2002
    Posts
    481

    Re: Grdient Button

    "That still leaves my question unanswered, why you want to make your own Button."

    To answer your question was using pictureBoxes for all my buttons .. so changing them out may not be an issue. I was just thinking of the safest path for now.

    So.. yes I may want to change them out, but it is hundreds of buttons, so for now I would just like the cairo to aid in drawing the gradient and maybe text on top.

    Next rev and future buttons will use the cwButton.

    WP

  10. #10
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Grdient Button

    Quote Originally Posted by axisdj View Post
    Ok got that working, but the gradient does not seem apparent enough on certain colors... is there a way to amplify the effect?
    You can implement your own Cairo-Theme-Override (for thmTypeButtonFace) quite easily (using the Power of VBs Implements-Keyword).

    For that you will need a new cMyTheme Class in your Project, with the following Content:
    Code:
    Option Explicit
    
    Private TOrig As cTheme, MyThemeColorArray(0 To 6) As Long, i As Long
    
    Implements cTheme
     
    Private Sub Class_Initialize()
      Set TOrig = New vbWidgets.cThemeWin7 'store the original vbWidgets-Theme-Instance in TOrig
      
      'here you can override the default-Widget-Colors - and the Demo shows a "dark-Theme"
      '(the originally implemented Theme-Color-Values are commented out)
      MyThemeColorArray(thmBackColor) = &H444444 'RGB(235, 235, 235)
      MyThemeColorArray(thmForeColor) = vbYellow 'RGB(30, 30, 30)
      MyThemeColorArray(thmBorderColor) = vbWhite ' RGB(103, 103, 98)
      MyThemeColorArray(thmHoverColor) = vbGreen ' RGB(190, 228, 255)
      MyThemeColorArray(thmFocusColor) = vbMagenta ' RGB(0, 140, 195)
      MyThemeColorArray(thmSelectionColor) = vbYellow ' RGB(178, 214, 255)
      MyThemeColorArray(thmDisabledColor) = &HCCCCCC ' RGB(166, 166, 166)
    End Sub
    
    'Overrides for 3 of the Methods of the original Implementation
    Private Sub cTheme_DrawTo(CC As cCairoContext, W As cWidgetBase, ByVal What As enmThemeDrawingType, ByVal State As enmThemeDrawingState, ByVal x As Double, ByVal y As Double, ByVal dx As Double, ByVal dy As Double, Optional ByVal Radius As Double, Optional ByVal Direction As enmThemeDrawingDirection)
      Select Case What
        Case thmTypeButtonFace 'your chance to override the ButtonFace-Rendering
          'currently we paint nothing here - meaning the Button remains "unfaced" (the BackGround-Color of the Container showing through)
          
        Case Else 'everything else will be delegated to and drawn using the Original Implementation
          TOrig.DrawTo CC, W, What, State, x, y, dx, dy, Radius, Direction
      End Select
    End Sub
    Private Sub cTheme_FillThemeColorArray(DstThemeColorArray() As Long)
      For i = 0 To UBound(MyThemeColorArray)
        DstThemeColorArray(i) = MyThemeColorArray(i)
      Next
    End Sub
    Private Function cTheme_GetThemeColor(WhichColor As enmThemeColor) As Long
      cTheme_GetThemeColor = MyThemeColorArray(WhichColor)
    End Function
    
    'the remaining two Methods of the cTheme-Interface just delegate to the Original Implementation
    Private Function cTheme_GetIconFontName() As String
      cTheme_GetIconFontName = TOrig.GetIconFontName
    End Function
    Private Function cTheme_GetScrollerSize() As Long
      cTheme_GetScrollerSize = TOrig.GetScrollerSize
    End Function
    What then remains is, to apply this new cMyTheme Override-instance as the new Cairo-Theme for your App.
    You can do that in the first line of Form_Load in the previous Example:
    Code:
    Private Sub Form_Load()
      Set Cairo.Theme = New cMyTheme
      '... with the rest of the Form_Load-code as it was before
    With the (dark-colored) Theme-Override, the previous Demo-Form-Code produces the following:


    Olaf

  11. #11
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Grdient Button

    Quote Originally Posted by axisdj View Post
    "That still leaves my question unanswered, why you want to make your own Button."

    To answer your question was using pictureBoxes for all my buttons .. so changing them out may not be an issue. I was just thinking of the safest path for now.
    If you already have a (VB.PictureBox-based) Button-Implementation throughout your whole App,
    then indeed the simple Cairo-Drawing from my first two replies might be entirely sufficient for a first "fast Hack".

    Just keep in mind, that the original VB6-Form and UserControl-engine does not support Zooming
    (is not really DPI-aware) - whilst the RC5-Widget-Engine does support that.

    Edit: for more convenience with regards to checking it out, I've now zipped the Theme-Override-Demo up -
    including a few enhancements as:
    - implementing something concrete for the thmTypeButtonFace-Case
    - adding a user-switchable BackGround-Image (to be able to easier determine, what is transparent and what not)
    - added modRC5regfree.bas into the Project, so that the Demo can serve as a Base-Wireframe for portable (regfree) deployment of the RC5-libs
    . (for the above you will have to add the 4 needed RC5-Dlls into the \Bin\-Subfolder of the App yourself)

    WidgetThemeOverrides.zip

    Here is a ScreenShot again:


    Olaf
    Last edited by Schmidt; Dec 9th, 2017 at 05:23 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width