|
|
|
|
||
|
DEFINITION MODULE DMMaster; (******************************************************************* Module DMMaster ('Dialog Machine' DM_V3.0) Copyright (c) 1985-2006 by Andreas Fischlin, Alex Itten and ETH Zurich. Purpose Manages all user dialog for a 'Dialog Machine' program and controls all remaining modules of the 'Dialog Machine'. It intercepts so-called user events as issued by the user and dispatches program events as needed to the 'Dialog Machine' program. Remarks The 'Dialog Machine' provides means to define,construct, manage, and use the following objects of a modern user interface: pull-down (or pop-up) menus, windows supporting pointing device input and window output, modal dialog windows and alerts to display system anomalies or call the user attention to issue warnings. This module provides all facilities needed to pass the control between the application specific program parts and the 'Dialog Machine' back and forth. Once started (see procedure RunDialogMachine), the control remains with the 'Dialog Machine' until a user event (mouse is clicked or a key is pressed) occurs that can no longer be handled automati- cally and which requires some appli- cation specific actions. In the latter cases the 'Dialog Machine' calls the corresponding procedure destined to handle the particular event. Typically the user event handling procedures are provided by the application program, i.e. they are installed by the application program before any user events can occur, in particular before procedure RunDialogMachine is called. Such an installation prevents the 'Dialog Machine' from responding to user events in just the standard way and lets the application perform its specific tasks, i.e. it provides the mechanism to temporarily pass control from the 'Dialog Machine' to the application specific program sections. Hence an application consists not of straight-line code, rather it consists of a set of procedures to be called at appropriate times, i.e. a user event such as a menu command selection, or the moving respectively resizing of a window. Such a program structure is called inverted program control. Typically an application written with the 'Dialog Machine' consists of a initialization, during which all necessary procedures handling user events are installed in the 'Dialog Machine', and the subsequent activation of the 'Dialog Machine'. User events handled automatically by the "Dialog Machine" are: selection of a menu item, activation, dragging resizing, updating (including the content), and closing of a window, input by means of dialog items allowing entry of e.g. numbers, various kinds of buttons and so-called check boxes, plus the display of standard warning or error messages by means of alerts. User events which are handled by default by the 'Dialog Machine' alone but which can be changed to produce a program event are: initialization of the start up state of the 'Dialog Machine', mouseclick in the front window, scrolling in the front window, bringing a window to or removing it from the front, pressing a key, and closing a window. User events which produce always a program event and which are always passed to the application are: execution of a procedure associated with a menu command, and the execution of a procedure attached to a so-called push button. The 'Dialog Machine' consists of several modules such as DMMaster, DMMenus, DMLanguage, DMWindows, DMWindIO, DMSystem, DMBase, DMErrorMsgs, DMStrings, and DMConversions plus optional modules such as DMEntryForms, DMAlerts, DMEditFields, DMFiles, DMClipBoard, DMPrinting, DMSaveOutput, and DM2DGraphs etc. which can be used depending on the actual programmer's needs. The Dialog Machine's purpose is to separate the application programming from the system programming in order to provide a modern user interface with win- dows and a pointing device like a mouse. The particular implementation for the Macintosh gives the application programmer indirect access to the toolbox, quickdraw and operating system routines by providing most of the essential features necessary to write standard Macintosh applications, which conform not only with the user interface of the 'Dialog Machine' but also with the "Macintosh User Interface Guidelines" (Inside Macintosh, Promotional ed., March 15, 1985). Hence the 'Dialog Machine' does not only substantially simplify the usage but also the programming of an application program. This module belongs to the 'Dialog Machine'. Programming o Design Andreas Fischlin 22/11/1985 o Implementation Andreas Fischlin 22/11/1985 Alex Itten 29/01/1987 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: 02/04/2000 AF *******************************************************************) FROM DMWindows IMPORT Window; (*******************************************) (*##### Types and Result Variable #####*) (*******************************************) TYPE MouseHandlers = (WindowContent, BringToFront, RemoveFromFront, RedefWindow, CloseWindow); MouseHandler = PROCEDURE (Window); (* type of a procedure handling mouse events *) KeyboardHandler = PROC; (* type of a procedure handling keyboard events *) VAR MasterDone: BOOLEAN; (*indicates whether an installation has been successful (installations may fail because of exceeded level of subprograms)*) (********************************) (*##### Setup Handlers #####*) (********************************) PROCEDURE AddSetupProc(sup: PROC; priority: INTEGER); (* Use this procedure to install a set-up procedure to be executed just after the 'Dialog Machine' has been started by calling procedure RunDialogMachine; for instance if you wish to start your program with a particular action, e.g. the creation of a window, or the initial setting of menu commands etc. You may install any number of set-up procedures. They will all be executed in reverse order of their installation. However, set-up procedures with lower priority will be called before such with a higher priority. First come those with priority 0, latest those with the priority MAX(INTEGER). By default an empty procedure is assigned, i.e. the default set-up when starting up the 'Dialog Machine' is just the display of the menubar (see module DMMenus) and the background (see module DMWindows). *) PROCEDURE RemoveSetupProc(sup: PROC); (* Removes set-up procedure sup *) (******************************) (*##### Mouse Events #####*) (******************************) PROCEDURE AddMouseHandler(which: MouseHandlers; mhp: MouseHandler; priority: INTEGER); (* Installs procedures being called automatically by the "Dialog Machine" in case one of the following events has to be handled: - The mouse handler of type WindowContent is called if the mouse has been clicked in the content region of the currently frontmost window (scroll bars excluded). - The mouse handler of type BringToFront is called if the mouse has been clicked within a window which is behind the frontmost window. This is the right moment to provide some visual feedback, such as redrawing a scroll bar as active, since the bringing of a window to the front implies its activation. - The mouse handler of type RemoveFromFront is called if the mouse has been clicked within a window which is the frontmost window. This is the right moment to provide some visual feedback, such as redrawing a scroll bar as inactive, since the removing of a window from the front implies its deactivation. - RedefWindow is called if the window has been redefined, e.g. by clicking within the resize symbol in the lower right corner or the zoom box in the upper right corner of the window title bar. This is the right moment to rescale and redraw graphical objects related to the current window size. - CloseWindow is called if the window is about to be closed, just before it is actually closed. This is the right moment e.g. to change the state of the "Dialog Machine" if it depends on the presence of particular windows. (For the saving of objects associated with windows, see also DMWindows.CloseHandler). You may install any number of mouse handlers. They will all be executed in reverse order of their installation. However, mouse handlers with lower priority will be called before such with a higher priority. First come those with priority 0, latest those with the priority MAX(INTEGER). By default all assigned procedures are empty, i.e. all events listed above are just swallowed by the 'Dialog Machine' and no particular handling of the listed mouse events takes place. *) PROCEDURE RemoveMouseHandler(which: MouseHandlers; mhp: MouseHandler); (* Removes mouse handler procedure mhp of type which *) (*******************************************) (*##### Reading From the Keyboard #####*) (*******************************************) PROCEDURE AddKeyboardHandler(khp: KeyboardHandler; priority: INTEGER); (* AddKeyboardHandler installs procedure khp which is called in case a key is pressed which does not invoke an action which can be handled by the 'Dialog Machine'. Keyboard actions always handled immediately by the 'Dialog Machine', i.e. without calling the procedure khp, are e.g. keyboard equivalents for a menu command selection. You may install any number of keyboard handlers. They will all be executed in reverse order of their installation. However, handlers with lower priority will be called before such with a higher priority. First come handlers with priority 0, latest those with priority MAX(INTEGER). Typically in the khp you call the procedure InspectKey (see below) to inspect the key. In case the handler decides to accept the key, KeyAccepted should be called at the end of khp (see below). Once any keyboard handler has called KeyAccepted, no more handlers will be called by the 'Dialog Machine'. In case the handler shall accept any keyboard event unconditionally, you may also simply call Read or BusyRead instead of the statement sequence InspectKey,...KeyAccepted. Example 1 (Recommended policy): PROCEDURE MyGoodAliasCharProvider; VAR ch: CHAR; m: BITSET; BEGIN InspectKey(ch,m); IF (CAP(ch)="A") AND (m={command}) THEN KeyAccepted; MySelectAll; END(*IF*); END MyGoodAliasCharProvider; … AddKeyboardHandler( MyGoodAliasCharProvider , 0 ); … Example 2 (not recommended policy): PROCEDURE MyBadAliasCharProvider; VAR ch: CHAR; BEGIN Read(ch); InspectKey(ch,m); IF (CAP(ch)="A") AND (m={command}) THEN MySelectAll; ELSE (* can't pass it on, Read has accepted it definitively!! *) END(*IF*); END MyBadAliasCharProvider; Above keyboard handler is not recommended, since it does not give a chance to any other keyboard handlers to handle the keyboard event, in case it would detect that it is not interested in the keyboard event. Note: If no keyboard handler has been installed by the 'Dialog Machine' program, or none of the currently installed handlers does accept the key, the 'Dialog Machine' just swallows the entered keys (It actually installs a handler which unconditionally calls KeyAccepted with priority MAX(INTEGER)). This behavior guarantees a proper synchronization between key board pressing and corresponding calls to handlers (see also SetKeyboardHandlerMode). *) PROCEDURE RemoveKeyboardHandler(khp: KeyboardHandler); (* Removes keyboard handler procedure khp *) PROCEDURE InspectKey(VAR ch: CHAR; VAR modifiers: BITSET); (* Inspect the pressed key together with the eventually also pressed modifiers. Modifier keys are keys which do not cause a keyboard event when they are pressed, they require that another, not a modifier key is pressed simultaneously. The latter is returned by InspectKey in ch, the simultaneously pressed modifier keys are returned in the bitset modifiers. Use the constants exported by DMKeyChars to inspect which modifier keys have been pressed (Note that even the pressing of the mouse button can be used as a modifier). Typically this procedure is called within a keyboard handler procedure installed in the 'Dialog Machine'. In case the calling handler wants to accept the key, it should call subsequently KeyAccepted, to avoid that further keyboard handler procedures can process the keyboard event. In order to write keyboard handlers which are portable accross computer platforms, use the module DMKeyChars while inspecting key events within your handler. E.g. to learn about a simple cursor up event, call InspectKey and compare the returned ch with DMKeyChars.cursorUp and make sure the modifiers = {}, i.e. InspectKey(ch,modifiers); IF (ch=cursorUp) AND (m={}) THEN ExecuteCursorUpCommand; KeyAccepted; END(*IF*); See also below for other sample code of keybaord handlers. *) PROCEDURE KeyAccepted; (* Typically called from within a keyboard handler. Once the keyboard handler has analyzed the pressed key, for instance by calling InspectKey, and decides to accept the key, this procedure should be called. Its effect is that the "Dialog Machine" stops calling further keyboard handlers. *) PROCEDURE Read(VAR ch: CHAR); (* waits till a character is typed (see also BusyRead) *) PROCEDURE SetKeyboardHandlerMode( readGetsThem: BOOLEAN; maxPriority: INTEGER); PROCEDURE GetKeyboardHandlerMode(VAR readGetsThem: BOOLEAN; VAR maxPriority: INTEGER); (* Allows to temporarily disable the reading process, e.g. when deactivating a window associated with a process which calls Read, and to resume it later, e.g. when the window is brought back again to the front. To understand the function of the keyboard handler mode consider the following facts: Normally the 'Dialog Machine' handles keyboard events by calling the currently installed keyboard handlers. In this mode Read has never a chance to get a key, unless you call it from within a keyboard handler or you call SetKeyboardHandlerMode(TRUE,…). Once the keyboard handler mode is set to readGetsThem = TRUE, Read is enabled to receive keyboard events. Read then loops forever calling DialogMachineTask. The loop can only be terminated if either a key is actually entered by the user or if the 'Dialog Machine' is quit. However, to temporarily disable the keyboard polling process by procedure Read, you may call SetKeyboardHandlerMode(FALSE,…). A typical usage of this feature is to temporarily disable the reading process in case the user brings his/her attention to another process than the reading one, for instance by clicking into another window than the one in which the reading request, e.g. a prompt, has been written to. In the latter case you should call SetKeyboardHandlerMode(FALSE,…) in the window handler of the class removedFromFront (see DMWindows WindowHandlers). To resume the reading as soon as the window requesting the input is brought to the front again, call SetKeyboardHandlerMode(TRUE,…) in the window handler of the class broughtToFront (see DMWindows WindowHandlers). Note also that in the keyboard handler mode readGetsThem=TRUE, any attempt to press a key while the program is not executing a Read, results in a call to SoundBell. This signals to the user, that all key entering is currently ignored, unless the program actually executes a reading request. Finally it is also important to note that the user would be confused, if some keys would not function the ordinary way, e.g. a string field, a number editing field (see DMEditFields), or keyboard equivalents for menu commands. The latter are always recognized and a keyboard equivalent of a menu command is of course not interpreted as a keyboard event but as a menu command selection. Since the 'Dialog Machine' allows to install additional keyboard equivalents to global commands such as menu commands by means of keyboard handlers, the user would be confused, if not some of these could remain active, despite the fact that the mode is currently readGetsThem=TRUE. Hence, there is a mechanism needed, which allows to selectively call installed keyboard handlers. Above goals are accomplished by means of the priority parameter maxPriority. It indicates up to which priority (0 is highest, MAX(INTEGER) the lowest) keyboard handlers are still executed, regardless of the current keyboard handler mode. E.g. calling SetKeyboardHandlerMode(TRUE,0) results in a mode where any keyboard event is first handled by all handlers with priority = 0, but by none with priority >0, before it is passed to the procedure Read. Of course does the "Dialog Machine" make the keyboard event only available to Read, if none of the handlers has yet called KeyAccepted. Otherwise the keyboard event is considered to have been handled properly and has become meaningless for any subsequent processing. SetKeyboardHandlerMode(TRUE,-1) results in a suppressing of all currently installed keyboard handlers. A good policy is to install with priority 0 only keyboard handlers which selectively accept keys, i.e. call first InspectKey and analyze whether they want to take the key or not; otherwise they don't swallow the key, e.g. don't call Read nor KeyAccepted, but leave if for further processing by other handlers. A handler which takes all keys unconditionally, e.g. by calling Read, should be installed only with a lower priority, e.g. 100, so that it can be disabled by calling SetKeyboardHandlerMode(TRUE,99) before calling Read. Otherwise this handler would never allow a key to arrive at the Read procedure. Note also, that the "Dialog Machine" itself installs as a keyboard handler with priority MAX(INTEGER) the procedure KeyAccepted. Example: Set up your 'Dialog Machine' program similar to the following: a) for keyboard events: PROCEDURE MyGoodAliasCharProvider; VAR ch: CHAR; m: BITSET; BEGIN InspectKey(ch,m); IF (CAP(ch)="A") AND (m={command}) THEN KeyAccepted; MySelectAll; END(*IF*); END MyGoodAliasCharProvider; … AddKeyboardHandler( MyGoodAliasCharProvider , 0 ); b) for mouse events, e.g. clicking into windows: VAR msdosWindow: Window; oldKBHMode, msdosActive: BOOLEAN; oldKBHPrior: INTEGER; PROCEDURE ActivateMSDOSWindow(u: Window); BEGIN DMMaster.GetKeyboardHandlerMode(oldKBHMode,oldKBHPrior); DMMaster.SetKeyboardHandlerMode(TRUE,0); msdosActive := TRUE; END ActivateMSDOSWindow; PROCEDURE DeactivateMSDOSWindow(u: Window); BEGIN DMMaster.SetKeyboardHandlerMode(oldKBHMode,oldKBHPrior); msdosActive := FALSE; END DeactivateMSDOSWindow; PROCEDURE MSDOSForcedToForeGround; BEGIN IF WindowExists(msdosWindow) THEN IF FrontWindow()<>msdosWindow THEN PutOnTop(msdosWindow); WHILE NOT msdosActive DO DialogMachineTask; (* make sure activation is properly updated *) END(*WHILE*); END(*IF*); SelectForOutput(msdosWindow); ELSE CreateWindow(msdosWindow,GrowOrShrinkOrDrag,WithVerticalScrollBar, WithCloseBox, WithZoomBox, bottomLeft, defaultFrame, "MS-DOS", AutoRestoreProc); AddWindowHandler(msdosWindow,closing,DeactivateMSDOSWindow,0); AddWindowHandler(msdosWindow,broughtToFront,ActivateMSDOSWindow,0); AddWindowHandler(msdosWindow,removedFromFront,DeactivateMSDOSWindow,0); END(*IF*); END MSDOSForcedToForeGround; … … Moreover you may install a menu command "MS-DOS…" associated with the following procedure: … PROCEDURE MSDOSCommandInterpreter; CONST dir = 1; copy = 2; … … exit = 32000; TYPE Command = INTEGER; VAR oldKBHMode,finished: BOOLEAN; oldMaxPrio: INTEGER; msdosCmd, args: ARRAY [0..127] OF CHAR; PROCEDURE ReadString(VAR s: ARRAY OF CHAR); BEGIN i:= 0; WHILE (s[i]<>EOL) AND DialogMachineRunning() DO Read(s[i]); INC(i) END; IF i<=HIGH(s) THEN s[i] := 0C END; END ReadString; PROCEDURE ParseMSDOSCmd(c: ARRAY OF CHAR; VAR args: ARRAY OF CHAR): Command; BEGIN Scan(c… … END ParseMSDOSCmd; BEGIN finished := FALSE; REPEAT MSDOSForcedToForeGround; WriteString("prompt> "); ReadString(msdosCmd); CASE ParseMSDOSCmd(msdosCmd,args) OF dir : ShowDirectory; | copy : MakeFileCopy(arg1,arg2); | … : … | … : … | exit : finished := TRUE; ELSE WriteString("unrecognizable command."); WriteLn; END(*CASE*); UNTIL finished OR NOT DialogMachineIsRunning(); END MSDOSCommandInterpreter; Such a code still allows the user to leave the MS-DOS interpreter anytime and work with other 'Dialog Machine' objects, e.g. other windows, menu commands etc. As soon the MS-DOS window is activate by clicking into it and bringing it to the front, the polling reading process by MS-DOS is resumed and it awaits keyboard inputs from the user, before it continues processing. P.S.: Remember that once you called SetKeyboardHandlerMode(FALSE,…) during a reading process, that you are fully responsible for a proper resuming of the normal reading by calling SetKeyboardHandlerMode(TRUE,…). Otherwise the callee of Read will not be able to continue and will hang in the Read statement until the mode is resumed and a key is actually entered. The only other way to terminate this hanging is if the whole Dialog Machine is terminated also. *) PROCEDURE BusyRead(VAR ch: CHAR); (*returns immediately 0C if no character has actually been typed. Interpretations are made to simulate on older Macintosh models lacking the control key the following control characters (non displayable) of the ASCII character set: command^A .. command^Z : 01C .. 32C (CTRL ^ alpha) command^a .. command^z : 01C .. 32C (CTRL ^ alpha) command^[ : 33C (CTRL ^ "[") command^] : 34C (CTRL ^ "]") command^\ : 35C (CTRL ^ "\") command^^ : 36C (CTRL ^ "^") command^_ : 37C (CTRL ^ "_") command^3 .. command^7 : 33C .. 37C (CTRL ^ number) e.g. CTRL^3 = ESC = 33C (oktal) IMPORTANT: Note, if the 'Dialog Machine' is in the so-called batch mode (cf. DialogMachineIsInBatchMode) this routine functions like Read and can't return 0C. *) PROCEDURE DoTillKeyReleased(p: PROC); (* Executes p as long as key remains pressed *) (********************************) (*##### User Feedbacks #####*) (********************************) PROCEDURE ShowWaitSymbol; PROCEDURE HideWaitSymbol; (* Calling procedure ShowWaitSymbol informs the user that an action will now start which might cause him to wait for some time. For instance call it just before reading a long file from a floppy disk or performing some large computations. This gives the user the assurance that his program is still in perfect running order and that the reason for the delayed response is only due to a slow action and not due to a silent program crash. On the Macintosh the shape of the omnipresent cursor is changed to a waiting symbol (e.g. a hour-glass). DON'T FORGET to call HideWaitSymbol after termination of the long action! Note: Calling ShowWaitSymbol consecutively without calling HideWaitSymbol inbetween, results in the display of a so-called animated waiting symbol, i.e. the wait symbol will change its shape with each call to ShowWaitSymbol. Hence, for very lengthy actions it is recommended to call ShowWaitSymbol regularly, e.g. in a loop, and not only once at the begin of the action. On the Macintosh the Dialog Machine supports up to 9 different cursor shapes. The first is only shown once after calling for the first time ShowWaitSymbol or after having called HideWaitSymbol in between (resource of type 'CURS', ID=4). Any subsequent call to ShowWaitSymbol shows another of the up to a maximum of 8 cursors in an endless loop according to the list defined in the resource of type 'acur' with ID=0. *) PROCEDURE Wait(nrTicks: LONGCARD); (*Wait for nrTicks * 1/60 seconds *) PROCEDURE SoundBell; (*Beeps with the currently active sound*) PROCEDURE PlayPredefinedMusic(fileName: ARRAY OF CHAR; musicID: INTEGER); (* Get a predefined piece of music from the resource fork of the file "fileName". If the file specified by fileName couldn«t be opened, then the default search strategy to find the resource is followed (see Inside Macintosh: Resource Manager). If no resource of type 'snd ' and id musicID could be found no sound will be produced at all. When you generate a stand alone application (With the MacMETH Linker Link using option /A), you should copy all resources into your application (e.g. with the ResEdit application). In this case the resources will be found regardless which fileName you have specified. NOTE: According to Inside Macintosh Volume VI p. 22-18 only musicID numbers > 8191 are allowed to be used by your application. *) (*************************************************) (*##### Core Routines of Dialog Machine #####*) (*************************************************) PROCEDURE InitDialogMachine; (* Makes the current (sub)program level to a DM level so that DMSystem.LevelIsDMLevel called on this level will from now on return TRUE. This procedure is mainly exported for compatibility reasons with the IBM PC version of the Dialog Machine. *) PROCEDURE RunDialogMachine; (* Start and run the 'Dialog Machine' on the current program level. Implicitly calls first InitDialogMachine and then DMMenus.UseMenuBar. *) PROCEDURE DialogMachineIsRunning(): BOOLEAN; (* Returns whether the 'Dialog Machine' is currently running; A request typically only made by the 'Dialog Machine' modules themselves. *) PROCEDURE DialogMachineTask; (* Temporal control of events may be returned to the "Dialog Machine" (e.g. activation of a menu etc.) by calling this procedure typically from within a loop, e.g. a numerical integration loop. *) PROCEDURE ForceDialogMachineIntoBatchMode(bm: BOOLEAN); (* Forces the 'Dialog Machine' to operate in a so-called batch mode (bm is TRUE) or to operate in the so-called normal, interactive mode (bm = FALSE). Basically this batch mode emulates the behavior of an alternative implementation of the 'Dialog Machine', i.e. the so-called 'Batch Dialog Machine' which is the basis of RASS, the RAMSES Simulation Server. In the batch mode a call of procedure RunDialogMachine will only result in the execution of all installed handlers and the subsequent, automatic quitting of the 'Dialog Machine'. No user interactions are exepected than the default ones. E.g. a user dialog, which presents a window and displays some information together with an OK and a Cancel button will not await the user to press any button. Instead the 'Dialog Machine' assumes that the user has pressed the default "OK" button and continue with whichever processing it is programmed for. In case the programmer has not foreseen a default answer, the user's input is mandatory and the result of the operation becomes ambiguous. Consequently the "Dialog Machine" can't proceed with its processing since the post condition of the input requesting operation is not defined. The 'Dialog Machine' will then temporarily abandon the batch mode and resume normal interactive mode, i.e. request the user to provide the requested input in order to make an unambiguous branching in the program as a consequence of the input. If the 'Dialog Machine' is actually a "Batch Dialog Machine" the entire 'Dialog Machine' program is aborted if this situation of an ambiguous user input request arises. E.g. calling DMFiles.GetExistingFile is such an ambiguous user input request, where no default answer can be provided by the programmer. The user has to provide a selection of an existing file. Of course a 'Dialog Machine' in batch mode could assume the user has cancelled the file opening dialog, however this is typically of little interest to the processing in batch mode and therfore batch mode is always abandoned whenever DMFiles.GetExistingFile is called in batch mode. Instead the programmer has an alternative, i.e. to write the batch mode program such that such situations are avoided by using e.g. procedure DMFiles.Lookup or to provide for all requests of user inputs always a default answer. Once the user has satisfied a mandatory input request the "Dialog Machine" will resume the processing in the batch mode. Note that error conditions, such as a program crash by a division by zero or similar fatal exceptions, or a programmed HALT will also abandon temporarily the batch mode and require some user input. You can still suppress the associated dialogs by redirecting such error output by a call to SetMsgDevice from module DMMessages like this SetMsgDevice(toJournalFile,toJournalFile,toJournalFile, toJournalFile); All output generated by the program, which might potentially require a user dialog, will then be suppressed. This is even valid for a programmed HALT. The batch mode may be useful to execute some lengthy computations in a setup procedure, such as an entire simulation, since calling RunDialogMachine in the batch mode will simply enter and immediately leave the "Dialog Machine" again. NOTE: In case the 'Dialog Machine' is implemented as the so-called 'Batch Dialog Machine' calling this routine will have no effect, since such a 'Dialog Machine' does always and only operate in the batch mode. You can use routine DMSystem.GetDMVersion to learn whether the current implementation of the 'Dialog Machine' is a full featured interactive or the more restricted 'Batch Dialog Machine' variant only. Note the batch mode is global and affects all subprogram levels once its activated. However, its use is supported in the following way: Termination of any subprogram level which has activated the batch mode as the first (after the last or initial deactivation), will resume the normal, interactive mode as was originally the case. IMPLEMENTATION RESTRICTIONS: The emulation of the batch mode may not be fully possible, depending on the platform and the particular implementation of the 'Dialog Machine'. Consequently some user interactions may still be required if an implementation is not complete. RAMSES is an acronym for Reserach Aids for Modeling and Simulation of Environmental Systems. *) PROCEDURE DialogMachineIsInBatchMode(): BOOLEAN; (* Returns wether the 'Dialog Machine' operates currently in the so-called batch mode (returns TRUE) or operates in the normal interactive mode (returns FALSE) (see also comments for procedure ForceDialogMachineIntoBatchMode). If the 'Dialog Machine' is actually implemented only as a 'Batch Dialog Machine' this procedure returns always TRUE. The latter fact can only be learned by calling DMSystem.GetDMVersion. *) PROCEDURE QuitDialogMachine; (* Quit running 'Dialog Machine' on current program level. Typically this procedure is never called directly by an application program, since the 'Dialog Machine' calls it automatically when executing the quit command installed by means of module DMMenus. *) PROCEDURE AbortDialogMachine; (*terminate 'Dialog Machine' regardless of current program level*) (****************************************) (*##### Dynamic Linking-Loader #####*) (****************************************) (* The following features are only meaningful if a dynamic linking loader is available. This is the case for MacMETH on the Macintosh *) TYPE SubProgStatus = (normal, abnormal); PROCEDURE CallSubProg(module: ARRAY OF CHAR; VAR status: SubProgStatus); (* Use this procedure to call another Modula program to be run as a subprogram under the control of the 'Dialog Machine'. Subprograms are stacked on each other and form a kind of program stack. Each (sub)program acts on its particular level, may install new menus, open windows etc. Previously installed objects are globally controllable by means of the 'Dialog Machine', not just those objects belonging to the topmost (sub)program level. In particular note that procedures attached via a mouse handler to a particular window or associated with a menu command will be executed on the very same program level as the window has been created or the menu command has been installed, not necessary only on the current topmost level. Upon quitting a subprogram, any objects created on the level to be left are removed automatically by the 'Dialog Machine'. *) END DMMaster.
|
||
|
|
|