DEFINITION MODULE DMWindows;
(*******************************************************************
Module DMWindows ('Dialog Machine' DM_V3.0)
Copyright (c) 1985-2006 by Andreas Fischlin, Alex Itten and
ETH Zurich.
Purpose Manages windows on behalf of a 'Dialog Machine'
program.
Remarks Windows give the user a particular view onto
any type of objects the application program
creates or manages, such as a portion of a
graph or a text. Multiple windows may coexist
on the same screen. They may overlap and can
be moved, resized, rearranged in their sequence
by bringing a partially overlapped window to
the front (= window activation) implies the
simultaneous removing of the previously
frontmost window from the front (= window
deactivation). A window's content can be
scrolled, so that other parts of the
displayedobject may become visible.
Method: Windows may be created, repositioned,
activated, or removed under program control exerted
by the application. However, typically an
application only creates windows (procedure
DMWindows.CreateWindow) and specifies its
properties. Once created, the window management is
left to module DMMaster, i.e. clicking the mouse
button in the content region or the close box of a
window results in an automatical call to the
corresponding window management procedure. Except
for the window creation, all window management
functions can be left to the 'Dialog Machine' and
must not be dealt with by the application program.
An exception to this is the updating of the window
content necessary after an event causing a
previously covered window portion to become visible
again. The client program has to provide a
so-called re- store procedure
(DMWindows.RestoreProc) which redraws the whole
window content. The calling of this procedure and
the restriction of the drawing area to window areas
currently really visible (not covered by other
windows) are automatically provided by the 'Dialog
Machine' and the restore procedure need not to be
concerned with this problem.
This module belongs to the 'Dialog Machine'.
Programming
o Design
Andreas Fischlin 16/12/1985
o Implementation
Andreas Fischlin 16/12/1985
Alex Itten 22/12/1986
ETH Zurich
Systems Ecology
CHN E 35.1
Universitaetstrasse 16
8092 Zurich
SWITZERLAND
URLs:
<mailto:RAMSES@env.ethz.ch>
<http://www.sysecol.ethz.ch>
<http://www.sysecol.ethz.ch/SimSoftware/RAMSES>
Last revision of definition: 05/08/1991 AF
*******************************************************************)
FROM SYSTEM IMPORT ADDRESS;
TYPE
Window;
(*
Variables of this type are needed to identify particular
windows. Always(!) declare such variables on a global
level, since the window management routines attempt to
update your variables. E.g. when closing a window by
clicking the close box contained in the window title bar,
the "Dialog Machine" assigns to your window variable the
value nonexistent.
*)
(*
types of application windows (document windows with a title
bar except for FixedLocation) are distinguished as follows:
*)
WindowKind = (GrowOrShrinkOrDrag, (*resizing and dragging permitted*)
FixedSize, (*no resizing, dragging permitted*)
FixedLocation, (*no resizing, no dragging. no title bar*)
FixedLocTitleBar); (*no resizing, no dragging*)
ModalWindowKind = (DoubleFrame, SingleFrameShadowed);
ScrollBars = (WithVerticalScrollBar, WithHorizontalScrollBar,
WithBothScrollBars, WithoutScrollBars);
CloseAttr = (WithCloseBox, WithoutCloseBox);
ZoomAttr = (WithZoomBox, WithoutZoomBox); (*only meaningful on >= Mac+*)
RectArea = RECORD x,y,w,h: INTEGER END; (*Rectangular area with
lower left corner (x,y)
and width w and height h*)
WindowFrame = RectArea; (*Determines size and position of a
window relative to the background
coordinates. It frames just the
working area in which output
takes place, i.e. the title bar or
any scrollbars are excluded. Note,
when you create a window, that these
areas are added on the outside of
the WindowFrame.*)
WFFixPoint = (bottomLeft, topLeft); (* Fixpoint on the window frame
(corner) relative to which the
window content is positioned
after a redefinition of the
window size (redefine event). *)
RestoreProc = PROCEDURE (Window);
(*
Procedure to redraw the whole content of a window. A
procedure of this type is called by the "Dialog Machine"
after a portion of a window's content region becomes
uncovered (for instance if the window becomes the frontmost
window after having been partially overlapped by other
windows). Its purpose is to simply redraw the whole
content of the window. Typically this is done without
being concerned about the visibility of the window's
content region or other similar issues; the "Dialog
Machine's" window management takes care of that. Given the
current arrangement of windows, only the visible portions
of the drawing will be displayed.
*)
CloseProc = PROCEDURE (Window, VAR BOOLEAN);
(*
Procedure called if the window is about to be closed by the
user when clicking into the close box, just before it is
actually closed. This happens before any eventually
installed window handlers (see below WindowHandlers) and
before the global MouseHandler for closing events from
DMMaster are called. This is the right moment to save
objects associated with the closing window or eventually to
suppress the closing of the window by returning FALSE.
Typically the latter case is used if it has not been
possible to complete successfully the handling procedure,
for instance if errors have been detected in the entry of
an edit field maintained by module DMEditFields requesting
from the user a value necessary for any further meaningful
use of the program. If FALSE is returned the global
MouseHandler CloseWindow is not called and the window
remains open as it was before the user attempted to close
it. The default close procedure returns always TRUE. (see
also SetCloseProc (this module) and
DMWindows.CloseHandler). Note that RemoveWindow will not
call such a close procedure, assuming that the programmer
calls the procedure only after having done any houskeeping.
In case you need to receive a message when RemoveWindow is
called, installed a WindowHandler closed.
*)
WindowProc = PROCEDURE (Window);
(*
Type of an action procedure to be performed with a window
(s.a. procedures DoForAllWindows, AddWindowHandler, and
RemoveWindowHandler).
*)
WindowHandlers = (clickedInContent, broughtToFront, removedFromFront,
redefined, onlyMoved, disappeared, reappeared, closing);
(*
Possible window related events. Some of these events may
be produced by the user via mouse or keyboard (user event)
or also by the running program (software event). The events
are:
Event type description
-----------------------------------------------------------
clickedInContent mouse, user User clicked into the content
region of the window (controls
and edit fields excluded)
broughtToFront mouse, user, The window has been brought
software to the front, i.e. it has just
become the frontmost window.
removedFromFront mouse, user, the opposite of broughtToFront
software
redefined mouse, user, The window size or position has
software been changed
onlyMoved mouse, user, The window's position has been
software changed but not its size
disappeared software The window has been made invisible
reappeared software the opposite of disappeared
closing mouse, user, The window is to be closed,
software i.e. completely removed
from the screen. Note, that
this event is handled
specially: This handler is
called before the denoted
action has actually taken
place (hence named closing not
closed). Note also, that it is
called after the CloseProc of
the involved window and before
the global MouseHandler
(CloseWindow). When called
you may safely assume that the
window still exists. Note
also, that this is the only
closing events related handler
which is callable via
software, i.e. by a call to
RemoveWindow or RemoveAllWindows.
Window handlers are owned by a single window and are only
called by the Dialog Machine if an event of the
corresponding class involves the particular window. See the
procedures AddWindowHandler and RemoveWindowHandler.
IMPORTANT NOTE: A closing window handler MUST NOT call
RemoveWindow nor RemoveAllWindows, since it is called by
these procedures (otherwise you will obtain an infinite loop)!
IMPORTANT RECOMMENDATION: It is highly recommended and a
safe programming practice to set your window variable (not
the actual argument passed to your closing handler, which
is only a value parameter) to the value notExistingValue
within the body of your closing handler routine.
Example code of a GOOD closing handler which you have
added to window myWindow:
PROCEDURE GoodClosingHandler(u: Window);
BEGIN
(* do cleaning up of objects associated with myWindow *)
myWindow := notExistingWindow;
END GoodClosingHandler;
Note, the value argument passed to your closing handler by
the 'Dialog Machine', i.e. u, always points properly at the
window object, which still exists, since the 'Dialog
Machine' will only really discard the instantiation of this
object after the last closing handler had a chance to
properly handle its closing task. This technique allows to
associate as many handlers as you wish to the particular
instantiation of a particular window object. Each closing
handler should then find the same preconditions, i.e. the
existence of the object while handling its closing task.
Hence, you can program every handler as if it would be
alone and set your opaque window variable to
notExistingWindow (as an important side effect of your
closing handler) and leave the rest to the 'Dialog
Machine'. This programing technique makes it less likely
that you have dangling pointers to no longer existing
objects.
The only situation in which you have to be more cautios is
the case where you have several handlers which all operate
on the same master instantiation of the variable of type
Window (instead of keeping a separate copy). Once a handler
(the first one), has set this variable to
notExistingWindow, the closing handlers subsequently called
by the Dialog Machine will of course no longer have proper
access to this variable, since the first handler which set
it to notExistingWindow has cleared it. In this case you
need to be aware of the coesticence of these handlers and
you have to program them such, that the first one leaves
the opaque variable intact and that only the last one does
actually assign notExistingWindow. Alternatively you can
use the actual argument passed to you by the 'Dialog
Machine' to access the object and perform the specific
cleaning up task and simply assign notExistingWindow to the
master variable (regardless of any sequence). In the
latter case it is NOT a safer programing practice to test
within the closing handler whether the actual argument and
your window variable (which you consider to be the same)
are equal. Example code of a BAD closing handler in a
multiple handler situation operating on the same window:
PROCEDURE BadClosingHandler(u: Window);
BEGIN
IF u=myWindow THEN
(* do cleaning up of objects associated with myWindow *)
myWindow := notExistingWindow;
ELSE
(* do nothing *)
END(*IF*);
END BadClosingHandler;
Since the test u=myWindow is likely to fail in a multiple
handler situation. However it is perfectly ok to do the following:
PROCEDURE AnotherGoodClosingHandler(u: Window);
BEGIN
myWindow := u;
(* do cleaning up of objects associated with myWindow *)
myWindow := notExistingWindow;
END AnotherGoodClosingHandler;
NOTE: In case there is also a global handler
(DMMaster.MouseHandler) installed for the particular event,
that a window handler is normally called before the global
handler. Note also that these window handlers are always
called, regardless whether the event was caused by a user
or software. This behavior is different from that of the
global handlers, which are only called if the event is
caused by a user event. Howeve, the use of global handlers
via DMMaster is discouraged, since it runs contrary to
information hiding.
*)
VAR
notExistingWindow: Window; (* read only var! *)
(*
Read only variable which may be used for variables of type
Window to denote that the associated window is actually
not existing, i.e. not displayed on the screen. It is a
good programming practice to assign this value to all
window variables during the initialization phase of the
"Dialog Machine", i.e. before calling procedure
DMMaster.RunDialogMachine.
*)
background: Window;
(*
This is a predefined window covering the whole screen
except for the menu bar. It is always provided
automatically by the "Dialog Machine" and cannot be
removed, dragged, put on top, nor resized. The origin of
its pixel coordinate system cannot be moved and is at the
lower left corner of the screen. The background window has
no title bar and it's content is by default filled with the
DMWindIO. GreyContent grey. The background resembles the
desktop; however, it is different in the following respect:
It is possible to make output in the background like in any
other ordinary window maintained by the "Dialog Machine".
To better support the new operating systems on the Macintosh,
the background is initially no longer visible unless you call
ReshowBackground.
*)
WindowsDone: BOOLEAN; (*indicates success of a window
management procedure*)
PROCEDURE NoBackground;
(* Call this procedure if your application does not need the
background window (is initially default). *)
PROCEDURE ReshowBackground;
(* Call this procedure if your application needs the
background again, e.g. after NoBackground. *)
PROCEDURE OuterWindowFrame(innerf: WindowFrame; wk: WindowKind;
s: ScrollBars; VAR outerf: RectArea);
(*
Calculates from the working area f within a window the outer
frame of the window of kind wk and with scrollbars s (reverse
of procedure InnerWindowFrame). Typically this procedure is
called before calling CreateWindow in order to determine the
exact position of the window relative to the background. This
routine does not work on a modal window. A modal window of
kind DoubleFrame which has no scroll bars has an outer frame
of 7 pixels larger than the innerf.
*)
PROCEDURE InnerWindowFrame(outerf: WindowFrame; wk: WindowKind;
s: ScrollBars; VAR innerf: RectArea);
(*
Calculates from the outer window frame outerf from a window
of kind wk and with scrollbars s the inner working area
innerf (reverse of procedure OuterWindowFrame). Typically
this procedure is called before calling CreateWindow in order
to determine the parameter f of type WindowFrame used in
parameter list of CreateWindow given a particular outer size
of the window. This routine does not work on a modal window.
*)
PROCEDURE CreateWindow(VAR u: Window; wk: WindowKind;
s: ScrollBars; c: CloseAttr; z: ZoomAttr;
fixPoint: WFFixPoint; f: WindowFrame;
title: ARRAY OF CHAR;
Repaint: RestoreProc);
(*
Creates and opens a window of kind wk, titlestring title,
with its lower left corner at position (f.x,f.y) and with
width f.w and height f.h. Attribute wk specifies whether the
window may be resized or has to keep its size always, plus
whether it may be dragged or has to stay at the same screen
location for its whole existence. Attribute s determines the
type of ScrollBars of the window, i.e. vertical and/or
horizontal scroll bars. Attribute c specifies whether the
window may be closed via a close box shown in the upper left
corner of a window's title bar. Windows of type
"GrowORShrinkOrDrag" may have a so called zoom box in the upper
right corner of the window's title bar. By clicking inside this zoom
box, the window will be enlarged to the entier screen size or
(with a second click) resized to it's original size before the
zooming. fixPoint denotes the point of the window content, which
will stay at it's position if the window grows or shrinks.
By default it specifies the origin (0,0) of the local window
coordinate system.
A window identifier u is returned for future references. Procedure
Repaint will be invoked in case the window has to be restored, i.e.
its whole content has to be redrawn.
*)
PROCEDURE CreateModalWindow(VAR u: Window; wk: ModalWindowKind; s: ScrollBars;
f: WindowFrame; Repaint: RestoreProc);
(*
Creates and opens a window of kind wk with its lower left
corner at position (f.x,f.y) and with width f.w and height
f.h. In case f.x or f.y define a point outside the main
screen the window will be automatically centered in the
middle of the screen. Attribute wk specifies whether the
window will have a double frame (recommended standard type
for modal dialogs) or will have a simple frame and a shadow.
Modal windows are typically used for modal dialogs (see
procedure UseWindowModally), i.e. during a modal dialog such
a window can't be dragged, nor zoomed, nor closed via
clicking into the close box. Attribute s determines the type
of ScrollBars of the window, i.e. vertical and/or horizontal
scroll bars. The origin (0,0) of the local window coordinate
system is always at the lower left corner. A window
identifier u is returned for future references. Procedure
Repaint will be invoked in case the window has to be
restored, i.e. its whole content has to be redrawn.
*)
PROCEDURE UsePredefinedWindow(VAR u: Window;
fileName: ARRAY OF CHAR;
windowID: INTEGER;
fixPoint: WFFixPoint;
Repaint : RestoreProc);
(*
Creates a predefined window read from a Macintosh resource of
the type "WIND" with ID = windowID contained in the resource
fork of the file fileName. In case that the fileName passed
is empty, the default search strategy to find the resource is
followed. For the other parameters see procedure
CreateWindow.
The following rules apply when mapping Macintosh procIDs with
the type WindowKind from DMWindows (see also Inside Macintosh
I-273, Fig.4):
procID WindowKind Resize drag title
------ ---------- ------ ---- -----
documentProc (0) GrowOrShrinkOrDrag yes yes yes
noGrowDocProc (4) FixedSize no yes yes
plainDBox† (2) FixedLocation† no no no
- (not available) FixedLocTitleBar no no yes
ModalWindowKind
---------------
dBoxProc° (1) DoubleFrame° no no no
altDBoxProc (3) SingleFrameShadowed no no no
† This type is used by the Dialog Machine for modal entry forms
(see DMEntryForms)
° This type is used by the Dialog Machine for the modal alerts
(see DMAlerts)
procID values different from any of those values given above (i.e.
0..4) are interpreted to code for WindowKind FixedLocTitleBar.
*)
CONST
DoubleFrameTitled = 3;
PROCEDURE CreateTitledModalWindow(VAR u: Window; title: ARRAY OF CHAR;
f: WindowFrame);
(*
Creates a double framed but titled and movable modal dialog
window. This function is only available under system 7.0.
The value for argument wk (see GetWindowCharacteristics)
returned is DoubleFrameTitled.
*)
PROCEDURE AttachWindowObject(u: Window; obj: ADDRESS);
PROCEDURE WindowObject(u: Window): ADDRESS;
(*
Attaches to the window u an object in memory at address obj.
The attach allows the calling program to associate its own
objects, e.g. a data structure with a window for reference to
that object. Typically a mouse handler (see DMMaster) may
profit from this mechanism, since it returns the window in
which the user event has taken place, which allows the
programer to access directly the associated object by calling
procedure WindowObject from within the mouse handler
procedure without having frist to search the object. Attach
NIL to detach an object.
*)
PROCEDURE RedefineWindow(u: Window; f: WindowFrame);
(* Change size or position of window *)
PROCEDURE RedrawTitle(u: Window; title: ARRAY OF CHAR);
PROCEDURE MakeWindowInvisible(u: Window);
PROCEDURE MakeWindowVisible (u: Window);
PROCEDURE IsNowVisible (u: Window): BOOLEAN;
PROCEDURE WindowLevel(u: Window): CARDINAL;
(*
Returns the level of the sub-program on which the window u
has been created. If the window does not exist it returns
DMSystem.startUpLevel-1, i.e. 0.
*)
PROCEDURE GetWindowCharacteristics(u: Window;
VAR wk: INTEGER; VAR modalKind: BOOLEAN;
VAR s: ScrollBars; VAR c: CloseAttr; VAR z: ZoomAttr;
VAR fixPoint: WFFixPoint; VAR f: WindowFrame;
VAR title: ARRAY OF CHAR);
(*
Returns the characteristics of the window u. Note that wk
either holds the ORD(WindowKind) or ORD(ModalWindowKind) value,
depending whether the window is an ordinary window (modalKind
= FALSE) or a modal window (modalKind = TRUE).
*)
(*********************************************************************
Window Updating:
If a part of a window becomes visible again after beeing covered
by another window or Desk Acessory, this part of the window content
must be restored.
The best way to do this is to pack all drawing procedures (offered by
DMWindIO) into a procedure of type RestoreProc (see above) and to
pass it eigther by procedure CreateWindow or SetRestoreProc to the
Dialog Machine. In this case the Dialog Machine cares about the entier
restoring of a window in the way that only the just discovered
part(s) of the window will actually been drawn (necessary for drawing
with mode invert).
On the other hand this module offers an automatic restore mechanism,
wich will maintain a copy in memory (bit map) of all drawings into the
specified window. This mechanism is very fast but needs quit a lot of
memory (default on Mac Plus and Mac SE apr. 22 kBytes and on Mac II
36 kBytes). This update mechanism may only restore in one single color,
mainly in the last assigned window color by DMWindIO.SetColor.
This procedure should be used in case the recalculation of the window
content takes a long time and would slow down execution speed
dramatically or in simple programs to minimize devellopement expense.
The automatic restore mechanism my be used in two different ways:
1. By simple assigning the procedure AutoRestoreProc to the Dialog Machine
by procedure CreateWindow or SetRestoreProc default hidden bit map size
is used which is as large as the maximum possible window size ( Size =
(ScreenHeight - MenuBarHeigth) * ScreenWidth ). This guarantees that the
whole window content may automatically be restored if the window content
will never be scrolled.
2. With the procedure StartAutoRestoring you may assign a rectangle area
to the auto restore mechanism in which the mechanism will maintain any
restoring. This is very usefull in the case of very large video displays
or if multiple video displays are used simultaneously. Then you may
combine the auto update mechanism inside this RectArea together with
your own (written) restore procedure for the rest of the window. To do
this you FIRST assign your update procedure which itself calls the
procedure AutoRstoreProc to the Dialog Machine and SECOND you define
the rect area to be maintained by calling the procedure StartAutoRestring
(which will not change the assigned RestoreProc but will allocate the
hidden bit map).
The restore procedure may be changed any time but this will cause the loss
of the content in the hidden bit map.
*********************************************************************)
PROCEDURE DummyRestoreProc(u: Window);
(*using this restore procedure results in no updating at all*)
PROCEDURE AutoRestoreProc(u: Window);
(*
Assigning this restore procedure directly to the Dialog
Machine results in an automatic updating, i.e. no application
provided restore procedure is called. Note, that this update
mechanism uses memory space, since for every window updated,
a bitmap accommodating the maximum window size has to be
provided (on older Macintosh with built in screens (e.g. Mac
Plus) approximately 22KBytes). NOTE: This procedure is not
capable to restore the window content if it contained
different colors!
*)
PROCEDURE SetRestoreProc(u: Window; r: RestoreProc);
(*
Sets r as the new restore procedure. If r is equal the
AutoRestoreProc a hidden bit map is allocated and if r is
different to AutoRestoreProc an eventually allocated hidden
bit map is removed.
NOTE: Calling this procedure will result in an eventual
reinitialization, hence clearing of the hidden bit map if it
has been used previously. r is called once immediately after
the installation.
*)
PROCEDURE GetRestoreProc(u: Window; VAR r: RestoreProc);
(*
Returns the current used Restore procedure of the window u.
*)
PROCEDURE StartAutoRestoring(u: Window; r: RectArea);
(*
It is possible to maintain the rectangle area r by the auto
restore mechanism, while restoring the rest of the window by
your own restore procedure previously assigned by
SetRestoreProc. If there is enough memory available, the rect
area r may be set equal to the content size of your document
and the auto scroll mechanism (see DMWindIO) may be used
together with the auto restoring. If you dynamically change
the size of r with this procedure the previous content of the
hidden bit map is destroyed.
*)
PROCEDURE StopAutoRestoring(u: Window);
(*
stops the autorestore mechanism for this window u and
deallocates the used hidden bit map.
*)
PROCEDURE AutoRestoring(u: Window): BOOLEAN;
(*
returns TRUE if current restore mechanism of window u is
performed by procedure DMWindows.AutoRestoreProc
*)
PROCEDURE GetHiddenBitMapSize(u: Window; VAR r: RectArea);
(*
Returns the current Size of the used hidden bit map.
*)
PROCEDURE UpdateWindow(u: Window);
(*
This procedure forces the update of the window u. The standard
update mechanism is used which guarantees that only an eventually
newly become discovered part of the window will actually beeing
drawn.
NOTE: The usage of this procedure is ONLY necessary if you want a
window beeing updated earlier than the 'Dialog Machine' would do it.
In the Batch 'Dialog Machine' this routine does flush the standard
output and standard error if you use the 'background' for the actual
argument.
*)
PROCEDURE InvalidateContent(u: Window);
(*
In contrast to the procedure UpdateWindow, this procedure declares
the entier window content as invalid, just like it would have got
visible after beeing totally covered by another window. It does not
call the window update procedure directly, but the Dialog Machine
will, when it handles the update event, call the window specific
update procedure. Then the entire content will be redrawn.
This procedure is very useful in case the information visible in a
window should be changed. Then all drawing routines may be packed
into a own written update procedure, which will update the
information on screen.
*)
PROCEDURE UpdateAllWindows; (*only used by the "Dialog Machine"*)
PROCEDURE RedrawBackground; (*only used by the "Dialog Machine"*)
PROCEDURE SetCloseProc(u: Window; cp: CloseProc);
PROCEDURE GetCloseProc(u: Window; VAR cp: CloseProc);
(*
Sets or gets cp as the close procedure for window u. Note
that a close procedure asks the user for confirmation before
actually closing the window.
*)
PROCEDURE AddWindowHandler(u: Window; wh: WindowHandlers; wp: WindowProc;
priority: INTEGER);
PROCEDURE RemoveWindowHandler(u: Window; wh: WindowHandlers; wp: WindowProc);
(*
Adds or removes a so-called window handler to a particular
window. Each handler handles only a particular class of
events; for a description of the events see above comment for
type WindowHandlers. Each time the Dialog Machine detects an
event involving a window, it checks whether any handlers are
installed for that window. In case it finds one for the
given class of event, it calls it by passing the involved
window u as the actual argument. Multiple handlers can be
installed, even for the same class of events. In case of the
latter situation, the priority decides which handler will be
called first (0 = highest priority). In case there should
still be a conflict (same event class, same priority), the
handler installed last will be called first (LIFO-queue). To
remove a handler, you must be the "owner" of the window
procedure; i.e. only if exactly the same wp is passed as
actual argument during removal as was used when installing
it, RemoveWindowHandler will succesfully remove the handler.
*)
PROCEDURE GetWFFixPoint(u: Window; VAR loc: WFFixPoint);
(*
Returns loc as the fixpoint on the window frame relative to
which the window content is positioned during all subsequent
redefinitions of the window size (redefine event). This point
is by default equal the origin (0,0) of the local window
coordinate system.
*)
PROCEDURE DoForAllWindows(action: WindowProc);
(* Execute procedure action for all windows *)
PROCEDURE GetWindowFrame(u: Window; VAR f: WindowFrame);
PROCEDURE PutOnTop(u: Window);
(*
Put window u in front of all other windows and make it the
active window by deactivating the previously frontmost
window
*)
PROCEDURE UseWindowModally(u: Window;
VAR terminateModalDialog,
cancelModalDialog: BOOLEAN);
(*
Use the window u for a modal dialog which implies the
following action taken by the Dialog Machine: In case u is a
draggable window it will be placed in the centre of the main
screen, put on top of all windows, terminateModalDialog and
cancelModalDialog will be set to FALSE. Then all user events
other than mouse clicks in the content of u or in the close
box of u (if it has one), or keyboard events, are not
accepted. In particular user events such as dragging, menu
selection, clicking in another window etc. are ignored and
the Dialog Machine will sound a beep instead. This behavior
is typical for a modal dialog, i.e. such a dialog does not
allow the user to proceed with anything than what is allowed
in the modal dialog. Hence, try to avoid modal dialogs, use
so-called modeless dialogs instead. The latter allow the
user to divert his attention away from the dialog and
complete first another task before resuming the original
dialog. This may be quite important, for instance if the user
wishes to look up a number before he makes an entry etc. On
the other hand, experience shows that reasonably used, modal
dialogs can be very effective and simple to comprehend, not
only for the programmer but also for the user!
It is important to ensure that the window contains an
appropriate push buttons, or content handlers which are
capable of setting either terminateModalDialog or
cancelModalDialog to TRUE. This is because the "Dialog
Machine" allows to terminate the modal dialog only if one of
the following conditions is satisfied:
o the calling program sets terminateModalDialog to
TRUE (e.g. via a push button). Note that installing a
so-called default push button (see module DMEditFields
procedure UseAsDefaultButton) allows to select that
button also via the keyboard, i.e. by typing Return (in
case no text field is currently selected) or via the
Enter key, or
o the calling program sets cancelModalDialog to
TRUE (e.g. via a push button), or
o the user presses the Command-key simultaneously with the
period "." ("Dialog Machine" sets cancelModalDialog
to TRUE), or
o the user types Escape ("Dialog Machine" sets
cancelModalDialog to TRUE), or
o if the window has a close box the user closes it
via its close box ("Dialog Machine" sets
cancelModalDialog to TRUE).
Note that in the first two cases the client program is
causing the dialog termination, in the latter cases the
"Dialog Machine" will assign a value to the variable
cancelModalDialog without any intervention by the client
program. Otherwise the "Dialog Machine" won't have any
effect on the values of terminateModalDialog or
cancelModalDialog. This allows the calling program to detect
always how the dialog has been terminated.
In order to avoid user confusion you can apply such modal
dialogs only to windows which have been created by
calling
CreateModalWindow
or then to a window of one of the following tyes:
- FixedSize and WithoutZoomBox
- FixedLocation
- FixedLocTitleBar and WithoutZoomBox
If you call this procedure with a window different from any
of the types listed the procedure will immediately return and
have no effect except that it sets dialogAborted to TRUE. It
is recommended not to run modal dialogs on windows with a
close box.
Here a sample program text demonstrating the use of procedure
UseWindowModally by implementing an entry form (see module
DMEntryForms) containing one integer field:
VAR
myEntryForm: DMWindows.Window; wf: DMWindows.WindowFrame;
acceptIt, cancelled, entryFormOk: BOOLEAN;
theInt1, origInt1, theInt2, origInt2: INTEGER;
intF1, intF2, okBut, cancelBut: DMEditFields.EditItem;
...
PROCEDURE DoOk;
BEGIN
acceptIt := DMEditFields.IsInteger(intF1, theInt1) AND
DMEditFields.IsInteger(intF2, theInt2);
END DoOk;
PROCEDURE DoCancel;
BEGIN
cancelled:=TRUE; theInt1:=origInt1; theInt2:=origInt2;
END DoCancel;
...
origInt1:=theInt1; origInt2:=theInt2; wf.w:=360; wf.h:=120;
wf.x := (DMWindIO.BackgroundWidth()-wf.w) DIV 2;
wf.y := (DMWindIO.BackgroundHeight()-wf.h) DIV 2;
DMWindows.CreateModalWindow(myEntryForm, DMWindows.SingleFrameShadowed,
DMWindows.WithoutScrollBars, wf,
DMWindows.AutoRestoreProc);
DMWindIO.SetWindowFont(DMWindIO.Chicago, 12, DMWindIO.FontStyle{});
DMEditFields.MakeIntField(myEntryForm,
intF1, (wf.w-6*DMWindIO.CellWidth()) DIV 2,
88, 6, theInt1, MIN(INTEGER), MAX(INTEGER));
DMEditFields.MakeIntField(myEntryForm,
intF2, (wf.w-6*DMWindIO.CellWidth()) DIV 2,
66, 6, theInt2, MIN(INTEGER), MAX(INTEGER));
DMEditFields.MakePushButton(myEntryForm, okBut, wf.w-75-14,
22, 75 DIV DMWindIO.CellWidth(),
DMLanguage.okButtonText, DoOk);
DMEditFields.UseAsDefaultButton(okBut);
DMEditFields.MakePushButton(myEntryForm, cancelBut, 14, 22,
75 DIV DMWindIO.CellWidth(),
DMLanguage.cancelButtonText, DoCancel);
DMEditFields.SelectField(intF1);
DMWindows.UseWindowModally(myEntryForm, acceptIt, cancelled);
DMWindows.RemoveWindow(myEntryForm);
entryFormOk := NOT cancelled;
Above code is equivalent to:
VAR ef: DMEntryForms.FormFrame; entryFormOk: BOOLEAN; theInt1,theInt2: INTEGER;
...
DMEntryForms.IntField(2, 20, 7, theInt1, useAsDeflt, MIN(INTEGER), MAX(INTEGER));
DMEntryForms.IntField(3, 20, 7, theInt2, useAsDeflt, MIN(INTEGER),MAX(INTEGER));
ef.x:=0; ef.y:=-1; ef.lines:=5; ef.columns:=45;
DMEntryForms.UseEntryForm(ef, entryFormOk);
*)
PROCEDURE FrontWindow(): Window;
(* returns currently frontmost window *)
PROCEDURE WindowExists(u: Window): BOOLEAN;
(*tests whether window u currently exists*)
PROCEDURE RemoveWindow(VAR u: Window); (*upon returning u = nonexistent*)
PROCEDURE RemoveAllWindows;
END DMWindows.