Shiny Glass Buttons anyone?
In a previous post I showed a class to generate "Aqua" buttons using GDI+x from codeplex.
This post is all about some modifications I made to that class to enable me to produce Shiny Glass Buttons. Also I did not explain the techniques in obtaining the effect. This post will fix that and I will try to explain as best I can, the inner workings of the class.
The Glass Button
Basically the class uses a subclassed Imgcanvas control from the GDIPLUS.VCX classes that you need to download from the link above. The classes INIT should not be touched. Instead use the SETUP method to run any code you'd normally run in the INIT.
.Setup
This
.originalht = This.Height
This
.originalwidth = This.Width
* resize to fit the shadow
This
.Width = This.Width + This.shadowOffset
This
.Height = This.Height + This.shadowOffset
The original height and width are saved and the canvas is increased to allow the shadow to display. This must be done in the Setup method.
.BeforeDraw
Here's where the magic happens.
* Declarations
Local
loGfx As xfcGraphics
Local
loBrush1 As xfcBrush
Local
loBrush2 As xfcBrush
Local
loBrush3 As xfcBrush
Local
loBrush4 As xfcBrush
Local
loRect1 As xfcRectangle
Local
loRect2 As xfcRectangle
Local
loRect3 As xfcRectangle
Local
path1 As xfcPath
Local
path2 As xfcPath
Local
path3 As xfcPath
Local
loFont As xfcFont
Local
loStringFormat As xfcStringFormat
loGfx
= This.oGfx
Local
nButtonColour1 As Integer, nButtoncolour2 As Integer, nButtoncolour3 As Integer, nButtoncolour4 As Integer
With _Screen
.System.Drawing
The canvas is now cleared to the parents background colour which means that these buttons can be placed in a container as well.
* clear
loGfx.Clear(.Color.FromRGB(This.Parent.BackColor))
* read in the colours from control's the properties
nButtonColour1 = .Color.FromRGB(This.pnButtoncolour1)
nButtoncolour2 = .Color.FromRGB(This.pnButtoncolour2)
* this is one of the options of the Drawing2D.SmoothingMode
loGfx.SmoothingMode = .Drawing2D.SmoothingMode.AntiAlias
The main button is drawn here. A rectangle to define its position and size is created.
* main button
loRect1 = .Rectangle.New(This.btnOffset,This.btnOffset,This.originalwidth, This.originalht)
The GetPath method, just plots a path with the button's dimensions, but rounds the corners as per the curvature set in the pnbtnCurvature property
path1 = This.GetPath(loRect1, This.pnbtnCurvature) && second param less = less curve
This code flips the colours used based on the MouseEnter and MouseLeave and creates the gardient brush to draw.
IF This.Hover
loBrush1 = .Drawing2D.LinearGradientBrush.New(This.Rectangle, nButtonColour2,nButtoncolour1,90,.T.)
ELSE
loBrush1 = .Drawing2D.LinearGradientBrush.New(This.Rectangle, nButtonColour1,nButtoncolour2,90,.T.)
ENDIF
loBrush1.GammaCorrection = This.Hover

The button Normal and Hover(below) states

* shadow
The same rectangle used above is used here except we offset the Left and Top by the ShadowOffset. This is the reason we resized the object in .SETUP. so that the shadow would be visible. A pathgradient brush is used.
loRect2 = loRect1
loRect2.offset(This.shadowOffset, This.shadowOffset)
path2 = This.GetPath(loRect2, This.pnbtnCurvature)
loBrush2 = .Drawing2D.PathGradientBrush.New(path2)
loBrush2.CenterColor = .Color.Black
loBrush2.SurroundColors = .Color.FromRGB(This.Parent.BackColor) && fade into background
Here's what the shadow looks like when drawn

