[comp.sys.handhelds] Friendly HP 48 User Interface

akcs.aaron@hpcvbbs.UUCP (Aaron Boonshoft) (04/22/91)

%%HP: T(3)A(R)F(.);
DIR

@ Hi, I recently graduated from The Ohio State University and moved to
@ Corvallis Oregon to pursue a career in handheld computing.  As I
@ learn more about programming these devices, I have come to realize some
@ things about user interfaces.  The following summarizes some of what I
@ have learned.  I hope it is helpful.

@*********************************************************************

@                 +===========================+
@                 | HP48 SCIENTIFIC EXPANDABLE|
@       A         |+-------------------------+|   Hi!  How are you?
@                 ||   <( O )>     <( O )>   ||             
@                 ||                         ||         /
@    FRIENDLY     || [  ]               [  ] ||  ______/
@                 ||    [  ][  ] [  ][  ]    ||
@                 |+-------------------------+|
@     HP 48       |===========================|
@                 || [A] [B] [C] [D] [E] [F] ||
@                 || MTH PRG CST VAR [^] NXT ||
@      USER       || ['] STO EVL [<] [v] [>] ||          by
@                 || SIN COS TAN SQR Y^X 1/X ||
@                 || [ENTER] +/- EEX DEL [<= ||
@     INTER-      || [a]  [7]  [8]  [9]  [/] ||    Aaron Boonshoft
@                 || [<]  [4]  [5]  [6]  [X] ||
@                 || [>]  [1]  [2]  [3]  [-] ||
@      FACE       || [ON  [0]  [.]  SPC  [+] ||
@                 +===========================+

@ Introduction:

@ One of the more challenging aspects of writing professional software
@ for the HP 48 is the user interface.  Professional software normally
@ requires a very clean, friendly, and flexible user interface.
@ The software should not generate an error regardless of the keys the
@ user presses (including [ATTN]) or of the input data the user enters
@ (including total gibberish).  The user interface is often time
@ consuming to design and debug.  It may also account for more
@ than half of the code in a project.  One way of combating the
@ problems of writing user interface code is to write the code in the
@ form of subprograms (programs designed to be used by other 
@ programs).  In this form, the code may be used for many different
@ projects.  This may greatly reduce their size and development time.

@ Below are five sets of programs and subprograms.  The first set
@ just contains examples of how the other four are used.  Each of the
@ other four contain one major subprogram which, in some cases, uses
@ the help of supporting subprograms or other major subprograms.  The 
@ subprograms take care of some general I/O needs and the inputting of
@ real numbers.  They are not designed to handle all I/O.

@ * BOXV is for demonstration only.  It directly or indirectly
@     makes use of all the other sets.
@ * RUN makes interfaces cleaner by taking program objects off the
@     stack if the [ATTN] key is pressed.  It will also return the
@     user to the menu used before the program was run.
@ * IPMO adds flexibility by allowing the user to choose a menu option
@     or the stack at an INPUT prompt.  It makes use of PAUSE.
@ * CIA makes interfaces more robust by checking for bad input of real
@     numbers and telling the user what's wrong.  It will also do
@     conversions with unit objects (including ones that have the
@     underscore missing.)
@ * PAUSE uses an alarm to halt program execution for any number of
@     seconds.  It can also be used to update the stack display.

@ (NOTE: Subprogram EB in the RUN set is also used by IPMO and CIA)

@ All of the subprograms have been written as straightforwardly as
@ possible to allow for modifications.  The only programming trick
@ that is used is to store some objects as strings.  This technique
@ was used four times in IPMO to save about 210 bytes.  Note, however,
@ that doing this makes the code less obvious and slower to a small
@ degree.

@*********************************************************************

@ BOXV: Box Volume Example

@ BV  is just an example program for showing how IPMO and CIA can be
@ used.  BOXV uses RUN to execute BV.  BOXV or BV will ask the user
@ to input the volume of a box or it will CALC'ulate it from the
@ dimensions.  A volume of 1.2_ft^3 is used to demonstrate the use of
@ default values.  To really see why the user interface can be called
@ professional, try entering negative numbers or gibberish, entering
@ 3ft^3 instead of 3_ft^3 or pressing the ATTN key while running BOXV.
@ Executing ERUN demonstrates how RUN deals with an error caused by
@ something other than pressing the ATTN key. See the sections below
@ this one for more information about RUN, IPMO and CIA.

BOXV @ Compute Box Volume ( --> box_volume )       BYTES # 61780d 35.5
\<< 'BV' RUN \>>

BV @ Subprogram for BOXV  ( --> box_volume )        BYTES # 57289d 419
\<<
DO
 "Box Volume?" ":V:" "1.2_ft^3" 45 {"CALC"} IPMO
 IF THEN
  43 {1_ft 'x > 0'} \-> M C \<<
  DO M TMENU "Box Width?"  ":W:" INPUT C CIA UNTIL END
  DO M TMENU "Box Depth?"  ":D:" INPUT C CIA UNTIL END
  DO M TMENU "Box Height?" ":H:" INPUT C CIA UNTIL END
  * * 1 \>>
 ELSE { 1_ft^3 'x > 0'} CIA END
UNTIL END 1_ft^3 * "V" \->TAG 
\>>

ERUN @ Example of RUN catching an error  ( --> )     BYTES # 31101d 40
@ Note that a list can be evaluated.
\<< { "" 2 * } RUN \>>

@*********************************************************************

@ RUN: Evaluate Object and Trap Errors

@ RUN is designed to evaluate programs and other objects.  If the [ATTN]
@ key is pressed while using RUN, the stack will be reset to the input
@ stack.  Unlike the LASTSTACK operation, it does not require the user
@ to press any additional keys or have any particular flag setting.
@ Using RUN will bring the back the menu and flag settings used before
@ the program started.

@ Note that there are some cases where pressing the [ATTN] key may not
@ be caught by RUN:
@ * If [ATTN] is pressed "immediately" after starting RUN
@ * If [ATTN] is pressed two are more times "rapidly"
@ * If the program being evaluated by RUN contains an IFERR command

@ RUN STACK INPUT
@   Level 1: Object to be evaluated by RUN
@    (other levels may contain input for the object)
@ RUN STACK OUTPUT
@   If [ATTN] was "not" pressed, the stack will contain the output of
@    the object evaluated by RUN.
@   If [ATTN] was pressed or the object evaluated with an error,
@    the stack will be reset to the input stack minus level 1.

RUN @ Evaluate Object                               BYTES # 57031d 276
\<< 
DEPTH ROLLD DEPTH 1 - \->LIST RCLMENU RCLF \-> prg stk men flg
\<<
IFERR stk LIST\-> DROP prg EVAL THEN 
IF ERRN #0d SAME NOT THEN
 CLLCD "An error has occurred" 1 DISP "while evaluating..." 2 DISP
 prg 3 DISP ERRN 5 DISP ERRM 6 DISP EB 3 FREEZE END
DEPTH DROPN stk LIST\-> DROP END
flg STOF men TMENU
\>> \>>

EB @ Error Beep ( --> )                            BYTES # 32606d 33.5
\<< "1400 .1" STR\-> BEEP \>>

@*********************************************************************

@ IPMO: INPUT with MENU Options

@ IPMO may be used instead of (really in addition to) the built-in
@ INPUT command.   It allows the user to choose a menu option rather
@ than inputting the requested data.  It also allows the user to
@ access an empty stack to compute the input if necessary.

@ IPMO STACK INPUT
@   Level 5: INPUT command "stack prompt" (3 lines or less)
@   Level 4: INPUT command "command-line prompt" (list not allowed)
@   Level 3: Default value, any object, (should be "" if no default)
@   Level 2: Menu displayed during stack INPUT (real number or list)
@   Level 1: Menu displayed during menu INPUT (must be a list)

@ IPMO STACK OUTPUT
@   Level 2: INPUT command "result" if 0 in level 1
@   Level 1: Exit Condition, 0 for INPUT, 1 to 6 for menu key

@ When the user is asked for input by IPMO, one of five things happens
@ depending on which key is pressed first:

@   ( 1.)  [ENTER] key will cause IPMO to end.  The default value and
@   a 0 will be the stack output.

@   ( 2.)  [0],[1],[2],...,[9],[.],backspace or [EXX] keys will cause
@   the 2nd level menu to be displayed and the real INPUT command will
@   be executed with the appropriate data appended to the command line
@   prompt.  The default, if any, will vanish from the display.  The
@   "result" from INPUT and the number 0 will be the stack output.

@   ( 3.)  Any menu key that is not blank will cause IPMO to end.
@   A number from 1 to 6 corresponding to the menu key (going left to
@   right) will be the stack output.

@   ( 4.)  [CONT] will cause the stack to be saved and IPMO to HALT.
@   An empty stack is then available for the user to compute the
@   required input.  When [CONT] is pressed again, IPMO will make
@   the object in level 1 a string and leave it and 0 on the stack.

@   ( 5.)  [ATTN] key will cause an error.  An error trap should be
@   used outside of IPMO.  RUN is recommended.

@ Pressing any other key will result in an error tone.  The
@ only exceptions are shifted versions of most of the keys above.
@ Only [CONT] and [ATTN] are shift sensitive.

IPMO @ INPUT with MENU Options                    BYTES # 48856d 669.5
\<<
5 DUPN CLLCD TMENU DROP + 3 \->GROB SWAP 3 DISP
"(Press CONT for stack)" 1 DISP
LCD\-> "{#0d#46d}" STR\-> ROT REPL \->LCD
@sON EN M6 M5 M4 M3 M2 M1 [0][1][2][3][4][5][6][7][8][9][.][<][EXX]
@ -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9 10 11 12 13
"{91 51 16 15 14 13 12 11 92 82 83 84 72 73 74 62 63 64 93 55 53}"
STR\->
DO
 DUP -1 WAIT IP POS 8 -
 CASE DUP
  1 \>= THEN C$ 41 {"0""1""2""3""4""5""6""7""8""9"".""""1E"} STR\->
             SWAP GET 5 ROLLD DROP2 TMENU DROP + INPUT 0 1 END DUP
 -5 \>= THEN NEG 1 + 3 PICK C$ 14 {""""""""""""} STR\-> + OVER GET 
             IF "" \=/ THEN 7 ROLLD 6 DROPN 1
             ELSE EB NOT END END DUP
 -6  == THEN 4 DROPN + SWAP DROP 0 1 END
 -7  == THEN DROP2 TMENU 3 DROPN DEPTH \->LIST \-> \255 \<<
0 PAUSE "Place desired input on
stack level 1 and then
press CONT to continue
running program." 1 DISP 3 FREEZE HALT
             IF DEPTH THEN \->STR DEPTH ROLLD DEPTH 1 - DROPN
             ELSE "" END \255 LIST\-> 1 + ROLL \>> 0 1 END
 EB 0 END
UNTIL END
\>>

@*********************************************************************

@ CIA: Check Input Acceptability

@ CIA will verify that the user has INPUT a valid real number based on
@ a check list.  The real number may be tagged or have units but it
@ must be contained in a string.  CIA will use ERR to display what
@ is wrong to the user if the INPUT value is not acceptable.

@ CIA STACK INPUT
@   Level 2: "result", INPUT value
@   Level 1: { unt rng }, check list (see below)
@ CIA STACK OUTPUT
@   Level 2: new_result, if 1 in Stack level 1 (real number)
@   Level 1: OK_flag, 1 if "value" OK, 0 otherwise

@ The check list must contain two values:
@   unt = the desired input units.  unt=1 if units will be ignored.
@         If the unt is anything else, the INPUT value will be
@         CONVERT'ed to those units and then the units will be removed.
@         The new_result will be a real number without tags or units.
@  'rng'= an expression which results in 1 if the INPUT value is
@         within range or 0 if not.  The expression must refer to the
@         INPUT value as 'x' as in 'x\>=0' or '2<ABS(x) AND ABS(x)<3'.
@         If rng=1, any INPUT value will be within range.

@ Note that you may want to tell the user what units are required (if
@ any) and what range of values are allowable.  This could be done as
@ part of the prompt messages for INPUT or IPMO.

@ Also note that during the INPUT command, PRG entry mode is used.
@ This will cause 3_ft^3 to be entered as 3ft^3 unless you explicitly
@ type in "_" character.  CIA is smart enough, with the help of ISU,
@ to recognize and compensate for this in virtually every case.  In
@ other words, 3ft^3 will be treated like 3_ft^3 so the user does not
@ have type the "_" character when using units.

CIA @ Check Input Acceptability                   BYTES # 57037d 590.5
\<<
DEPTH SWAP LIST\-> DROP \-> dep unt rng \<<
CASE
 IFERR STR\-> THEN
  ISU IFERR STR\-> THEN 1
 ELSE 0 END ELSE 0 END  THEN DROP "    Invalid Syntax" ERR END
 DEPTH dep - 1 +
 IF DUP 1 == THEN
  ROT DTAG 3 ROLLD
  IF
   3 PICK TYPE 0 ==
   3 PICK TYPE DUP 6 ==
   SWAP 7 == OR AND
  THEN
   DROP _ 0
  END END DUP                THEN 1 + DROPN "Only One Value Allowed"
                                   ERR END DROP
 DTAG DUP TYPE DUP 13 == XOR THEN DROP "Must be a Real Number" ERR END
 unt 1 SAME NOT OVER TYPE AND
  IF THEN IFERR unt CONVERT
   THEN 1 ELSE UVAL 0 END
  ELSE UVAL 0 END            THEN DROP2 "  Inconsistent Units" ERR END
 rng { x } 3 PICK + \|^MATCH
 DROP \->NUM NOT             THEN DROP "  Value Out of Range" ERR END
 1 END
\>> \>>

ISU @ Insert Underscore Character                 BYTES # 39323d 196.5
@ ( "ValueUnits" --> "Value_Units" )
\<<
 DUP SIZE 1
 IF DUP2 \>= THEN FOR n
  IF "0123456789" OVER n DUP SUB POS THEN
   IF "^" OVER n 1 - DUP SUB \=/ THEN
    DUP 1 n SUB "_" + SWAP n 1 + MAXR
    \->NUM SUB + 0 'n' STO END END
 -1 STEP ELSE DROP2 END
\>>

ERR @ Display Input Error  ( "message" --> 0 )       BYTES # 10754d 87
\<< CLLCD "Sorry, not acceptable:" 3 DISP
5 DISP {"OK"} TMENU EB -1 WAIT DROP 0 \>>

@*********************************************************************

@ PAUSE: Timed Program HALT

@ PAUSE will set an alarm and HALT.  The alarm will CONT the program
@ after a given number of seconds.  One reason why this is useful is
@ that it allows the calculator time to update the stack display.
@ PAUSE uses ATCT and ADDT to do some date and time arithmetic.  They
@ use HP 48 HMS and Date formats.

PAUSE @ Timed Program HALT  ( seconds --> )          BYTES # 19068d 88
\<< .2 MAX 3600 / \->HMS MEM DROP ATCT
\<< DELALARM CONT \>> + STOALARM DROP HALT \>>

ATCT @ Add Time to Current Time                    BYTES # 30370d 38.5
@ ( Delta_Time --> {Date2 Time2} )  Computes Time2 and Date2 by adding
@ Delta_Time to the current Time and Date.
\<< DATE TIME 2 \->LIST SWAP ADDT \>>

ADDT @ Add Time to a Date and a Time                 BYTES # 50943d 77
@ ( {Date1 Time1} Delta_Time --> {Date2 Time2} )
@ Computes Time2 and Date2 by adding Delta_Time to Time1 and Date1.
\<< SWAP LIST\-> DROP ROT HMS+ DUP 24 / IP
ROT SWAP DATE+ SWAP 24 MOD 2 \->LIST \>>

@*********************************************************************

END