I have always looked at other programming languages, especially .Net WPF forms and admired the Easing that was available for those controls. In VFP that seemed impossible.
Not any more. Enter the Easing Library of functions for VFP. If you don't know what Easing is, then have a read here
Also, to better visually understand what is meant by easing, have a look at this page where you can try out the different easing functions available. You need to do this to understand what easing is and what it can bring to your apps. No static image can ever illustrate what easing is.
For instance, suppose you had a small image and wanted to zoom it. The usual way, without easing would be to add a timer and then in the Timer event, slowly increase the width and height till the image was zoomed. This is called Linear easing.
But what if you wanted a fancier way of zooming, say with a bounce at the end, then you were out of luck or had to do some heavy code manipulations to even come near that effect.
Well recently I came across Robert Penner's Easing Functions and decided to have a go at implementing this in VFP.
The result, after initial testing, is this set of easing functions translated into VFP. All the functions are in the procedure file easing.prg so to use it you will first have to issue:
SET Procedure to easing.prg ADDITIVE
After that all the easing functions are available for you to call.
In the download at the end of this post, is the library and a couple of sample forms and some images used in the samples.
Form1 - This form allows you to play around with all the easing functions and see the different effects that can be achieved. The simplest, and one we usually use in VFP is the linear easing where the object's property is changed over a set period of time in EQUAL steps.
The more complicated ones after that use different formula to calculate the objects property to be changed over the same period, but with different effects applied.
So what can you do with easing on your forms. Well you can now create animated controls like never before, with easing animations. All that is needed is a bit of imagination and the functions of course.
To see some practical implementation of easing on a VFP form, open and run Form2.
I have made 4 different examples of easing in this one form. Check them out and you will never go back to linear easing after seeing the effects you can achieve in a simple form.
So howwould you actually use this library in your forms. Here are some examples.
A number of times you have a small image on your form and when the user clicks it or some other event, you zoom the image. This can be done 3 ways.
1. Just Zoom to the final size. This gives a jerky movement where the image is zoomed in a flash.
2. Use linear easing. You add a timer and in its Timer event you add code like
.Width = .Width+1
.Height = .Height + 1
always checking for the max size etc. If the timer is fast enough this provides a form of animation.
Another example, is where you want to pop out a toolbar from the left or top and hide it again.
Still another is where you have a large Edit region (editbox) but do not want the editbox to always be large because of screen/form real-estate. So when the control has focus, you enlarge it and when focus moves you shrink it again.
These are some of the many ways you practice linear easing.
But with this library you are not subject to linear easing but to the whole range.
So how to use this library? Here is how I made the image zoom with easing on form2
1. SET Procedure to easing.prg ADDITIVE
2. Add your image and note the final size. Resize the image control (image.stretch = 2) to the small size and note its dimensions as well.
You now have:
Width = 98
Height = 60
Width = 600
Height = 312
3. Add a timer to the form and set the following properties:
Enabled = .F.
Interval = 10
4. We need to store where we are in the animation so add a custom property to the form - timecount - and give it the value of 0 (zero)
All easing is calculated as the action to undertake between 0 and 1
5. Add code similar to this to the timer's Timer event
This.Enabled = .F.
IF ThisForm.timecount < 1
fn = "OutBack"
* fn(duration,startpos,(endpos(240)-startpos = ChangeInPos,1(sec))
* start ht = 60, w = 98
* end ht = 312 w = 600
ThisForm.image1.Height = &fn(Thisform.timecount,60,252,1)
ThisForm.image1.Width = &fn(Thisform.timecount,98,502,1)
Thisform.timecount = Thisform.timecount + .02
This.Enabled = .T.
All easing functions take 4 parameters and return a single value.
duration - If our easing function is to take 1 second to complete (1000 ms) and we increment the timecount property by .02 , we can calculate that the timer will fire every 10 ms for 50 times.
1/.02 = 50
So our easing goes from 0 to 1 in steps of 50. If we just incremented the width and height of the image 50 times it would be a linear easing. We would also need to calculate by how many pixels we would need to do this over the peroiod to get to the final zoom size.
OutBack(duration, start, change, time)
duration - This value stored in the property timecount and incremented by .02 50 times is what we use as the first parameter - duration, so the function can calculate where in the complete sequence from 0 to 1 we are in. This seems more complicated but it actually is very simple.
start - This is the initial start position of our object. So if we are easing the width this will be the initial width - e.g. 98
change - this is the change we want to implement. This is calculated by
final property value - start property value = change
So in the image, if we want a final width of 600 pixels the change from the initial 98 px to 600 px
change = 600 - 98 = 512
The final parameter is the time and we have set this to 1 (second)
Every iteration of the timer we change the width by calling the easing function like this:
and directly assign the returned value to the property we are changing - ThisForm.image1.Width
Then update the position in time to the new one:
Thisform.timecount = Thisform.timecount + .02
The same is done to the height. The easing function will return a value that is applied to the width or height. You do not need to know what it is but simple know that it is the next value of that property in that easing method.
Remember there is NO image1.width = image1.width + some value. The value returned is directly applied to the property we are easing.
The easing functions actually return a proper value that is directly applied to the object's property.
Finally we need an event to kick off the timer to run the easing. In the image.MouseEnter you could add code to kick off the easing:
Thisform.Timer1.Enabled = .T.
And that is all there is to do. Run the form and on moving the mouse over the image, the timer is fired and the image zooms, but with easing.
Have a look at the sample code and see how I have implemented Reverse easing to Unzoom the image or resize the form controls as needed.
My next step with this is to implement the whole thing as a class such that setting a few properties will allow you to implement easing in your forms and controls.
Now no more jerky movements. Lets EASE into those controls.
Update 03 Mar 2013
Some of the easing functions were not behaving properly so I had another look at them.
Specifically the in/out Expo. A;so the in/out Elastic functions were not implemented. This has been corrected in the new update and the Elastic functions have been implemented.
Grab the new set of files from the link below and start animating your controls.