DEFINITION MODULE FieldEditor; (********************************************************) (* *) (* Screen editing utilities *) (* *) (* Programmer: P. Moylan *) (* Last edited: 13 May 1998 *) (* Status: OK *) (* *) (********************************************************) FROM SYSTEM IMPORT (* type *) ADDRESS; FROM Windows IMPORT (* type *) Window; (************************************************************************) (* *) (* The editor in this module is "generic" in a limited sense. It *) (* performs screen editing of variables of arbitrary types, provided *) (* that those types have been declared by calls to DefineFieldType. *) (* *) (* The caller is required, when calling DefineFieldType, to supply *) (* procedures which write and edit variables of that type. The *) (* "write" procedures has three parameters: a window, a pointer to the *) (* variable to be written or edited, and the number of character *) (* positions to use. The "edit" procedure is similar but has an *) (* extra parameter: the third parameter is for the size of the *) (* variable itself, and the fourth parameter is for the number of *) (* character positions to use on the screen. For field types where *) (* the number of character positions cannot be determined in advance, *) (* the caller is expected to supply 0 as the value of the third *) (* parameter, and the user-supplied procedures are expected to be able *) (* to work out the actual width required. The user-supplied *) (* procedures are expected, in all cases, to leave the screen cursor *) (* at the character position just beyond the written form of the *) (* field. They must be prepared to deal with NIL addresses. The *) (* user-supplied editor must handle all keystrokes which belong to it, *) (* but leave intact (via Keyboard.Putback, for example) the keystroke *) (* which causes it to return. Note that it will be very common for *) (* the editor to receive a cursor movement key implying that the user *) (* does not want to modify this field but is simply skipping over it. *) (* In such cases the editor still has the responsibility for showing *) (* the user where the cursor is, by using blinking, reverse video, etc.*) (* *) (* Given all of these rules, and the fact that all the hard work is to *) (* be done by user-supplied procedures, you might by now be wondering *) (* whether there is any point in having this module. The main point *) (* is that the rules impose some uniform standards which make it *) (* easier to develop readable software for applications which need a *) (* lot of screen editing. They also help, in some applications, to *) (* avoid duplication of effort. These properties are used to *) (* advantage in modules ListEditor and ScreenEditor. *) (* *) (* As an added bonus, this module exports some pre-defined field types *) (* for commonly encountered cases. For those cases, the user does not *) (* need to call DefineFieldType, and therefore does not need to supply *) (* the procedures for writing and editing variables of those types. *) (* *) (************************************************************************) TYPE FieldType; (* is private *) WriteProc = PROCEDURE (Window, ADDRESS, CARDINAL); EditProc = PROCEDURE (Window, VAR (*INOUT*) ADDRESS, CARDINAL, CARDINAL); (************************************************************************) (* THE PREDEFINED TYPES *) (************************************************************************) VAR Byte, Cardinal, Real, String: FieldType; (************************************************************************) (* DEFINING A NEW TYPE *) (************************************************************************) PROCEDURE DefineFieldType (Writer: WriteProc; Editor: EditProc): FieldType; (* Introduces a new field type into the system. Writer is a *) (* user-supplied procedure to write a variable of the new type. *) (* Editor is the user-supplied procedure for editing a variable of *) (* that type. *) PROCEDURE DiscardFieldType (type: FieldType); (* A notification from the user that this type will not be used *) (* again (unless it is redefined by another call to procedure *) (* DefineFieldType). Use of this procedure is optional, but is *) (* recommended for the sake of "clean" memory management. *) (************************************************************************) (* COMPARING TYPES *) (************************************************************************) PROCEDURE SameType (t1, t2: FieldType): BOOLEAN; (* Returns TRUE iff t1 = t2. *) (************************************************************************) (* SCREEN OUTPUT *) (************************************************************************) PROCEDURE WriteField (w: Window; address: ADDRESS; type: FieldType; width: CARDINAL); (* Writes address^ on the screen at the current cursor position in *) (* window w. The width parameter specifies how many character *) (* positions to use. Use width=0 for variable-width fields for *) (* which the write procedure for that type must work out the width. *) (************************************************************************) (* THE EDITOR *) (************************************************************************) PROCEDURE EditField (w: Window; VAR (*INOUT*) address: ADDRESS; type: FieldType; varsize, width: CARDINAL); (* Edits the variable at the given address, and of the given type, *) (* at the current cursor position in window w. The width parameter *) (* specifies how many character positions are to be used on the *) (* screen. Set width=0 for variable-width fields where the editor *) (* must determine the width. We leave this procedure on seeing a *) (* keyboard character which does not belong to us. The cursor is *) (* left just beyond the last character of the field as it is *) (* displayed. The terminating keystroke is returned to the *) (* keyboard driver so that it can still be read by the caller. *) (* Note that the address is an inout parameter because there are *) (* cases where we allow the user to create and delete fields, i.e. *) (* address could be NIL on entry but not on exit, or vice versa. *) END FieldEditor.