Kirk Woodward (harryst@castel.nl) PULL-DOWN MENU ------------------------------------------------------------------------------ DEFINT A-Z DECLARE SUB menuSub6 () DECLARE SUB menuSub5 () DECLARE SUB menuSub3 () DECLARE SUB menuSub4 () DECLARE SUB menuSub2 () DECLARE SUB menuSub1 () DECLARE SUB menuTop () DECLARE SUB eraseSubMenus () DECLARE SUB showTopFrame () DECLARE SUB showSubFrame () DECLARE SUB showSubText (dimSwitch$) DECLARE SUB showSubHighlight () DECLARE SUB getSubDecision () DECLARE SUB showTopText () DECLARE SUB showTopHighlight () DECLARE SUB getTopDecision () DECLARE SUB DisplaySubMenu () DECLARE SUB topBarDisplay (topBarText$(), topSelection, itemWanted) DIM topBarText$(1 TO 6) ' the text on the top line of initial menu ' We have opted to designate the menu elements as COMMON SHARED so that ' any part of the menuing system will be available from any part of your ' application. COMMON SHARED subMenuText$() COMMON SHARED topBarText$() COMMON SHARED topSelection COMMON SHARED topHighlight COMMON SHARED subMenuToShow COMMON SHARED subSelection COMMON SHARED mc COMMON SHARED position COMMON SHARED strippedTopBarString$ '$DYNAMIC ' Converted from PowerBASIC to QuickBASIC by Mr. Snow^Xtance ' Coders Alliance & DeeJee'z Team ' ' E-Mail: mrsnow@freemail.nl ' ================== ' bbmenu.bas ' ================== ' ' Does the world REALLY need another bounce bar menuing program? ' ' I LOVE Microsoft's User Interface - but - wow! the baggage ' one has to carry to use it! ' ' By way of comparison: If you load up MS's UIDEMO.BAS along ' with the required LIB and compile it you'll have an .EXE file ' of 120,000 bytes(!). Friends, thats BEFORE you even start ' writing your program! ' ' If you compile BBMENU.BAS you'll wind up with an .EXE file ' of 54,848 bytes and -- for what I needed -- I had everything ' I needed UI for!! i.e., get, and act upon, an operator's ' decision. ' ' Let me be the first to say: UI can do a whale of a lot ' more than BBMENU does -- BUT -- how much more do YOU need ' to do? I just KNOW I could get you some windowing, shadowing ' ect for a WHOLE lot less than the 66,000 bytes BBMENU doesn't ' need as it stands now! ' ' Better Yet: How 'bout YOU show us YOUR stuff? ' ' Register this source code, gimmie a little credit at the top of ' your program, then YOU add what you feel you've "gotta have" and ' send it back up to this BBS with a new name??? ' ' Sound like fun? Sure -- it is! Get goin' on becoming a ' published author yourself! ' ' Register your use for $25 and get the NEWEST version PLUS ' two ADDITIONAL SUBs that do meaningful work and will save your ' time! ' ' (Those additional SUBs register separately for $10-$25. You ' get 'em free for registering.) ' ' SOURCE? OF COURSE! You always get full source code with ' your registration. ' ' We accept Visa, MasterCard or American Express credit cards, ' 24 hours a day, 7 days a week. ' ' ' Kirk Woodward CompuServe: 70146,51 ' People Centered Programs ' PO Box 610171 ' Dallas, TX 75261-0171 ' REGISTRATIONS ONLY: 1-800-553-5883 ' 817/488-4940 FAX: 817/488-4945 ' ' Here's the logic of this menuing system: ' ' 1. Program Starts with top line display of the topBarText$() ' array. ' ' 2. Operator makes a selection with the left and right arrow ' keys and touches ENTER - or - touches the highlighted letter. ' ' 3. That 'pulls down' the secondary menu. ' ' 4. Operator makes a selection from the secondary menu ' via arrow keys and ENTER or highlighted letter. (Same ' as the Top Bar, except that the sub menus all use A-Z) ' ' Additionally, when the sub menu is pulled down, the ' operator can move left or right, pulling down menus as ' they go. (The 'old' pulled down menu is cleared from the ' display. If you prefer to leave it on the screen -- in ' effect "stacking" the menus -- just REM out the lines in ' the eraseSubMenus SUB or delete the call to that sub in ' getSubDecision SUB) ' ' A short explanation of "bounce bar" technology, or, things ' are not what they appear to be! ' ' To get the effect of a moving bar of light that shows the ' operator's decision in a very graphic manner, two things happen ' very quickly: ' ' 1. The existing highlighted text must be over ' written with the same characters un-highligted. ' ' 2. The new selection must be 'reversed' (or high- ' lighted) and printed right on top of the text ' printed in 1. ' ' I have also elected to add another touch: 'Diming' the texts ' that are no longer under consideration by virtue of the ' operator's decision(s) and "jumping" the highlight bar should ' the operator elect to touch a highlighted key rather than ' moving the bar to an item. These effects are, again, created ' by re-writing affected segments of the screen. ' ' Students of the process can slow the action down to see each ' process as it happens by setting a break point - or the command ' STOP at the end of 4 SUBs: ' ' 1. showTopText ' 2. showTopHighlight ' 3. showSubText ' 4. showSubHighlight ' ' Place the break point at the END SUB command in each SUB or ' in the blank line above it type: STOP. Then run the program. ' As you hit each stopping point, touch the F4 key to see the screen ' the program has created. (The F5 key will continue running the ' program) ' ' Be sure to REM out your STOP commands! programStarts: SCREEN 0 CLS ' The nested nature of the SUB calls in this program make ' the "out of stack space" error a possibility should the ' operator pull down a menu and then hold down the left or ' right arrow without stopping to make a selection. Over several ' crash tests we found the program could take about 15 such ' non-decision making repetitions before crashing. If you feel ' you need to protect against such odd stroking, the appropriate ' measure would be to set a larger stack (it will deny the space ' to other parts of your application.) ' ' Out of Stack space is not a trappable error and the STACK and ' CLEAR commands cannot appear in a SUB. ' ' The 'absolute' solution would be to disable the program's ' present ability to respond to left and right arrow presses ' in the SUB getSubDecision. That will force the operator to ' return to the top bar menu in order to move to a new sub menu. ' ' Our recommendation: Build your application with the feature ' included. If out of stack space becomes a problem as you test ' the finished application, disable the feature in the SUB ' getSubDecision. ' ' We tested the top bar menu with the arrow keys depressed for ' several THOUSAND repetitions with no problems. ' CALL menuTop ' Trap a "N"o answer to the question about quitting the program ' in the menuTop SUB (the topSelection variable will = 27) IF topSelection = 27 THEN GOTO programStarts: END IF evaluateChoice: ' trap ESC key press in the sub menu IF subSelection = 27 THEN eraseSubMenus GOTO programStarts: END IF ' two values are returned to this main module . . . ' ' These nested SELECT CASE blocks call the appropriate ' action for each operator selection. ' ' As it is now, we have made provision for all the demo ' selections . . . if you change the number of items on ' a sub menu, you will need to adjust the number of CASE ' statements. (The SUB getSubDecision accepts all twenty sub ' menu selections, so what follows is where an invalid entry ' would be trapped. You are correct that the entry error ' could be trapped in getSubDecision, but if each menu is ' different in terms of items, you would need a separate getSubDecision ' for each menu. ' ' This secondary block seemed the best way to maintain ' modularity, yet trap inevitable operator errors. SELECT CASE topHighlight ' the top bar menu selected CASE 1 ' top bar Item #1 SELECT CASE subSelection ' sub menu #1 CASE 1 CASE 2 CASE 3 CASE 4 CASE 5 CASE 6 CASE 7 CASE 8 CASE 9 CASE 10 CASE 11 CASE 12 CASE 13 CASE 14 CASE 15 CASE 16 CASE 17 CASE 18 CASE 19 CASE 20 CASE ELSE SOUND 1300, 1 COLOR 30, 0: LOCATE 5, 6: PRINT " Invalid " SLEEP 1 subSelection = 0 menuSub1 GOTO evaluateChoice: 'LOCATE 5, 6: COLOR 0, 7: PRINT " Invalid ": COLOR 7, 0 'SLEEP 1 END SELECT CASE 2 ' top bar item #2 SELECT CASE subSelection ' sub menu #2 CASE 1 CASE 2 CASE 3 CASE 4 CASE 5 CASE 6 CASE 7 CASE 8 CASE 9 CASE 10 CASE ELSE SOUND 1300, 1 COLOR 30, 0: LOCATE 5, 18: PRINT " Invalid " SLEEP 1 subSelection = 0 menuSub2 GOTO evaluateChoice: END SELECT CASE 3 ' top bar item #3 SELECT CASE subSelection ' sub menu #3 CASE 1 CASE 2 CASE 3 CASE 4 CASE 5 CASE ELSE SOUND 1300, 1 COLOR 30, 0: LOCATE 5, 24: PRINT " Invalid " SLEEP 1 subSelection = 0 menuSub3 GOTO evaluateChoice: END SELECT CASE 4 ' top bar item #4 SELECT CASE subSelection ' sub menu #4 CASE 1 CASE 2 CASE 3 CASE 4 CASE 5 CASE 6 CASE 7 CASE 8 CASE 9 CASE 10 CASE 11 CASE 12 CASE 13 CASE 14 CASE 15 CASE ELSE SOUND 1300, 1 COLOR 30, 0: LOCATE 5, 38: PRINT " Invalid " SLEEP 1 subSelection = 0 menuSub4 GOTO evaluateChoice: END SELECT CASE 5 ' top bar item #5 SELECT CASE subSelection ' sub menu #5 CASE 1 CASE 2 CASE 3 CASE 4 CASE 5 CASE 6 CASE 7 CASE 8 CASE 9 CASE 10 CASE 11 CASE 12 CASE 13 CASE 14 CASE 15 CASE ELSE SOUND 1300, 1 COLOR 30, 0: LOCATE 5, 45: PRINT " Invalid " SLEEP 1 subSelection = 0 menuSub5 GOTO evaluateChoice: END SELECT CASE 6 ' top bar item #6 SELECT CASE subSelection ' sub menu #6 CASE 1 CASE 2 CASE 3 CASE ELSE SOUND 1300, 1 COLOR 30, 0: LOCATE 5, 48: PRINT " Invalid " SLEEP 1 subSelection = 0 menuSub6 GOTO evaluateChoice: END SELECT END SELECT ' In your finished application, you would discard everything ' below here and unrem the END command and the RUN "YourAPP" ' (substituting the name of your application for YourAPP.) ' RUN "YourAPP" ' END ' program would normally end here ' the balance of this main module 'validates' the return from the ' menus. The flow would have gone to those specific tasks before ' reaching this point. SOUND 700, 3 SOUND 1200, 2 SOUND 1000, 4 PLAY "g" showSubText "YES" position = subSelection showSubHighlight COLOR 7, 0 LOCATE 25, 1 PRINT STRING$(80, 32); LOCATE 25, 1 PRINT " Selected: "; COLOR 0, 7 PRINT " "; subMenuText$(subSelection); COLOR 7, 0 PRINT " Any key reruns. Ctrl+Break ends"; DO: LOOP UNTIL INKEY$ > "" COLOR 6, 0: LOCATE 2, 2: PRINT strippedTopBarString$: COLOR 7, 0 LOCATE 25, 1: PRINT SPACE$(80); COLOR 23, 0 LOCATE 25, 35: PRINT " Working "; COLOR 7, 0 eraseSubMenus SLEEP (1) RUN "bbmenu" END handler: IF ERR = 9 THEN 'subscript out of range error position = 1 RESUME NEXT END IF REM $STATIC '================= SUB eraseSubMenus '================= ' clears the area occupied by the sub menus COLOR 7, 0 ' setting white on black LOCATE 3, 2: PRINT STRING$(78, 205) ' redraw bottom of top frame FOR x = 4 TO 24 LOCATE x, 1: PRINT SPACE$(79); NEXT END SUB '=================== SUB getSubDecision '=================== ' We come here to get operator input when the sub menu(s) is/are ' on the screen. DO keyPressed$ = "" DO keyPressed$ = INKEY$ LOOP UNTIL keyPressed$ > "" ' trap the ESC key IF ASC(keyPressed$) = 27 THEN : subSelection = 27: EXIT SUB IF LEN(keyPressed$) = 1 THEN ' a regular key, or a highlighted letter was pressed ' ' the block is set up for the maximum of 20 possible ' choices - if the choice is not appropriate for the ' menu displayed it is trapped in BBMENU, the main module keyPressed$ = UCASE$(keyPressed$) SELECT CASE keyPressed$ CASE "A" subSelection = 1 CASE "B" subSelection = 2 CASE "C" subSelection = 3 CASE "D" subSelection = 4 CASE "E" subSelection = 5 CASE "F" subSelection = 6 CASE "G" subSelection = 7 CASE "H" subSelection = 8 CASE "I" subSelection = 9 CASE "J" subSelection = 10 CASE "K" subSelection = 11 CASE "L" subSelection = 12 CASE "M" subSelection = 13 CASE "N" subSelection = 14 CASE "O" subSelection = 15 CASE "P" subSelection = 16 CASE "Q" subSelection = 17 CASE "R" subSelection = 18 CASE "S" subSelection = 19 CASE "T" subSelection = 20 CASE CHR$(13) ' operator touched ENTER subSelection = position CASE ELSE ' This block passes ALL key strokes back to the ' main module, error trapping is done there ' rather than here. subSelection = 21 END SELECT ELSEIF LEN(keyPressed$) = 2 THEN ' an arrow or function key -- extended key -- was pressed ' pick off the ASC value of the 'meaningful' byte. SELECT CASE ASC(RIGHT$(keyPressed$, 1)) CASE 72 ' up arrow was pressed position = position - 1 IF position < 1 THEN position = UBOUND(subMenuText$) ' If the operator presses the left or right arrow ' while a sub menu is 'pulled down' they move to ' the adjacent sub menu immediately - without having ' to return to the top bar menu ' ' The program erases the old sub menu before pulling ' down the new one, but, if you REM out the eraseSubMenus ' call, the menus will 'stack' on the screen. ' ' This feature also opens the program up to a possible ' out of stack space error, which can't be trapped. If ' you have a problem with it, REM out this section. The ' operator then presses the ESC key to return to the top ' bar and make another sub menu selection. CASE 75, 77 ' left (75) or right (77) arrow was pressed ' REM out this call to the eraseSubMenus SUB if ' you would like to leave the 'old' sub menu on ' the screen - stacking them. eraseSubMenus IF ASC(RIGHT$(keyPressed$, 1)) = 75 THEN subMenuWanted = topHighlight - 1 IF subMenuWanted < 1 THEN subMenuWanted = 6 ELSE subMenuWanted = topHighlight + 1 IF subMenuWanted > 6 THEN subMenuWanted = 1 END IF LOCATE 2, 2: COLOR 6, 0: PRINT strippedTopBarString$: COLOR 7, 0 SELECT CASE subMenuWanted CASE 1: menuSub1 CASE 2: menuSub2 CASE 3: menuSub3 CASE 4: menuSub4 CASE 5: menuSub5 CASE 6: menuSub6 END SELECT EXIT SUB CASE 80 ' down arrow was pressed position = position + 1 IF position > UBOUND(subMenuText$) THEN position = 1 CASE ELSE SOUND 1200, 1 END SELECT ' now we update the screen CALL showSubText(dimSwitch$) CALL showSubHighlight ELSE ' an unanticipated key was pressed SOUND 1000, 1 ' restart the sub CALL getSubDecision END IF ' only making a selection will escape LOOP UNTIL subSelection > 0 ' this loop CALL showSubText("YES") ' "YES" means the call IS to dim the text CALL showSubHighlight ' the sub menu selection is highlighted END SUB '=================== SUB getTopDecision '=================== topSelection = 0 showTopText IF topHighlight = 0 THEN topHighlight = 1 ' making Item One the default selection showTopHighlight DO keyPressed$ = "" DO keyPressed$ = INKEY$ LOOP UNTIL keyPressed$ > "" IF ASC(keyPressed$) = 27 THEN topSelection = 27: EXIT SUB IF LEN(keyPressed$) = 1 THEN ' a regular key, or a highlighted letter was pressed keyPressed$ = UCASE$(keyPressed$) SELECT CASE keyPressed$ ' These are the highlighted letters on the top line CASE "O" topSelection = 1 CASE "T" topSelection = 2 CASE "H" topSelection = 3 CASE "F" topSelection = 4 CASE "I" topSelection = 5 CASE "X" topSelection = 6 CASE CHR$(13) ' operator touched ENTER topSelection = topHighlight CASE ELSE ' unacceptable key was touched SOUND 1300, 1 topSelection = 0 END SELECT ELSEIF LEN(keyPressed$) = 2 THEN ' an arrow or function -- extended -- key was pressed. ' We pick off the 'meaningful' byte and analyze ' it's ASC value. SELECT CASE ASC(RIGHT$(keyPressed$, 1)) CASE 77 ' right arrow was pressed topHighlight = topHighlight + 1 CASE 75 ' left arrow was pressed topHighlight = topHighlight - 1 CASE 80 ' down arrow was pressed ' has same effect as pressing the ENTER key, ' operators seem to expect it. topSelection = topHighlight CASE ELSE SOUND 1200, 1 END SELECT ' now we refresh the display CALL showTopText CALL showTopHighlight ELSE ' an unanticipated key was pressed SOUND 1000, 1 ' restart the sub CALL getTopDecision END IF ' only making a selection will escape LOOP UNTIL topSelection > 0 ' this loop ' This 'turns off' the top bar highlights COLOR 6, 0: LOCATE 2, 2: PRINT strippedTopBarString$: COLOR 7, 0 END SUB '============= SUB menuSub1 '============= ' Do you want to change the number of items on this menu? ' ' Simple. ' ' Just change the dimension of the subMenuText$ array and ' type in the new items or make the appropriate deletions. ' The drawing of the sub menu frame, and the display of the ' menu items is controlled by the UBOUND function of the ' sub menu array. ' ' You should also adjust the SELECT CASE block for this ' menu in the main module, BBMENU. ERASE subMenuText$ DIM subMenuText$(1 TO 20) subMenuText$(1) = "Menu One SubMenu Item One " subMenuText$(2) = "Menu One SubMenu Item Two " subMenuText$(3) = "Menu One SubMenu Item Three " subMenuText$(4) = "Menu One SubMenu Item Four " subMenuText$(5) = "Menu One SubMenu Item Five " subMenuText$(6) = "Menu One SubMenu Item Six " subMenuText$(7) = "Menu One SubMenu Item Seven " subMenuText$(8) = "Menu One SubMenu Item Eight " subMenuText$(9) = "Menu One SubMenu Item Nine " subMenuText$(10) = "Menu One SubMenu Item Ten " subMenuText$(11) = "Menu One SubMenu Item Eleven " subMenuText$(12) = "Menu One SubMenu Item Twelve " subMenuText$(13) = "Menu One SubMenu Item Thirteen" subMenuText$(14) = "Menu One SubMenu Item Fourteen" subMenuText$(15) = "Menu One SubMenu Item Fifteen " subMenuText$(16) = "Menu One SubMenu Item Sixteen " subMenuText$(17) = "Menu One SubMenu Item Seventee" subMenuText$(18) = "Menu One SubMenu Item Eighteen" subMenuText$(19) = "Menu One SubMenu Item Nineteen" subMenuText$(20) = "Menu One SubMenu Item Twenty " mc = 3 showSubFrame showSubText (dimSwitch$) showSubHighlight topHighlight = 1 showTopHighlight getSubDecision END SUB '============== SUB menuSub2 '============== ' Do you want to change the number of items on this menu? ' ' Simple. ' ' Just change the dimension of the subMenuText$ array and ' type in the new items or make the appropriate deletions. ' The drawing of the sub menu frame, and the display of the ' menu items is controlled by the UBOUND function of the ' sub menu array. ' ' You should also adjust the SELECT CASE block for this ' menu in the main module, BBMENU. ERASE subMenuText$ DIM subMenuText$(1 TO 10) subMenuText$(1) = "Menu Two SubMenu Item One " subMenuText$(2) = "Menu Two SubMenu Item Two " subMenuText$(3) = "Menu Two SubMenu Item Three " subMenuText$(4) = "Menu Two SubMenu Item Four " subMenuText$(5) = "Menu Two SubMenu Item Five " subMenuText$(6) = "Menu Two SubMenu Item Six " subMenuText$(7) = "Menu Two SubMenu Item Seven " subMenuText$(8) = "Menu Two SubMenu Item Eight " subMenuText$(9) = "Menu Two SubMenu Item Nine " subMenuText$(10) = "Menu Two SubMenu Item Ten " mc = 15 showSubFrame showSubText (dimSwitch$) showSubHighlight topHighlight = 2 showTopHighlight getSubDecision END SUB '============= SUB menuSub3 '============= ' Do you want to change the number of items on this menu? ' ' Simple. ' ' Just change the dimension of the subMenuText$ array and ' type in the new items or make the appropriate deletions. ' The drawing of the sub menu frame, and the display of the ' menu items is controlled by the UBOUND function of the ' sub menu array. ' ' You should also adjust the SELECT CASE block for this ' menu in the main module, BBMENU. ERASE subMenuText$ DIM subMenuText$(1 TO 5) subMenuText$(1) = "Menu Three SubMenu Item One " subMenuText$(2) = "Menu Three SubMenu Item Two " subMenuText$(3) = "Menu Three SubMenu Item Three " subMenuText$(4) = "Menu Three SubMenu Item Four " subMenuText$(5) = "Menu Three SubMenu Item Five " mc = 20 showSubFrame showSubText (dimSwitch$) showSubHighlight topHighlight = 3 showTopHighlight getSubDecision END SUB '============= SUB menuSub4 '============= ' Do you want to change the number of items on this menu? ' ' Simple. ' ' Just change the dimension of the subMenuText$ array and ' type in the new items or make the appropriate deletions. ' The drawing of the sub menu frame, and the display of the ' menu items is controlled by the UBOUND function of the ' sub menu array. ' ' You should also adjust the SELECT CASE block for this ' menu in the main module, BBMENU. ERASE subMenuText$ DIM subMenuText$(1 TO 15) subMenuText$(1) = "Menu Four SubMenu Item One " subMenuText$(2) = "Menu Four SubMenu Item Two " subMenuText$(3) = "Menu Four SubMenu Item Three " subMenuText$(4) = "Menu Four SubMenu Item Four " subMenuText$(5) = "Menu Four SubMenu Item Five " subMenuText$(6) = "Menu Four SubMenu Item Six " subMenuText$(7) = "Menu Four SubMenu Item Seven " subMenuText$(8) = "Menu Four SubMenu Item Eight " subMenuText$(9) = "Menu Four SubMenu Item Nine " subMenuText$(10) = "Menu Four SubMenu Item Ten " subMenuText$(11) = "Menu Four SubMenu Item Eleven " subMenuText$(12) = "Menu Four SubMenu Item Twelve " subMenuText$(13) = "Menu Four SubMenu Item Thirtee" subMenuText$(14) = "Menu Four SubMenu Item Fourtee" subMenuText$(15) = "Menu Four SubMenu Item Fifteen" mc = 35 showSubFrame showSubText (dimSwitch$) showSubHighlight topHighlight = 4 showTopHighlight getSubDecision END SUB '============ SUB menuSub5 '============ ' Do you want to change the number of items on this menu? ' ' Simple. ' ' Just change the dimension of the subMenuText$ array and ' type in the new items or make the appropriate deletions. ' The drawing of the sub menu frame, and the display of the ' menu items is controlled by the UBOUND function of the ' sub menu array. ' ' You should also adjust the SELECT CASE block for this ' menu in the main module, BBMENU. ERASE subMenuText$ DIM subMenuText$(1 TO 15) subMenuText$(1) = "Menu Five SubMenu Item One " subMenuText$(2) = "Menu Five SubMenu Item Two " subMenuText$(3) = "Menu Five SubMenu Item Three " subMenuText$(4) = "Menu Five SubMenu Item Four " subMenuText$(5) = "Menu Five SubMenu Item Five " subMenuText$(6) = "Menu Five SubMenu Item Six " subMenuText$(7) = "Menu Five SubMenu Item Seven " subMenuText$(8) = "Menu Five SubMenu Item Eight " subMenuText$(9) = "Menu Five SubMenu Item Nine " subMenuText$(10) = "Menu Five SubMenu Item Ten " subMenuText$(11) = "Menu Five SubMenu Item Eleven " subMenuText$(12) = "Menu Five SubMenu Item Twelve " subMenuText$(13) = "Menu Five SubMenu Item Thirtee" subMenuText$(14) = "Menu Five SubMenu Item Fourtee" subMenuText$(15) = "Menu Five SubMenu Item Fifteen" mc = 42 showSubFrame showSubText (dimSwitch$) showSubHighlight topHighlight = 5 showTopHighlight getSubDecision END SUB '============= SUB menuSub6 '============= ' Do you want to change the number of items on this menu? ' ' Simple. ' ' Just change the dimension of the subMenuText$ array and ' type in the new items or make the appropriate deletions. ' The drawing of the sub menu frame, and the display of the ' menu items is controlled by the UBOUND function of the ' sub menu array. ' ' You should also adjust the SELECT CASE block for this ' menu in the main module, BBMENU. ERASE subMenuText$ DIM subMenuText$(1 TO 3) subMenuText$(1) = "Menu Six SubMenu Item One " subMenuText$(2) = "Menu Six SubMenu Item Two " subMenuText$(3) = "Menu Six SubMenu Item Three " mc = 45 showSubFrame showSubText (dimSwitch$) showSubHighlight topHighlight = 6 showTopHighlight getSubDecision END SUB SUB menuTop IF topHighlight = 0 THEN topHighlight = 1' Item One will be default ' The > symbol tells the system that the next character is ' to be highligted. Each highlighted letter should be unique . . . topBarText$(1) = " Item >One " topBarText$(2) = " Item >Two " topBarText$(3) = " Item T>hree " topBarText$(4) = " Item >Four " topBarText$(5) = " Item F>ive " topBarText$(6) = " Item Si>x " CALL showTopFrame ' draw a box for the top bar menu CALL showTopText ' print the topBarText$ array CALL showTopHighlight ' highlight an item CALL getTopDecision ' get the operator's decision SELECT CASE topSelection CASE 1 CALL menuSub1 CASE 2 CALL menuSub2 CASE 3 CALL menuSub3 CASE 4 CALL menuSub4 CASE 5 CALL menuSub5 CASE 6 CALL menuSub6 CASE 27 ' operator pressed ESC at LOCATE 2, 2 ' the top bar menu COLOR 7, 0: PRINT STRING$(78, 32) ' clear the top line box LOCATE 25, 1: PRINT SPACE$(80); ' clear the bottom line LOCATE 2, 30 COLOR 5, 7 PRINT " Quit the Program? (Y/N) " COLOR 7, 0 qd$ = "" DO SOUND 1500, 3 qd$ = UCASE$(INPUT$(1)) IF qd$ = "Y" THEN CLS PRINT "Operator Exited Program on "; DATE$; " at "; TIME$ PRINT ' You will want to subsitute your own 'sign off' ' information for the following lines. Many ' 'shareware' authors display registration information. ' Others invite call for "new products catalog." PRINT "People Centered Programs Software" PRINT "PO Box 610171 " PRINT "Dallas, TX 75261-0171" PRINT "817/488-4940" PRINT END END IF LOOP UNTIL INSTR("YN", qd$) > 0 EXIT SUB CASE ELSE END SELECT END SUB '================= SUB showSubFrame '================= ' draw the sub menu frame and the highlighted character ' (The mc value -- the upper left corner of the sub menu frame -- ' is set in the subMenuX that is calling this routine. ' ' A limited 3-d effect is possible by combining the two line ' drawing characters with the single line ones. ' ' As with : ' ' ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ' º ³ ' ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ' ' Refer to PDS's on line help under ASC Characters ' LOCATE 3, mc COLOR 7, 0 PRINT "Ñ"; STRING$(33, 205); "Ñ"; ' top bar FOR x = 1 TO UBOUND(subMenuText$) x$ = CHR$(x + 64) LOCATE 3 + x, mc: PRINT "³ "; ' left side COLOR 0, 7 PRINT x$; ' highlighted ltr COLOR 7, 0 PRINT SPACE$(31); "³"; ' right side NEXT x LOCATE 3 + x, mc: PRINT "À"; STRING$(33, 196); "Ù"; ' bottom bar END SUB '==================== SUB showSubHighlight '==================== subStarts: ' the variable position can be at 0 when the program ' reaches this SUB and would crash. We trap the error ' and assign a value to position. ON ERROR GOTO handler: IF position = 0 THEN position = 1 COLOR 0, 7 LOCATE 3 + position, mc + 4 PRINT subMenuText$(position) COLOR 7, 0 EXIT SUB END SUB '=============== SUB showSubText (dimSwitch$) '=============== ' display the sub menu's choices IF dimSwitch$ = "YES" THEN dimSwitch$ = "" COLOR 6, 0 ' dims the text on a monochrome ELSE ' monitor - brown on a color monitor COLOR 7, 0 END IF FOR x = 1 TO UBOUND(subMenuText$) LOCATE 3 + x, mc + 4: PRINT subMenuText$(x) NEXT x COLOR 7, 0 END SUB '================== SUB showTopFrame '================== ' draw a box for the top bar menu items ' see the showSubFrame SUB for an example of ' a 3-d effect one can achieve by mixing two line ' and one line drawing characters. LOCATE 1, 1: PRINT "É"; STRING$(78, 205); "»"; ' top score LOCATE 2, 1: PRINT "º "; TAB(79); " º"; ' the end pieces LOCATE 3, 1: PRINT "È"; STRING$(78, 205); "¼"; ' bottom score ' show operator's instructions ' the instructions are the same for the sub menus ' so it stays on the screen when they are displayed COLOR 0, 7 LOCATE 25, 10: PRINT " Use Arrow Keys & ENTER or touch Highlighted Letter (ESC to End) "; END SUB '===================== SUB showTopHighlight '===================== 'come here to reverse the item where the cursor is located on top bar IF topHighlight < 1 THEN topHighlight = 6 ' Jump to #6 IF topHighlight > 6 THEN topHighlight = 1 ' Jump back to #1 COLOR 0, 7 ' black letters on white backgroud ' the variable strippedTopBarString$ equals all the topBarText array ' elements cocantenated to eliminate the > symbol. The variable ' (strippedTopBarString$) is created in the SUB showTopText. It ' is a COMMON SHARED variable, so can be called from anywhere in the ' the application. IF topHighlight = 1 THEN LOCATE 2, 2: PRINT LEFT$(strippedTopBarString$, 12) IF topHighlight = 2 THEN LOCATE 2, 15: PRINT MID$(strippedTopBarString$, 14, 12) IF topHighlight = 3 THEN LOCATE 2, 27: PRINT MID$(strippedTopBarString$, 26, 13) IF topHighlight = 4 THEN LOCATE 2, 40: PRINT MID$(strippedTopBarString$, 39, 12) IF topHighlight = 5 THEN LOCATE 2, 52: PRINT MID$(strippedTopBarString$, 51, 13) IF topHighlight = 6 THEN LOCATE 2, 68: PRINT MID$(strippedTopBarString$, 67, 12) COLOR 7, 0 END SUB '================= SUB showTopText '================= strippedTopBarString$ = "" ' makes sure only one copy is in memory ' We cocantenate the topBarText$ array for printing purposes topBarString$ = topBarText$(1) + topBarText$(2) + topBarText$(3) + topBarText$(4) + topBarText$(5) + topBarText$(6) ' now we print the top bar, highlighting "speed keys" as we go COLOR 15, 0 LOCATE 2, 2 FOR x = 1 TO LEN(topBarString$) c$ = MID$(topBarString$, x, 1) ' looking at each character IF c$ = ">" THEN COLOR 0, 7 c$ = "" ' now we know the next ELSE ' character is to be highlighted PRINT c$; ' so we erase the > and change ' the color ' now we rebuild the menu items without the > highlight symbol strippedTopBarString$ = strippedTopBarString$ + c$ COLOR 15, 0 ' returning to white on black END IF NEXT x END SUB