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

12 Responses to A Visual Foxpro Animated Zoombar Class

  • Imran Syed says:

    Excellent work.

    thanks for sharing your knowledge & skills

  • MikeS says:

    Nice work Bernard. I have two comments:

    1) I prefer the “popup” effect over the “zooming”. To me, the zooming effect is too distracting and it is not always obvious which button is actually going to be selected because sometimes the size of it has not grown big enough to be obvious. The popup is always obvious. Perhaps if the other buttons didn’t grow/shrink as the one getting focus grew/shrank it may be more tolerable to me.

    The other buttons actually don’t grow/shrink. They just move aside for the highlighted button.

    2) As a sometimes “keyboard only” user, I’d be annoyed if this was the only menu interface I’d have to use 🙂

    Most modern interfaces have moved towards mouse interfaces and away from the keyboard. Take the Apple Leopard OSX and Microsoft Office 2007 tool strip for instances.

    Please don’t take this feedback in a negative way. Your work is very impressive even with the those two issues.
    Never, Thank you for the feedback. At least you took the time to provide the feedback.

  • Chris-Jan says:

    Very amazing… 🙂 Thank you!

  • Guille (Paraguay!!!) says:

    hi Bernard, i will talk to you in spanish, because my english is so bad!!!!. Estuve probando la clase, buenisima!!!!, solo que pude agregar 9 “botones” ‘no more’, despues todos los “botones” se movian a la derecha… creo que se viene el SP1 del BBZoomBarClass… thank you!!… bye

    Guille
    Good encontrar. Clase fue diseñado para 9 botones. Tengo fijos y descargar desde el enlace anterior. Gracias

  • bhanji joshi says:

    Amazing…!!!, Excellent work.

    again,thankful for sharing your knowledge & skills.

    Thanks Bhanji.It feels better when people stop by and make a comment, instead of lurking.

  • MikeS says:

    Bernard, are you saying that Apple’s OSX and MS’s Ribbon UI don’t support keyboard input? If so, I think that you are mistaken. They may be easier (intuitive) to navigate using a mouse, but, there is no way they could eliminate the keyboard!

    I have neither to test. But IMHO there are interfaces for Keyboard and interfaces for a mouse and sometimes for both. This is one of those for a mouse. 

    Besides the source is provided so anyone who wants to add support for keyboard is welcome. The whole idea of the interface is mouse driven using the mouseomove event. I really cannot see the usefulness of a keyboard access here as it takes away the zooming and of what use is a zoombar if you cannot zoom?

  • I use a simple cmdButton based routine for some minor zooming.  Your development is creative and impressive. Good Work!

    Thanks.

  • FrankE says:

    Does it have to work with VFP7.0?

    It might, but I doubt it since I use the PictureVal property and the builder uses _memberdata.

  • Nicu says:

    Does it works in vfp 7?

    No

  • Doug Card says:

    Good for me ’cause I found you!. Great! I like it a lot!

  • hadiriyanto says:

    I am very interested and grateful for your sharing but I am still confused how to make buttonclicked procedure in order to perform the function of each button

    thank you very much

    • Bernard Bout says:

      The class ZoomContainer has a custom method called “buttonclicked”
      The instance of the button being clicked is passed into that method:

      Zoomcontainer.ButtonClicked()
      LPARAMETERS toButton

      Now you have toButton so you can easily do this:

      Wait Window Nowait "You clicked "+toButton.name

      Or for handling multiple buttons – where the name of each button is button1,button2,button3,….:

      DO CASE
      CASE toButton.Name = "button1"
      * code here to do something for click of button1

      CASE toButton.Name = "button2"
      * code here to do something for click of button2

      CASE toButton.Name = "button3"
      * code here to do something for click of button3

      * etc. for how many other buttons you have

      ENDCASE

      Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *