Features


A Simple Application Environment

Mark A. Johnson


Mark Johnson has been designing software for a major R&D corporation since 1976. He received a BSCS from the University of Pittsburgh and his MSCS from Carnegie-Mellon. His current computer interests include languages, programming for children, business applications, and computer-generated music. Mark is continuing to develop other DCUWCU applications.

Having used a mouse in user interfaces since 1981, I believe it to be most convenient way to inform a computer program what you want it to do. I wanted to use a mouse in a number of PC programs and so looked into a few application environments. Microsoft Windows and Digital Research's GEM disappointed me, due to the complexity that had to be mastered. The resource construction sets, complex window management, and other overheads needed to write a simple application led me to write my own simple application environment based on Turbo C graphics routines and a public domain mouse interface.

My goal was to build an easy-to-use environment that provides a mouse-driven cursor, stacked pop-up menus, and forms that contain editable fields and a variety of selectable buttons. The environment would keep track of what the user was doing, inform the application as needed, and clean up after itself.

An additional goal was to facilitate porting the environment to other machines that have a mouse, bitmap graphics, console I/O, and a simple timer. I have the same DCUWCU environment on my PC compatible and Atari ST, allowing me to easily move applications between systems.

Operation

A typical application begins with a blank screen (or suitable greeting) showing an arrow-shaped cursor controlled by the mouse. Pressing the right mouse button displays a set of stacked pop-up menus. While holding the right mouse button down, the user selects an item (or another menu) from the front-most menu and then releases the button. If a menu item was selected, then the application acts on that selection. If another menu was selected, it is brought to the front of the menu stack, ready for another round of menu item selection. Pressing the left mouse button or a keyboard key usually causes an application-specific action, often resulting in a form appearing on the screen that the user must fill out. When processing the form, all mouse and keyboard events are handled by the environment. Keyboard input is directed to the current editable field, denoted by the special input cursor. A TAB moves the input cursor to the next editable field. An ESC (cancel) or ENTER (accept) terminates form processing, returning data and control back to the application. Some forms may contain small text labels, called form buttons, that are selected (or de-selected) by moving the cursor over them and pressing the left mouse button. There are three types of buttons: plain, radio, and exit. A plain button is a simple on/off switch. A radio button is a one-of-many switch, much like the buttons on a car radio. An exit button is like the plain button, but causes form processing to end.

The application environment works equally well when no mouse is present by using the cursor keys to simulate mouse motion and the function keys F1 and F2 to simulate the left and right mouse buttons. Pressing F2 once simulates pressing the right mouse button; another press of F2 simulates its release. A single press of the F1 button simulates the left mouse button.

Application Interface

The interface between application and environment was made as simple as possible: strings are used to define forms and menus, pointers to variables are used to store values collected by forms, and calls to functions inform the application of user events, such as menu selection or mouse button clicks.

The application environment follows (and is named after) what is called "The Hollywood Principle," (or "don't call us, we'll call you"). An application developer supplies four critical routines, called when the application environment detects various user interface events.

start(argc, argv, envp) int argc; char **argv, **envp;

This is the initialization routine called immediately after initializing the graphics interface but before the environment is completely started. It is passed the same arguments normally passed to a C main() routine. The start() routine usually initializes the application and creates the menu stack using repeated calls to add_menu().

menu(m, i)

The menu() routine is called whenever a menu selection is made. The application environment supports a stack of pop-up menus. Any number of menus can be supported, although only two or three are usually active at any one time in order to minimize interface complexity (see menu_state() below). The m argument identifies which menu was selected. When the menu is first declared (see add_menu()), the application provides a value that identifies the menu. This same identifer value is passed back to the application when a menu is selected. The i argument specifies which menu item was selected, a value of 1 meaning the first item, etc.

button(b, x, y)

The button() routine is called when a mouse button is pressed. The right mouse button is reserved for menu manipulation, all others are passed to the application. The b argument is the button number (usually 1) and the x and y arguments are the mouse coordinates when the button was pressed.

keyboard(key)

The keyboard() routine is called whenever a console key is struck. The character typed by the user is contained in the single argument.

timer(t)

The (optional) timer() routine is called whenever an application-requested timer expires. When the timer is requested, a value identifying the timer is passed to the application environment. The same identifer value is passed back to the application in the t argument when the timer expires.

