# Evolution of a Computer Application - User Interface

Author(s):
John J. Wavrik

When I first circulated Groups16 for review as an illustration of programming methodology, several reviewers suggested that it might make a good instructional program -- provided it could be made easier for students to use.

Groups32, as presented so far, requires the user to learn a collection of command names, together with the parameters (and order) required for their use. As with similar research systems, there are actually only a handful of top-level commands in the system. (The others are useful mainly for those who wish to write programs to extend the system.) It is not unrealistic to use the system with a "command line" interface, but there is a learning curve involved, making casual use more difficult. Typing commands and their arguments is slow. Also, a more constrained type of input would decrease the need for error trapping.

I explored several methods to make these top-level commands more accessible and to ensure valid input.  In one attempt, evoking a top level command provided prompts for parameters. In another, I presented the top-level commands in a menu -- clicking on a command initiated a prompt for input.

The approach I finally used, a "command completion" interface, appears to be the quickest and easiest to use. In this interface, the user is presented with a list of available commands:

CENTER      CENTRALIZER  CHART     CONJ-CLS

COSETS      EVALUATE     GENERATE  GROUP

NORMALIZER  ORDERS       PERMGRPS  POWERS

QUIT        RESULT       RIGHT     SEARCH

STOP        SUBGROUPS    TABLE


The user types enough letters of a command to distinguish it from the others. To generate a table, for example, the user needs only to type "T", since this is the only command that starts with T. To obtain a list of conjugacy classes, the user types "CON".  The interface discards all letters typed beyond the bare minimum (so the user need not worry about mistyping subsequent characters).  Once the interface identifies a command, it prints the rest of the command and prompts for any arguments needed to carry out its operation.

G1>> CONJ-CLS   Group Number 8    { A }   { B C }   { D E F }


Typing "CON" distinguishes the CONJ-CLS command and asks for a group number.

Here is a sketch of how I implemented the interface:

The commands and information about them are put into a binary tree.  Each node in the tree has a name field (for a string of a maximum size), the address of the node to the left, the address of the node to the right, and the execution address of the word used to carry out the command.

            32 CONSTANT Max#Cmds

24 CONSTANT CmdSize

0 VALUE    #Cmds

CmdSize CELL + CONSTANT EntrySize

Max#Cmds  CONSTANT #Nodes

CREATE 'Tree1  #Nodes NodeSZ * ALLOT ALIGN

SZ + 1 CELLS + @  ;

: Exec  ( n_addr -- )

SZ + 2 CELLS + @ EXECUTE ;

: Left!  ( x n_addr -- ) SZ + !  ;

: Right! ( x n_addr -- )

SZ + 1 CELLS + ! ;

SZ + 2 CELLS + !  ;

: Name! ( $n_addr -- ) DUP SZ BLANK$!! ;

: Leaf? ( n_addr -- flag )

DUP Right 0=  SWAP Left 0=  AND  ;


Each new command is added to the tree to the left of an existing node if the name comes before in lexicographic order, and to the right if the command comes after.  The commands are introduced by the word >CMD, which is used in the form

>CMD <menu_name> <word_to_execute>


The word_to_execute contains prompts and input routines to get any parameters needed from the keyboard.  There is also a provision for including descriptive "help" information that will be printed if the user types HELP before typing the name on the menu.

Here is an example of how the Table command is made into a word %Table that prompts for input:

:  %Table

Help:

This prints a table for the group requested

(and makes that the current group). Elements

are represented by letters A to Z and the

symbols [  ] ^ _ and

Help;

." for " ['] Get-Grp CATCH 0=

IF CR Table THEN ;

>CMD TABLE %Table


I have written a collection of input commands.  For example, Get-Grp is the command to get a group number. In all cases, the system waits for the user to type a string, which is put into the terminal input buffer (TIB) as if it had been typed at the keyboard in an interactive session.  The input is then processed by Forth words that read the input stream.  Also, the cursor position is saved at the start of input, and the cursor is returned to this position if there is an error in the input.

Here are other input commands that can be used for writing the prompted input sections.

2VARIABLE Save-Pos

: Get-TIB  ( --  )  AT? QUERY AT

>IN @ 0 WORD

COUNT TYPE >IN !  ;

: Get-Num  ( -- n )  ." Number "  AT?

Save-Pos 2!

BEGIN  Save-Pos 2@ AT

Get-TIB  BL WORD

COUNT ?DUP 0= THROW

NUMBER?  IF   DROP TRUE

ELSE 2DROP BEEP FALSE

THEN

UNTIL  ;

: Get-Grp  ( -- n )   ." Group "

BEGIN  ['] Get-Num CATCH

IF TRUE THROW

ELSE  G-OK

DUP 0= IF CR 10 SPACES THEN

THEN

UNTIL  ;

: Get-Set ( -- set )

." set: { "  Get-TIB ."  }"

0  0 WORD   COUNT 2DUP UPPER  0

?DO  DUP C@ ID -

DUP 0 MaxOrd 1- BETWEEN

IF    ROT Member! SWAP

ELSE  DROP  THEN

1+

LOOP  DROP  ;

: Get-Ele  ( -- ele ) ." element "

0 BEGIN

DROP KEY UPC ID -

DUP 0 Gord 1- BETWEEN

DUP 0=  IF BEEP THEN

UNTIL ;

: Get-Ele.  ( -- ele ) Get-Ele DUP .Ele ;


Here is how the interface works. The characters typed by the user are added to an incomplete command string. Each time a character is added, the tree is searched to see if the string matches the leading part of a name in the tree.  If there is no match, the user is informed (by a beep), and the latest character is not accepted. If there are multiple matches, the system waits for further characters. If there is only one match, the remainder of the name is typed and the stored command is executed.

Since the user must type additional information from the keyboard, this interface has proved to be faster than one in which the user selects commands with a mouse. An additional feature of the interface is that it is very easy to add additional commands -- so the interface is extensible.

It is easy to learn to use the interface, and no programming is required. As a result, Groups32 can be easily integrated into courses in abstract algebra.

The original version of the interface used a single ordered list of commands. In later revisions I used a single binary tree. When I added permutations, I revised the code for the interface to enable using more than one tree. In Groups32 the permutation commands are in a second tree and there is a separate menu:

  CREATE     ELEMENTS   HELP      INSTALL
`