5

The LA Fox Developer Newsletter
May 1998
Add a Cascade Function to
Your Window Menu
Use this generic code to give your MDI application a profes-
sional Windows feel.

Most VFP applications are MDI (multiple document interface) in
nature. That means that users can open several forms at the
same time and jump from one to another at will. MDI applica-
tions usually have a Window menu, with options to cascade and
tile the open windows and to select specific windows. VFP has
most of that functionality built in. But there is no Cascade
function. If you want to let your users cascade their forms, you
have to write the code yourself.

What exactly do we mean by cascade? Essentially, it means
that all the open forms will appear on the screen, each offset
slightly to the right and below the one before. If you examine
other MDI applications, you will observe a fairly consistent
behavior.

Specifically, each window (form) is resized so that it occupies
three quarters of the parent window. The first window is then
moved to the top left corner of the parent. Subsequent window
are placed on top of the previous one, offset down and to the
right by an amount equal to the height of the title bar. If a given
window does not fit within the boundaries of the parent, the
sequence starts again from top left corner of the parent.

The code at the end of this article implements this procedure.
As it is generic, it does not know the names of the forms that it
is working with. Instead, it uses _SCREEN to access the forms.

For those who haven’t worked with _SCREEN before, it is
essentially, a device which allows the main VFP window to be
manipulated as if it was itself a form. You can use it to alter the
main window’s title, to assign an icon to the main window (see
the FoxStuff article Do your application icons always show up?),
to move the main window to a particular point on the screen,
and, as in this case, to access the forms currently contained in
the main window. It has around 70 properties and 20 methods,
all of which are described in the VFP Help.

Our Cascade routine uses two properties of_SCREEN: the
Forms property is an array (to be precise, a collection) of the
currently open forms; and FormCount is the number of forms in
this collection. Using these properties, the routine iterates
through the open forms, changing their sizes and positions as it
does so.

There are a couple of points to watch out for. The routine can
only resize a form if its BorderStyle property is 3; other border
styles are non-resizable. So we need to test the BorderStyle
property each time round the loop. But before we do that, we
must check that this property actually exists. That’s because
the Forms collection can also hold floating toolbars, and these
do not have a border style. The Type() fUnction is used to check
that the property exists.

Even if the form is resizable, it might be subject to minimum
and maximum sizes, as stipulated by its MinWidth, MinHeight,
MaxWidth and MaxHeight properties. If any of these properties
is greater than —1, it means that a corresponding limit is in
force. Our routine tests for this before resizing each form.

After the form is resized, the routine moves it to its new posi-
tion. The Sysmetric(9) function, called near the start of the
code, determines the height of the title bar, this being the
amount of the vertical and horizontal offset for each window.

To use the code, cut and paste it to your application. Add a
Cascade prompt to your Window menu, and place a suitable
call (e.g. DO Cascade) in its result field.

PROCEDURE Cascade
local lnHorizOff, lnVertOff, lnNewWidth, InNewHeight, InNewLeft,
lnNewTop, lnFmldx

lnHorizOff = Sysmetric(9) && horizontal offset
InVertOff = Sysmetric(9) && vertical offset

lnNewWidth = 0.75 * _SCREEN.Width && new form width
lnNewHeight = 0.75 * _SCREEN.Height && new form height

lnNewLeft = 0
lnNewTop = 0

FOR lnFmldx =1 TO _SCREEN.FormCount
WiTH _SCREEN.Forms(lnFmldx)
IF Type(”.Border~ty!a”}c>”tJ” AND .BorderS+yle 3
*
form has a resizable border, so adjust its dimensions,
*
subject to its mm/max height and width
.Width = ItF(.MinWidth = -1,lnNewWidth,
Max(InNewWidth,.MinWidth))
.Width = lIF(.MaxWidth = -1,lnNewWldth,
Min(lnNewWidth,.MaxWidth))
.Height = IIF(.MinHeight = -1,lnNewHeight,;
Max(lnNewHeight,.MinHeight))
.Height = ilF(.MaxHeight = -1,lnNewHelght,;
Mmn(innewHeight,.MaxHeight))
ENDIF

*
move the form to its new position
IF (lnNewTop + .Height ‘C _SCREEN.Height);
AND (InNewLeft + .Width <_SCREEN.Width)
*
the form will not overflow the main window,
*
so go ahead and move it
.Move(lnNewLeft,InNewTop)
*
calculate the position of the next form
InNewLeft = InNewLeft + inHorizOff
lnNewlop = lnNewTop + InVertOff
ELSE
*
form does overflow, so go back to top left corner
.Move(0,0)
InNewLeft = InHorlzOffset
lnNewTop = InVertOffset
ENDIF
ENDW1TH
ENDFOR

ENDPROC


(Copyright Mike Lewis Consultants Ltd. 1998.)
Page

5