{ GG> Could somebody post a message with the Pascal 6.0 source for some GG> sort of a scrolling menu system? I do NOT want TurboVision. I GG> HATE OOP. I don't mind records and arrays, but i don't want OOP. GG> I've done some programming for one myself.... } UNIT MPMENU; { Written and designed by Michael Perry, (c) 1990 Progressive Computer Serv. A basic, flexible, user-definable menu system using only the most basic functions in Turbo Pascal. This unit is easily integratable into your applications and gives you more versatility than most "pull down"-type menu interfaces. License: This unit should NOT be modified and redistributed in source or object/TPU form. You can modify and use this in any non- commercial program free-of-charge provided that "Mike Perry" if credited either in the program or documentation. Use of these routines in a commercially-sold package requires a one-time registration fee of $30 to be sent to: Progressive Computer Services P.O. Box 7638 Metairie, LA 70010 Non-commercial users are also invited to register the code. This insures that updates and future revisions are made available and users are kept informed via mail. Usage: Implementing menus using the MPMENU unit involves just a few basic steps. At any point in your program, add code to perform the following actions: 1. Define the menu by assigning values to the MENU_DATA record. 2. Call the procedure MENU(MENU_DATA,RETURNCODE); 3. Implement a routine to evaluate the value of RETURNCODE and act accordingly. The values of RETURNCODE are as follows: 0 = ESC pressed (menu aborted) 1-x = The appropriate option was selected, with 1 being the first menu choice, 2 the second, etc. Example: Here is a sample main menu using the MENU procedure: ----------------------------------------------------------------------------- Program DontDoMuch; Uses Crt,MPMenu; CONST HELL_FREEZES_OVER=FALSE; VAR CHOICE:BYTE; Begin REPEAT With Menu_Data Do Begin Menu_Choices[1]:='1 - First Option '; - define menu choice onscreen Row[1]:=10; Column[1]:=30; - where on screen displayed Menu_Choices[2]:='2 - Second Option'; - same thing for 2nd choice Row[2]:=12; Column[2]:=30; . Menu_Choices[3]:='X - Exit Program '; . Row[3]:=14; Column[3]:=30; . Onekey:=TRUE; - enable 1-key execution Num_Choices:=3; - number of menu choices HiLighted:=112; - highlighted attribute Normal:=7; - normal attribute End; MENU(MENU_DATA,CHOICE); - call the menu now and wait for user Case Choice Of - evaluate user response and act 0:Halt; - ESC pressed 3:Halt; - option 3, Exit, selected 1:Begin - put code here to do menu option 1 End; 2:Begin - put code here to do menu option 2 End; End UNTIL HELL_FREEZES_OVER; - infinite loop - back to main menu End. ----------------------------------------------------------------------------- } INTERFACE USES Crt; CONST MAX_CHOICES = 10; { MAX_CHOICES can be changed depending upon the highest number of options you will have on any given menu } TYPE MENU_ARRAY = RECORD { record structure for menu } MENU_CHOICES : ARRAY[1..MAX_CHOICES] OF STRING[50]; { displayed option } COLUMN : ARRAY[1..MAX_CHOICES] OF BYTE; { column location } ROW : ARRAY[1..MAX_CHOICES] OF BYTE; { row location } NUM_CHOICES : BYTE; { # choices on menu } HILIGHTED : WORD; { attribute for hilight } NORMAL : WORD; { attributed for normal } ONEKEY : BOOLEAN; { TRUE for 1-key execution } END; VAR MENU_DATA : MENU_ARRAY; { global menu variable } { NOTE: You can define many menu variables simultaneously, but since you can generally use only one menu at a time, you can conserve memory and program space by re-defining this one MENU_DATA record each time a menu is to be displayed. } { internal procedures } PROCEDURE SHOW_MENU(MENU_DATA:MENU_ARRAY); PROCEDURE HILIGHT_CHOICE(MENU_DATA:MENU_ARRAY;CHOICENUM:BYTE); PROCEDURE UNHILIGHT_CHOICE(MENU_DATA:MENU_ARRAY;CHOICENUM:BYTE); FUNCTION GETKEY(VAR FUNCTIONKEY:BOOLEAN):CHAR; FUNCTION FOUND_CHOICE(MENU_DATA:MENU_ARRAY;VAR EXITCODE:BYTE;CH:CHAR):BOOLEAN; { basically, the ONE callable procedure } PROCEDURE MENU(MENU_DATA:MENU_ARRAY;VAR EXITCODE:BYTE); IMPLEMENTATION (*===========================================================================*) PROCEDURE SHOW_MENU(MENU_DATA:MENU_ARRAY); { display defined menu array } VAR I:BYTE; BEGIN TEXTATTR:=MENU_DATA.NORMAL; FOR I:=0 TO (MENU_DATA.NUM_CHOICES-1) DO BEGIN GOTOXY(MENU_DATA.COLUMN[I+1],MENU_DATA.ROW[I+1]); WRITE(MENU_DATA.MENU_CHOICES[I+1]); END; END; (*===========================================================================*) PROCEDURE HILIGHT_CHOICE(MENU_DATA:MENU_ARRAY;CHOICENUM:BYTE); { highlight the appropriate menu choice } BEGIN GOTOXY(MENU_DATA.COLUMN[CHOICENUM],MENU_DATA.ROW[CHOICENUM]); TEXTATTR:=MENU_DATA.HILIGHTED; WRITE(MENU_DATA.MENU_CHOICES[CHOICENUM]); { below needed if direct screen writing not done } GOTOXY(MENU_DATA.COLUMN[CHOICENUM],MENU_DATA.ROW[CHOICENUM]); END; (*===========================================================================*) PROCEDURE UNHILIGHT_CHOICE(MENU_DATA:MENU_ARRAY;CHOICENUM:BYTE); { highlight the appropriate menu choice } BEGIN GOTOXY(MENU_DATA.COLUMN[CHOICENUM],MENU_DATA.ROW[CHOICENUM]); TEXTATTR:=MENU_DATA.NORMAL; WRITE(MENU_DATA.MENU_CHOICES[CHOICENUM]); END; (*===========================================================================*) FUNCTION GETKEY(VAR FUNCTIONKEY:BOOLEAN):CHAR; { read keyboard and return character/function key } VAR CH: CHAR; BEGIN CH:=ReadKey; IF (CH=#0) THEN BEGIN CH:=ReadKey; FUNCTIONKEY:=TRUE; END ELSE FUNCTIONKEY:=FALSE; GETKEY:=CH; END; (*===========================================================================*) FUNCTION FOUND_CHOICE(MENU_DATA:MENU_ARRAY;VAR EXITCODE:BYTE;CH:CHAR):BOOLEAN; { locate next occurance of menu choice starting with char CH } VAR I:BYTE; TEMP:STRING; BEGIN CH:=UPCASE(CH); IF EXITCODE=MENU_DATA.NUM_CHOICES THEN BEGIN TEMP:=MENU_DATA.MENU_CHOICES[1]; IF UPCASE(TEMP[1])=CH THEN BEGIN UNHILIGHT_CHOICE(MENU_DATA,EXITCODE); EXITCODE:=1; HILIGHT_CHOICE(MENU_DATA,EXITCODE); FOUND_CHOICE:=TRUE; EXIT; END; END; FOR I:=EXITCODE+1 TO MENU_DATA.NUM_CHOICES DO BEGIN TEMP:=MENU_DATA.MENU_CHOICES[I]; IF UPCASE(TEMP[1])=CH THEN BEGIN UNHILIGHT_CHOICE(MENU_DATA,EXITCODE); EXITCODE:=I; HILIGHT_CHOICE(MENU_DATA,EXITCODE); FOUND_CHOICE:=TRUE; EXIT; END; END; IF EXITCODE<>1 THEN BEGIN { KILLER RECURSION } UNHILIGHT_CHOICE(MENU_DATA,EXITCODE); EXITCODE:=1; IF FOUND_CHOICE(MENU_DATA,EXITCODE,CH) THEN BEGIN HILIGHT_CHOICE(MENU_DATA,EXITCODE); FOUND_CHOICE:=TRUE; EXIT; END ELSE HILIGHT_CHOICE(MENU_DATA,EXITCODE); END ELSE BEGIN TEMP:=MENU_DATA.MENU_CHOICES[1]; IF UPCASE(TEMP[1])=CH THEN BEGIN FOUND_CHOICE:=TRUE; EXIT; END; END; FOUND_CHOICE:=FALSE; END; (*===========================================================================*) PROCEDURE MENU(MENU_DATA:MENU_ARRAY;VAR EXITCODE:BYTE); { display menu and return user's response: 0 = ESC pressed 1-x = appropriate choice selected during operation, variable EXITCODE holds number of currently-selected menu choice. } VAR FNC:BOOLEAN; TEMPATTR:WORD; CH:CHAR; BEGIN TEMPATTR:=TEXTATTR; IF (EXITCODE=0) OR (EXITCODE>MENU_DATA.NUM_CHOICES) THEN EXITCODE:=1; SHOW_MENU(MENU_DATA); HILIGHT_CHOICE(MENU_DATA,EXITCODE); REPEAT CH:=GETKEY(FNC); IF FNC THEN BEGIN IF CH=#77 THEN CH:=#80 ELSE IF CH=#75 THEN CH:=#72; CASE CH OF #72:IF EXITCODE>1 THEN BEGIN { UP } UNHILIGHT_CHOICE(MENU_DATA,EXITCODE); EXITCODE:=EXITCODE-1; END; #80:IF EXITCODE1 THEN BEGIN { HOME } UNHILIGHT_CHOICE(MENU_DATA,EXITCODE); EXITCODE:=1; END; #79:IF EXITCODE