* lighter top half
loRect3 = .Rectangle.New(This.btnOffset+2,This.btnOffset+2,This.originalwidth -(This.btnOffset+4),;
This.originalht/2 + This.btnOffset)
path3 = This.GetPath(loRect3, This.pnbtnCurvature,.T.)
nButtoncolour4 = .Color.FromRGB(This.pnButtonColour4)
nButtoncolour3 = .Color.FromRGB(This.pnButtonColour3)
IF This.Hover
loBrush3 = .Drawing2D.LinearGradientBrush.New(loRect3,nButtoncolour4,;
nButtoncolour3, .Drawing2D.LinearGradientMode.Vertical)
ELSE
loBrush3 = .Drawing2D.LinearGradientBrush.New(loRect3,nButtoncolour3,;
nButtoncolour4, .Drawing2D.LinearGradientMode.Vertical)
ENDIF
Same as above except the rectangle is changed and the curvature for the bottom 2 curves is doubled for effect.
This is the result of the above code:

Normal State (above) and Hover (below)

The 3 object and then drawn in this sequence.
loGfx.FillPath(loBrush2, path2) && shadow

loGfx.FillPath(loBrush1, path1) && dark main

loGfx.FillPath(loBrush3, path3)

The above 3 lines actually draw the images onto the imgcanvas(ignore the text for now)
Finally the Text is drawn using the standard GDI+x code
* draw the text
nButtonfontcolour = .Color.FromRGB(This.pnButtonFontColour)
loBrush4 = .SolidBrush.New(nButtonfontcolour)
loRect = .Rectangle.New(This.btnOffset, This.btnOffset, This.Width-This.shadowOffset,This.Height-This.shadowOffset)
* Get a basic string format object, then set properties
loStringFormat = .StringFormat.New()
loStringFormat.Alignment = .StringAlignment.Center
loStringFormat.LineAlignment =.StringAlignment.Center
* Create a Font object
loFont = .Font.New(This.pcButtonFontName,This.pnButtonFontSize, .FontStyle.Bold, .GraphicsUnit.Point)
* draw it
loGfx.DrawString(This.pcButtonCaption , ;
loFont, loBrush4, loRect, loStringFormat)
Endwith
This code produces the button below
with the same button in "Hover" state.

I have also atached code to the MouseEnter/MouseLeave, MouseDown/MouseUp to handle these states and give a visual feeedback. The Hover effect, just flips the gradient colours. The MouseDown/MouseUp redefines the rectangle with an offset giving the appearance of the button being pressed and released.
So its just a matter of dropping the class on a form and sizing it to your needs.
I have made most changable properties Favourites so those are the only ones that need to be changed.

To assist, I have also designed and attached a live builder. This builder is just a form class that is called from the MemberData script of the custom property aaGlassBtnBuilder with this script code. This code is very generic, so if ever you need to attach a custom builder you can modify this snippet for calling your own builder. Also check out the code in the builder for how the properties are read and set.

Memberdata Editor with script code.
The clicking on the builder button displays the builder which has a live preview. Make your changes and click "Apply" to update the class properties and update the preview. The preview is exactly how your button will finally look at runtime.

Here are some samples I created with this class.

Also note that just by changing the colours used and the curvature of the corners you can produce a huge variety of spectacular glass buttons. Here are a few more I created just by changing the colour sequence and the curvature.

As usual the full source code for the class and the builder are included in the attached file. Download and create your own Glass buttons courtesy of GDI+x and me. I have not included any sample form in the attachment.
Only the class is included but then that is all you need. That and some imagination on your part. The rest is done by my class and of course the GDI+xclasses.
Note:
As mentioned in other posts,
I dont include the gdiplusc.vcx since you need to download the latest from the VFPx site.
Just open the form/class in VFP and when it asks you for the Imgcanvas, navigate it to the gdiplusx.vcx on your computer. The form/class will then resolve the location correctly. Save the form/class, set the default path to the directory where your form is (to find any images) and then run the forms. I have subclassed the imgcanvas class from the gdiplusx.vcx class library. Unfortunately this would happen since I don't supply the gdiplusx.vcx and I don't know where a user might have stored it.