A Visual Foxpro Animated Zoombar Class
The Zoombar Class
From the first time I saw this class here
http://www.devcomponents.com/dotnetbar/BubbleBar.html
I liked it a lot. Only problem was it was in .NET and not VFP and I did not want all that overhead.
Emerson Reed did a good class here http://weblogs.foxite.com/emersonreed but it only had 2 states so was more of a popup button class rather than a zoom class.
So I decided to develop this from the ground up to suit my needs and with an actual zooming effect. The class I came up with was easier to program than I first thought.

The Class
The class library consists of 2 classes:
1. A zooming button class that can be used by itself and
2. A container class that holds a series of buttons that would zoom when the mouse was moved over them.
The buttons had to be able to be zoomed from the bottom up (bottom fixed) as well as to zoom from a central point. Also the container had to be able to move the remaining buttons around the zoomed button.
Another need was that the buttons were centrally arranged in the container whether odd or even numbers of buttons were used.
The class was to be self contained as well as have a handler for the click. Of what use is a button that does nothing when you click it?
The Zoom Button Class - Zoomimage
The whole animation of zooming takes place in the MouseMove of the button. This is a VFP image class.
So if the mouse is moving over the button from Left to Right, the button should zoom till the central point is reached and then as the mouse moves away from the centre, the button un zooms and vice versa for the opposite diretion. So find this central point, zoom till reached and then unzoom. There is also the fact that the direction the mouse is moving in, should also be stored and known else if you moved the mouse from right to left, the button would first shrink till the central point and that was undesirable.
All the original positions of the button are stored for later use here:
WITH This as image
.oldwidth = .Width
.oldheight = .Height
.oldleft = .Left
.oldtop = .Top
.vcenter = .OldLeft+INT(.Oldwidth/2)
.hCenter =.oldtop+INT(.oldheight/2)
.oldbottom = .top+.height
ENDWITH
Also the button acts differently when placed on a form or in a container. So this code was put in the Zoomimage.MouseMove:
LPARAMETERS nButton, nShift, nXCoord, nYCoord
*is this in a container or form
IF This.Parent.BaseClass = "Form"
This.zoomimage(nXCoord)
ELSE
bb = This.zoomimage(nXCoord - this.parent.left)
ENDIF
This.Parent.Reposition(This)
Zoomimage.Zoomimage
All the zooming happens here in this method. The position of the mouse cursor is passed into this depending on if it is a form or container that is the parent
If cStr = "LEFT"
inc = Int(((nxcoord-.oldleft)*10)/(.oldwidth/2))+1
Else
inc = Int(((.oldleft +.oldwidth - nxcoord )*10)/(.oldwidth/2))+1
Endif
The 10 here means that the zooming is done in 10 steps depending on the original size of the button.
.zoomfactor is the amount of zoom we want. A larger number means a greater zoom.
The next bit of code zooms the button as needed depending on whether it is a “bubble” zoom of centre zoom:
If Not .centerzoom
.Height = .oldheight + inc
.Top = .oldbottom - (.Height)
Else
.Height = .oldheight + inc
.Top = .hcenter - (.Height/2)
Endif
Finally I store the mouse position so that we can check next time to find the direction of movement: This.oldnx = nxcoord
And that is all that is needed. The class can be used on its own as below:
The ZoomContainer Class

This is used as a button bar and is responsible for creating the buttons, repositioning them and maintaining that position and has the button click handler.
ZoomContainer.Init
I have added some sample code to show how the buttons are added. Important is the DODEFAULT() since this is what initially positions the buttons and sets up the anchor of the container depending on its centerzoom property.
ZoomContainer.InitialReposition.
A user may opt for odd or even buttons so the buttons must all be centrally located. Here again I get the central point of the container and the buttons are arranged around this. This method is also called in the ZoomContainer.Resize so that the central location of the buttons is always maintained even if the form is resized.
Above you would have seen this line
This.Parent.Reposition(This)
The Zoomcontainer.Reposition method is the one that maintains all the buttons in position.
Here I get the central point of the container and the sum of widths of the buttons. One pixel is added for each button to stop overlapping them:
nTotalWidth = oButton.Width*This.buttoncount + This.buttoncount
nCenter = THis.Width/2
nbCenter = nTotalWidth/2
nLeft = nCenter - nbCenter
Next the top of the button is calculated depending on the centrezoom property:
IF this.centerzoom
nTop = This.Height/2 - oButton.height/2
ELSE
nTop = This.Height - (oButton.Height+1)
ENDIF
Finally I iterate through all the buttons setting theme up in position:
For N = 1 To .ButtonCount
oButton = Evaluate(".zoomimage"+Transform(N))
With oButton As zoomimage
.Left = nLeft
.Top = nTop
.setupprops()
nLeft = nLeft+oButton.Width+1
.Visible = .T.
Endwith
Endfor
ZoomContainer.reposition
This method handles the repositioning of the other buttons around the zoomed one by getting a left and right value and setting each button so that the Left position of a button is one pixel to the right of the previous button. This all works very sweetly.
For aesthetics I placed a label and image in the container which is hidden at runtime.
Also I added a 3d bar to give an added perspective effect. This is just another image and is anchored to the sides of the container.
Finally the handler for the buttons. You can add any code here. The name you passed is stored in the TAG property of the button, and can be used to identify which button was clicked but really ny property can be used since I pass the button object to the method.
I looked at many icon sets but I really liked Emerson's icons so used them in the class. However you are free to use any icons you wish. I found that simple PNG's like these are the best. The more complex PNG's suffer from the VFP Flashing bug and are not recommended. Bitmaps can be used instead but PNG's give a better effect when zoomed. Just change your code to point to the icons of your choice:
.addbuttons("Name of your button","Your Icon file here","Any tooltip text")
Here 3 buttons are added
WITH This as zoomcontainer
.addbuttons("FirstButton","explorer96.png","This is the first button")
.addbuttons("SecondButton","folder96.png", "Click here for a file")
.addbuttons("ThirdButton","monitor96.png", "Monitor events")
ENDWITH
The effect is as in the naimations below depending on the centerzoom property:

The final result is as per the sample form attached in the download:
The class including source code and images can be downloaded from here.
http://www.foxite.com/downloads/default.aspx?id=176
The Green Vista bar (shown below) in the sample form above - you can select this image and “SaveAs” . It should be a BMP with a white background since PNG’s on PNG’s will cause too much flashing. It is not included in the download.

I hope you find good use for this class. If you do please drop me a line.
Cheers.
Bernard
21/12/2007 - Updated bbZoombar Class is now available for download from the attachment below. Note that this is only the class update. The main file is still available at Foxite at the link above..
This fixes a bug where only 9 buttons could be added. Now 99 buttons can be added. Thanks to Guille (Paraguay!!!) who reported this