to write two classes, screen and field, representing a screen
layout and an individual field (either a label or an input region) that
appears on a screen.
The field class, which lets us display, and possibly edit, a character
string, is really intended as a base class from which we'll derive many
kinds of field (displaying/editing different kinds of data) in the
future. Because of this, and because the code for the screen class will
use the field class extensively, it is important that the screen class'
logic uses only features of the field class described below and not
extra features you may decide to add to the field class.
When instantiated a field must be passed between three and five values,
in the following order:
- required: the row on which the field is to be displayed (int)
- required: the starting column for the field (int)
- required: the field's width (int)
- optional: an initial value for the field (constant character string)
- optional: editability flag (true: editable, false: display-only)
If only three parameters are specified, the field begins empty. If fewer
than five parameters are specified, the field is editable. Note that
instantiating a field does not cause it to appear - there are member
functions (below) to do that. If the coordinates specified are not
valid, the closest on-screen coordinates to those specified are used. If
the field width is too long to fit on the screen, the width should be
reduced so that the field fits on the screen. Similarly, if the initial
value is longer than the field width, only as many characters of the
initial value as will fit are used.
A field has the following public member functions, all of which are
void display() - causes the field to be displayed on the screen. On
systems where terminal output is buffered, this function does
not flush the screen buffer. Note that if the field's current
value is shorter than the field width, trailing spaces are
displayed to fill out the field. (Such trailing spaces are not
considered part of the data of the field, however).
int edit() - causes the field to be displayed (as in display()) and
then lets the user edit the field, using the keys just as
dt_edit() does. The key code used to terminate editing is
returned. The first time a field's edit() function is called,
the cursor is positioned at the beginning of the field.
Subsequent calls to edit() start the cursor where it left off at
the end of the previous edit() call, unless the string is now
too small (in which case the cursor is positioned just past the
end of the string).
In the case where the field is not editable, this function
simply displays the field and returns 0 without waiting for any
bool editable() const - returns true if the field is editable, false
if it is display-only.
void *data() - returns the address of the string currently stored by
the field. Note that we expect that in derived classes this may
be the address of some other kind of data being edited.
field *clone() const - dynamically allocates another instance of the
field, making that field a copy of itself, and returns the
address of the copy. If a copy cannot be made, this function
returns NULL. It is the caller's responsibility to deallocate
Since dynamic memory allocation is required to implement this properly,
the field class also has an appropriate copy constructor, = operator and
A screen manages up to 50 fields (although if you can remove this limit,
you are more than welcomed to do so). The fields are kept in order by
when they were added to the screen - the field that was added first is
known as field number 0, the field that was added next is known as field
number 1 and so on. The screen class has the following public member
int add(int, int, int) and
int add(int, int, int, const char *) and
int add(int, int, int, const char *, bool) - adds a field to the
screen, where the field added is constructed with the data
supplied to add(). These functions return the number of fields
in the screen after adding the field, or 0 if the field could
not be added for some reason.
int add(const field &f) - adds a copy of "f" to the screen,
returning the number of fields in the screen after adding the
field (or 0 if the add() failed for some reason).
void display() and
void display(bool clear) - displays all the fields managed by the
screen, in the same order that they were added to the screen. If
"clear" is specified and true, the screen is cleared before the
fields are displayed, otherwise the fields are displayed without
touching any other part of the screen. On systems that buffer
terminal output, this function does not flush the output buffer.
int edit() and
int edit(bool clear) and
int edit(int *pfield) and
int edit(int *pfield, bool clear) - Displays all the fields of the
screen (after clearing the screen if "clear" is specified and
true) and then allows the user to edit them, starting at field
number "*pfield". The user moves between fields with any of the
Down arrow - moves to the next editable field
Up arrow - moves to the previous editable field
Tab - works just like Down Arrow
Enter - moves to the next editable field, except when pressed
in the last editable field of the screen, in which case it
causes edit() to end.
Here "next" and "previous" refer to the order in which the
fields were added to the screen. There is a wrap-around effect,
also, so the the next field after the last field is the first
field, and the previous field before the first field is the last
All other keys which terminate a field's edit() function
terminate this function as well, setting "*pfield" to the number
of the field from which the user exited. The key code used to
exit the field's edit() is returned.
If "pfield" is NULL or not provided, then editing starts at the
first editable field the first time edit() is called, and
resumes at the field last exited upon subsequent calls.
If "pfield" points to an int, but that int is not the number of
en editable field, then editing begins at the next editable
field (where "next" is as defined above).
If there are no editable fields on the screen, this function
returns 0 after displaying all the fields.
field *getfield(int i) - returns the address of field numbered "i"
or NULL if "i" is not the number of a field.
int remove(int i) - removes field number "i" from the list of fields
being managed by the screen, and returns the number of fields
left on the screen after removal. If "i" is not the number of a
field, then nothing happens and the current field count is
Note that removing a field renumbers the remaining fields.
Also, the += operator can be used, with a screen on the left and a field
on the right, to add a field to a screen, returning a reference to the
Note that creating a screen, adding a field to a screen, or removing a
field from a screen causes no immediate visual effect. It is when the
screen is display()ed or edit()ed that the user sees anything.
Note also that since adding a field involves copying the field, and
since we plan to derive new types of field in the future, you must make
the copies of fields by using clone(), rather than by relying on the
Since this means that your screen must use dynamic memory allocation
(clone() dynamically allocates a copy), you should be sure to code an
appropriate copy constructor, = operator and virtual destructor for the
Both the screen class and the field class should be declared in a header
file screen.h, and coded in a source file screen.cpp. Including screen.h
should also make the dtio functions available for use.