Environment Interface

The application environment provides some basic routines that an application can call for control and service.

finish()

The finish() routine is called whenever the application is done and the program must exit.

add_menu(m, mdef) char *mdef;

The add_menu() routine adds a menu to the current set of pop-up menus maintained by the environment. An application typically initializes all its menus from the start() routine. The m argument is remembered by the environment and passed back to the application when a menu selection is made. The mdef argument is a string that defines the menu. For example,

add_menu(1, "Main:About|Help|Quit")
defines a menu identified as menu 1, titled Main, and with three items: About, Help, and Quit.

menu_state(m, on)

The menu_state() routine allows the application to activate or de-activate a particular menu. The m argument refers to the menu defined with a previous add_menu() call. The on argument should be set to 1 to activate or 0 to deactivate the menu.

menu_item(m, i, str) char *str;

The menu_item() routine is used to change the name of a particular menu item. For example, suppose a drawing program can turn a grid on and off. The application might have a menu item called Grid when no grid is shown and change it to No Grid using menu_item() when the grid is shown.

mouse_state(on)

The mouse_state() routine will activate or deactivate the mouse-driven cursor. The on variable should be set to 1 to show the mouse and 0 to hide it.

mouse_shape(type, bits, hotx, hoty) char *bits;

The application can control the cursor's shape with mouse_shape. There are two built-in forms: arrow and cross. A type value of 0 and 1 specify arrow and cross, respectively. A type value of 3 allows the user to specify a custom designed mouse cursor. The bits argument is a pointer to an eight-byte character array containing the mouse bitmap (8 x 8 bits). The hotx and hoty arguments indicate which bit in the bitmap is considered the hotspot of the cursor. For example, the cross form has a hotspot of hotx=hoty=3, which is the center of the 8 x 8 bitmap.

add_timer(t, wait) long wait;

Many applications, especially games, require some sense of the passage of time. Using add_timer(), the application can arrange for timer() to be called after some time has elapsed. The application's timer() routine can do such things as blank the screen if no activity has taken place for many minutes or move sprites around the screen after a few tenths of a second. The t argument identifies a particular timer and is passed back to the application when the timer expires. The wait argument specifies the needed delay in milliseconds (e.g. wait=1000L is a delay of one second).

form(def, argptr1, ...) char *def;

form() displays a form on the screen, collects data from the user, and deposits it in the variables pointed to by the argptr parameters. This routine is somewhat similar to scanf(). The form definition string defines a number of fields. For example,

" Name: %15s |Number: %5d |%[male|female] %[over 55]| %{ok}"
This form definition would result in the following being displayed in the middle of the screen surrounded by a rectangle.

Name:____________________
Number:_____
[male|female] [over 55]
    {ok}
Most of the text in the definition string is used as titles. A | signifies the beginning of a new line in the form. A data field begins with a % and is associated with a particular variable. There are five types of data fields. (For the examples that follow, assume the following declarations occur before the call to form(): char c, buf[11]; int x;). (See
Table 1. ) If a character pointer fdef points to the string described in Table 1, the following code fragment uses form() correctly.

char name[16], m_or_f = 0, over_55 = 1, ok = 0;
int number;
if (form(fdef,
        name, &number,
        &m_or_f,
        &over_55,
        &ok)) {
    /* do stuff with name, number, etc. */
}
After filling out the form, if the user selects the {ok} button or hits ENTER, form() returns a non-zero value. The data values collected by the form and stored in name, number, m_or_f, and over_55 are processed further by the if statement. If the user strikes the ESC key while filling out the form, form() returns zero and the processing doesn't take place.

An Example

Listing 1 is a simple drawing program that illustrates how to build a DCUWCU application. The code for this example and the complete source for the DCUWCU have been added to the CUG Library. See the New Releases column by Kenji Hino for more details.

Conclusion

I have used the "Hollywood Principle" design model for a number of projects and have found it to shorten development time and result in a robust application. The mouse is an effective user interface device and, when coupled with pop-up windows and forms, provides clean, uncluttered operation.

I would like to acknowledge the designers of the many mouse-based user interfaces I have used in the past, such as the Apple Macintosh, Microsoft Windows, DR/Atari GEM, but most significantly the Xerox Mesa Development System, for the inspiration to build this simple application environment.