Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!bcm!dimacs.rutgers.edu!aramis.rutgers.edu!paul.rutgers.edu!njin!princeton!phoenix.Princeton.EDU From: woodhams@phoenix.Princeton.EDU (Michael Woodhams) Newsgroups: comp.sys.handhelds Subject: HP48SX: Full screen menu program, mark III Message-ID: <5816@idunno.Princeton.EDU> Date: 30 Jan 91 22:05:23 GMT Sender: news@idunno.Princeton.EDU Organization: Princeton University Observatory Lines: 382 Sometime ago I wrote a program that would turn the top 5 rows of the HP48SX keyboard into menu keys, and displayed the menu options on the top of the screen. My use was to access frequently used astronomical constants and units, so it acquired the name PHYCONST. An improved version was posted by Tom Huber that had an improved user interface for setting up the menu, and had a cleaner structure. I have now taken his version and enhanced it again to produce mark III. I call this the full screen menu program (or fsmenu) as it is by no means restricted to physics or constants. Enhancements over Tom Huber's version include: (1) Variable menu size - from one to eight rows can be turned into a menu. (2) Multiple menus available - the programs (the menu modification program and the program that actually runs the menu) take the names of two variables as input, and these variables contain the menu information. (3) The ability to define a key to run another full screen menu. This allows multiple page menus, like the "next" key does for normal menus. (4) When redefining a key, it is possible to leave the current label unchanged by just pressing "enter" when prompted for the new label, and to leave the value unchanged by pressing "N" for no change. (5) Error checking to ensure that key labels do not overflow their boxes. (6) Error checking to gracefully abort if a key outside the menu range is pressed (including shifted/alpha keys inside the key range) Recommended use: Make a subdirectory called FSMENU somewhere, and put KEYSIZE, UCLEAR and UMOD in it. Put UMENU in your home directory. Using scrap paper, design your menu(s), deciding what you want to assign to each key, and how to label them. Run UCLEAR to generate a blank menu (it will prompt for how many rows you want the menu to have) and store the top of stack object (a list of list of lists) in a variable whose name suggests it contains menu values (I use UVL) and the GROB in a variable whose name suggests it contains a picture of the menu labels (I use UGR). Put the names of these variables on the stack as algebraics, the graphics variable name in level 2 and the values variable name in level 1. (e.g. 'UGR' enter 'UVL' enter) then run UMOD. It will display the menu labels so far (all blank initially) and wait for a keypress. Press the key you want to redefine. It will then prompt for a label string. If you press enter, the label will be left unchanged. If you type in a label which is too long, it will return to prompting for a new label. Once a label has been entered, it will give 6 options for what you want to do with this key. They are: C: enter a constant. Selecting this will prompt for a number. If you want to have units, append an underscore after the number and type in the units. (You can use the units menus to speed this process.) L: enter a library constant (if you have the Equation Library card. This comes from Tom Huber's update of the program, and as I don't have an EL card, I have never tested this part of the code.) M: make this key shift you to a different menu. You will be prompted to give the names of the variables containing the labels picture and the values list for the other menu. I recommend redefining the "next" key if you are going to do this. N: No change. Useful if you only wanted to change the label of a key, or pressed the wrong key to start off with. U: Make a units key. This behaves just like an entry from the built in units menus, including the blue and gold shift functions. Enter the name of the unit (without an underscore). After all this, the changes will be saved in the variables, and the program will exit with the variable names still on the stack. To redefine another key, just run UMOD again. To create another menu, run UCLEAR again and save the blank menu variables under different names (e.g. UVL2 and UGR2.) I store the resulting variables in my home directory and redefine the "CST" key to be \<< 'UGR' 'UVL' UMENU \>>. As the variables are in my home directory, they are available from anywhere in the directory hierachy. Furthermore, if (purely for the sake of argument) started gambling on the stock exchange and had a directory subtree devoted to such activities, by saving new 'UGR' and 'UVL' variables at the top of that subtree, I could get a different menu anywhere within that subtree, giving me interest calculations and conversions between Hong Kong and New Zealand dollars, while everywhere else, the old menu would still be available. Disclaimers: I do not yet have a cable, so the programs are entered by hand. Some of the "\" codes may be wrong (especially \/= for "not equals") and I may have mistyped something. I have used only standard RPL functions, so if this program caused your calculator to electrocute you, explode, start a nuclear war or make analogies between naughts and crosses (tic-tac-toe to american readers) and nuclear war, blame HP, not me. If despite the above you still want to sue me, go ahead. I'm a graduate student, and if you get everything I own, it still won't pay your legal fees. KEYSIZE: Each inner list contains information for one row. The first number is the number of keys in that row, the second is the x-coordinate of the last pixel of the label for the first key in that row. (The first pixel is assumed to be zero.) The third number is the x-coordinate of the first pixel in the second key, and the fourth number is the x-coordinate of the last pixel in the second key. The last number is the offset for each key beyond the second. (All the remaining keys are assumed to be the same size as the second.) There is one such list for each of the first 8 rows. { { 6 #20d #22d #42d #22d } { 6 #20d #22d #42d #22d } { 6 #20d #22d #42d #22d } { 6 #20d #22d #42d #22d } { 5 #42d #44d #64d #22d } { 5 #20d #24d #49d #27d } { 5 #20d #24d #49d #27d } { 5 #20d #24d #49d #27d } } checksum #45815d, 481 bytes UCLEAR: This program prompts for the number of rows of keys you want in your menu, then leaves a GROB of a blank keyboard (with the correct number of keys) and a list of lists of blank lists, which will be modified to contain the values/actions to be assigned to the keys. These should be stored in two variables, e.g. UGR and UVL. \<< "Enter number of rows" @ Get number of rows of keys and { V } INPUT OBJ\-> @ store it in local variable "n" \-> n \<< IF 'n<1 OR n>8 OR FP(n)\/=0' THEN KILL @ quit if n is out of range END ERASE {#0d #0d} PVIEW @ erase screen and display it 1 n FOR row @ for each row KEYSIZE row GET @ get the list of key size parameters LIST\-> DROP @ disassemble it into components \-> m e1 s2 e2 inc @ and store in local variables @ m=number of keys in this row @ e1=last pixel in the first key @ s2=first pixel in the second key @ e2=last pixel in the second key @ inc=distance between start of second and @ third keys \<< 1 m FOR col @ for each key in the row IF 'col==1' THEN @ if first row, then #0d e1 @ draw from pixel 0 to e1 ELSE @ else col 2 - inc * DUP s2 + @ draw from s2+(col-2)*inc SWAP e2 + @ to e2+(col-2)*inc END \-> x1 x2 @ put the left and right x-coordinates of @ the key into x1 and x2 \<< row 1 - 8 * DUP 6 + FOR line @ for line = (row-1)*8 to (row-1)*8+6 @ (for line=top pixel of key to bottom pixel) x1 line R\->B 2 \->LIST @ make coordinate list {x1 line} x2 line R\->B 2 \->LIST @ make coordinate list {x2 line} LINE @ draw line between coordinates NEXT @ next line \>> @ end of x1, x2 local variable block NEXT @ next col (i.e. next key in the row) \>> @ end of m, e1, s2, e2, inc variable block NEXT @ next row PICT {#8d #41d} "\Ga" @ write alpha on the alpha shift key 1 \->GROB GXOR @ (even if fewer than 6 rows were requested) PICT {#7d #49d} GROB 7 5 4020f72444 GXOR @ write left arrow on gold shift key PICT {#7d #57d} GROB 7 5 0102f71211 GXOR @ write right arrow on blue shift key PICT {#0d #0d} @ put PICT, {#0d #0d}, {#131d n*#8-#1} #131d n #8d * #1d - 2 /->LIST @ onto stack SUB @ and extract the picture of the keyboard @ from the graphics screen. (If there were @ not enough rows for the alpha and/or shift @ keys to be displayed, the alpha, left and @ right arrows that were drawn on the screen @ will be left behind at this stage { } @ Now make the list of key definitions @ These braces will delimit the list of @ row information 1 n FOR row @ for each row { } @ These braces will delimit the list of @ information for each key in the row 1 KEYSIZE row GET 1 GET @ get number of keys in the row from KEYSIZE FOR col @ for each key in the row { { } } + @ add an empty list to the row list @ for each key in the row NEXT @ next col 1 /->LIST @ Imbed the row list in another set of braces + @ add the row list to the master list NEXT @ next row />> @ end of n local variable block />> @ end of UCLEAR program Checksum: #32473d, 765.5 bytes UMOD: This program takes from the stack the names of the variables containing the keyboard picture grob (in level 2) and the key values list (in level one.) It leaves with the stack unaltered (i.e. the variable names are still there to make it easier to run several times in a row.) The names should be entered as algebraics, e.g. 'UGROB' ENTER 'UVALUES' UMOD. \<< DUP RCL SIZE @ find size (number of rows) of values variable \-> ugrob uvalues n @ store names of variables in ugrob, uvalues @ and number of rows in n \<< ugrob RCL PICT STO @ store keyboard picture in graphics screen {#0d #0d} PVIEW @ and display it 0 WAIT @ get a keystroke IF DUP n 1 + 10 * > THEN @ if keystroke comes from a row after row n DROP ugrob uvalues KILL @ restore stack and kill program END DUP 10 / IP @ find row number of the key SWAP IP 10 MOD @ and column number of the key \-> row col @ store in local variables row, col \<< KEYSIZE row GET @ get list for this row from KEYSIZE IF 'col==1' THEN @ if this is the first key in the row 2 GET #0d @ the rightmost and leftmost pixels of the key @ are e1 (2nd element of list) and #0 ELSE @ if this is not the first key in the row LIST\-> DROP @ disassemble the list col 2 - * @ put inc*(col-2) on the stack SWAP OVER @ stack contains: @ m e1 s2 inc*(col-2) e2 inc*(col-2) + ROT ROT + @ stack contains: @ m e1 e2+inc*(col-2) s2+inc*(col-2) ROT DROP ROT DROP @ stack contains: @ e2+inc*(col-2) s2+inc*(col-2) @ i.e. rightmost and leftmost pixels of the key END row 1 - 8 * @ stack contains: @(rightmost pixel) (leftmost pixel) (top pixel) \-> x2 x1 y @ store these in x2, x1, y \<< PICT @ put PICT on stack for use later 0 @ put a junk value on stack to drop inside loop DO DROP @ drop junk value or previous bad label STD @ put calc in std mode to display row and col row "," + col + " Label?" + @ assemble prompt string { \Ga } INPUT @ input label for key as a string 1 \->GROB @ turn it into a grob UNTIL DUP SIZE DROP @ loop until x size of grob is smaller than key 'x2-x1' EVAL \<= @ ("\<=" means less than or equals. I may have @ the wrong code here.) END DUP SIZE DROP @ get x size of grob on stack IF DUP #0d == THEN @ if the label was a null string DROP DROP DROP @ drop PICT, grob and grob size from stack, @ and leave keyboard picture unchanged ELSE y 'y+6' FOR line @ for each row of pixels in the key x1 line R\->B 2 \->LIST @ make pixel coordinate {x1 line} x2 line R\->B 2 \->LIST @ make pixel coordinate {x2 line} LINE @ draw a line between them NEXT @ the key has now been erased 'x1+x2+2' EVAL SWAP - @ find x-coordinate to put grob at 2 / @ (x size of grob was already on stack) y #1d + @ find y-coordinate to put grob at 2 /->LIST SWAP GXOR @ put label in keyboard picture END @ end "if grob size = 0" />> @ end of x2, x1, y local variable block PICT {#0d #0d} #131d n #8d * 2 /->LIST @ coordinates of lower right corner of picture SUB ugrob STO @ extract picture from screen and store it uvalues RCL @ get key values list DUP row GET @ extract list for the row DO @ loop until valid key input "C-constant object" 1 DISP @ display menu "L-library constant" 2 DISP "M-menu" 3 DISP "N-no change" 4 DISP "P-program name" 5 DISP "U-unit" 6 DISP 0 WAIT IP @ get (integer part of) key number CASE DUP 13 == THEN @ "c" was pressed DROP @ drop key number "Constant Object" { V } INPUT OBJ/-> @ input constant as string and make it object 1 \->LIST @ turn it into a one element list 1 @ leave 1 on stack to indicate success END DUP 26 == THEN @ if "l" pressed DROP @ drop key number "Constant Name" { \Ga } INPUT @ input constant name as a string "\<< '" SWAP + @ make string "' CONST \>>" + @ "\<< 'constantname' CONST \>>" OBJ\-> @ turn string into a program 1 \->LIST @ put program in a list 1 @ indicate success END DUP 31 == THEN @ if "m" pressed DROP @ drop key number "\<< '" @ start of program string "Graphic variable name" { \Ga } INPUT + "' '" + @ get name of picture variable, add to string "Values variable name" { \Ga } INPUT + "' UMENU \>>" + @ string contains @ "\<< 'grobname' 'valuename' UMENU \>>" OBJ\-> @ turn string into a program 1 \->LIST @ put program in a list 1 @ indicate success END DUP 32 == THEN @ if "n" pressed DROP @ drop key number DUP col GET 1 @ get current value of key to stack 1 @ indicate success END DUP 34 == THEN @ if "p" pressed DROP @ drop key number "Program name" { \Ga } INPUT "\<< " @ get program name as a string SWAP + " \>>" + OBJ\-> @ make program \<< programname \>> 1 ->LIST @ put into a list 1 @ indicate success END 43 == THEN @ if "u" pressed "Unit Name" { \Ga } INPUT @ get unit as a string \-> u \<< "\<< 1_" u + " * \>>" + OBJ\-> @ make program \<< 1_unit * \>> "\<< 1_" u + "CONVERT \>>" + OBJ\-> @ make program \<< 1_unit CONVERT \>> "\<< 1_" u + " / \>>" + OBJ\-> @ make program \<< 1_unit / \>> 3 \->LIST @ make a list of the three programs \>> 1 @ indicate success END 0 @ else indicate failure END @ end of case statement UNTIL @ loop again if 0 on stack END col SWAP PUT @ put the object generated into row list row SWAP PUT @ put the modified row list into main list uvalues STO @ store in values variable />> @ end of row, col local variable block ugrob uvalues @ return variable names to stack />> @ end of ugrob, uvalues, n local variable block />> @ end of program checksum #61103d bytes 1618.5 UMENU: This program takes the names of a grob and key values list from the stack, displays the keyboard picture grob, waits for a keystroke, and executes the appropriate code from the values list. \<< \-> ugrob uvalues @ store variable names in ugrob, uvalues \<< LCD\-> @ turn stack display into a picture {#0d #0d} ugrob RCL REPL @ overwrite the top of picture with keyboard PICT STO @ and store in graphics screen {#0d #0d} PVIEW @ store composite keyboard/stack display 0 WAIT @ get keystroke IFERR @ (keystroke might be from too low on keyboard) uvalues RCL @ put values list on stack OVER 10 / IP GET @ extract row from this list (could give error) OVER 10 MOD GET @ extract key from row list (should not give @ error) THEN @ (does following if error) DROP DROP DROP KILL @ return stack to pristine status and die END IFERR @ (values list might not have defined response @ for a shifted key, or the key might never @ have been defined by UMOD) SWAP FP 10 * GET @ extract program from key list THEN DROP DROP KILL @ restore stack and die END EVAL @ execute the program extracted from values @ list \>> @ end of local variables list. \>> chksum: #17079d, 254 bytes.