|
|
The ETI form driver works very much like the ETI menu driver. As soon as the form driver receives a request, it checks if it is an ETI form request. If so, it performs the request and reports the results. If the request is not an ETI form request, the form driver checks if the character is data, that is, a printable ASCII character. If it is, it enters the character at the current position in the current field. If the character is not recognized as a form request or data, the form driver assumes the character is an application-defined command and returns E_UNKNOWN_COMMAND.
To illustrate a sample design for calling the form driver, we will consider a program that permits interaction with a sweepstakes entry form reproduced in ``Sweepstakes form output''.
+------------------------------------------------+ | | | Sweepstakes Entry Form | | | | Last Name First Middle | | _________________ ____________ ___________ | | | | Comments | | _____________________________________________ | | _____________________________________________ | | _____________________________________________ | | _____________________________________________ | | | +------------------------------------------------+
Sweepstakes form output
You have already seen much of the sweepstakes program in previous examples. ``An example of form driver usage'' shows its remaining routines.
/* This program displays a sweepstakes entry form. */#include <string.h> #include <form.h>
static void start_curses() /* see the previous section "ETI Low-level */ /* Interface to High-level Functions" */
static void display_form (f) /* create form windows and post */
static void erase_form (f) /* unpost and delete form windows */
/* define application commands */
#define QUIT (MAX_COMMAND + 1)
static int get_request (w) /* virtual key mapping */
static int my_driver (form, c) /* handle application commands */ FORM * form; int c; { switch (c) { case QUIT:
/* validate current field */
if (form_driver (form, REQ_VALIDATION) == E_OK) return TRUE; break; } beep (); /* signal error */ return FALSE; }
main (argc, argv) int argc; char * argv[]; { WINDOW * w; FORM * form; FIELD ** f; FIELD ** make_fields (); void free_fields (); int c, done = FALSE;
PGM = argv[0];
if (! (form = new_form (make_fields ()))) error ("error return from new_form", NULL);
start_curses (); display_form (form);
/* interact with user */
w = form_win (form);
while (! done) { switch (form_driver (form, c = get_request (w))) { case E_OK: break; case E_UNKNOWN_COMMAND: done = my_driver (form, c); break; default: beep (); /* signal error */ break; } }
/* terminate form processing */
erase_form (form); end_curses (); f = form_fields (form); free_form (form); free_fields (f); exit (0); }
typedef FIELD * (* PF_field ) ();
typedef struct /* define struct for creation */ { PF_field type; /* field constructor */ int rows; /* number of rows */ int cols; /* number of columns */ int frow; /* first row */ int fcol; /* first column */ char * v; /* field value */ } FIELD_RECORD;
static FIELD * LABEL (x) /* create a LABEL field */ FIELD_RECORD * x; { FIELD * f = new_field (1, strlen (x->v), x->frow, x->fcol, 0, 0);
if (f) { set_field_buffer (f, 0, x->v); field_opts_off (f, O_ACTIVE); } return f; }
static FIELD * STRING (x) /* create a STRING field */ FIELD_RECORD * x; { FIELD * f = new_field (x->rows, x->cols, x->frow, x->fcol, 0, 0);
if (f) set_field_back (f, A_UNDERLINE); return f; }
/* field definitions */
static FIELD_RECORD F [] = { LABEL, 0, 0, 0, 11, "Sweepstakes Entry Form", LABEL, 0, 0, 2, 0, "Last Name", LABEL, 0, 0, 2, 20, "First", LABEL, 0, 0, 2, 34, "Middle", LABEL, 0, 0, 5, 0, "Comments", STRING, 1, 18, 3, 0, (char *) 0, STRING, 1, 12, 3, 20, (char *) 0, STRING, 1, 12, 3, 34, (char *) 0, STRING, 4, 46, 6, 0, (char *) 0, (PF_field) 0, 0, 0, 0, 0, (char *) 0, };
#define MAX_FIELD 512
static FIELD * fields [MAX_FIELD + 1]; /* field buffer */
static FIELD ** make_fields () /* create the fields */ { FIELD ** f = fields; int i;
for (i = 0; i < MAX_FIELD && F[i].type; ++i, ++f) *f = (* F[i].type) (& F[i]);
*f = (FIELD *) 0; return fields; }
static void free_fields (f) /* free the fields */ FIELD ** f; { while (*f) free_field (*f++); }
An example of form driver usage
Function main first calls an application-defined routine make_fields to create the fields and new_form to create the form. Routine make_fields offers a somewhat different way to create fields from what we have seen previously. (Array F holds the string labels and field sizes; it can be changed so that make_fields can create any form.) Function main then initializes curses using start_curses and displays the form using display_form.
In its while loop, main repeatedly calls form_driver with the character returned by get_request. If the form driver does not recognize the character as a request or data, it returns E_UNKNOWN_COMMAND, whereupon the application-defined routine my_driver is called with the same character. Routine my_driver processes the application-defined commands. In this example, there is only one, QUIT. Note how this request automatically calls the form driver again, now with the REQ_VALIDATION request. Remember that this request is necessary to ensure that current field validation occurs before your end-user leaves the form. If validation is successful, my_driver returns TRUE. In turn, this sets done to TRUE, and the while loop is exited.
Finally, main erases the form, terminates low-level ETI (curses), frees the form and its fields, and exits the program.
This example is typical, but it is only one of many ways you can structure an application. ETI's flexibility lets you use it over a wide range of applications.
Like other ETI routines that return an int, the form driver returns E_OK if it recognizes and processes the input character argument. If it encounters an error, it returns one of the following: