{************************ Start of module Menutil ************************} { This module contains the Menu Utilities. They require the type definitions } {shown below for use. This entire module could easily be cut out of this demo} {and included in other programs on an as needed basis. } { MENUDEMO.PAS is Copyright 1987 by Lee W. Benjamin & S. Lee Mavity, whose joint address is 293 HyWy 247 So., Warner Robins, Ga. 31088. MENUDEMO may be used freely for non- commercial purposes, but may not be sold, included in a package for sale, or used as an incentive to buy, by any person, organization or corporation without prior arrangement with the copyright holders, Lee Benjamin & S. Lee Mavity. Furthermore, the copyright holders will bear no responsibility for losses resulting from the use or inability to use this demonstration program. MENUDEMO.COM may not be distributed without MENUINCL.PAS, nor may the copyright messages be removed from either file nor caused to not be displayed. Since the utilities don't actually display this message they may be used freely in you code, however this notice must remain in your code. } const yes = true; no = false; { limit the number of options to seven to keep things on screen and readable } MaxOptions = 7; null:char = #0; bell:char = #7; type short_string = string[30]; long_string = string[78]; option_count_type = 1..MaxOptions; { define a menu option } option_type = record option_name : short_string; help_line1 : long_string; help_line2 : long_string; end; { define a menu } menu_type = record header : short_string; menu_number : integer; number_of_options : option_count_type; option_list : array[1..MaxOptions] of option_type; end; scr_pos = record xpos: 1..80; ypos: 1..24; end; { define the corners of the box for the first menu option } menu_box = record top_left: scr_pos; top_right: scr_pos; bottom_left: scr_pos; bottom_right: scr_pos; end; var { Define variables for Menutil support } menu_number: integer; main_menu : menu_type; option_number: option_count_type; first_menu_box: menu_box; exit_menu: boolean; menu_onscreen: boolean; I : Integer; Ch : char; line : string[80]; procedure initialize_first_menu_box; begin with first_menu_box do begin top_left.xpos := 24; top_left.ypos := 4; top_right.xpos := 56; top_right.ypos := 4; bottom_left.xpos := 24; bottom_left.ypos := 6; bottom_right.xpos := 56; bottom_right.ypos := 6; end; end; procedure wait_for_keypress(show_prompt: boolean); begin if show_prompt then write('Press any key to continue...'); repeat until keypressed; end; {wait for keypress} procedure Frame(UpperLeftX, UpperLeftY, LowerRightX, LowerRightY: Integer; ch: char); { Draws a frame on the sceen using the line drawing character set or the character specified } var I : Integer; top_left_corner : char; horizontal_line : char; top_right_corner : char; vertical_line : char; bottom_left_corner : char; bottom_right_corner : char; begin {Frame} { Modified for Generic CP/M systems } top_left_corner := #42; { * } { if available use line drawing} horizontal_line := #45; { - } {characters in place of these} top_right_corner := #42; { * } vertical_line := #124; { | } bottom_left_corner := #42; { * } bottom_right_corner := #42; { * } { if a replacement character is defined, use it a blank is useful for erasing a frame. } if ch <> #0 then begin top_left_corner := ch; horizontal_line := ch; top_right_corner := ch; vertical_line := ch; bottom_left_corner := ch; bottom_right_corner := ch; end; GotoXY(UpperLeftX, UpperLeftY); Write(Top_left_corner); for I := (UpperLeftX + 1) to (LowerRightX - 1) do begin Write(Horizontal_Line); { Across top } end; Write(Top_right_corner); for I := (UpperLeftY + 1) to (LowerRightY - 1) do begin GotoXY(UpperLeftX , I); Write(Vertical_line); { on left side } GotoXY(LowerRightX, I); Write(Vertical_line); { on right side } end; GotoXY(UpperLeftX, LowerRightY); Write(Bottom_left_corner); for I := (UpperLeftX + 1) to (LowerRightX - 1) do begin Write(Horizontal_Line); { Across bottom } end; Write(Bottom_right_corner); end; {Frame} procedure Make_Menu(menu: menu_type); { build a menu on screen using the menu definition that was passed in. } var line, width, startpos, option_count: integer; begin initialize_first_menu_box; if menu.number_of_options <= MaxOptions then begin clrscr; { draw frame around screen using the line drawing character set } { draw header frame } frame(1,1,80,3,#0); { draw rest of screen frame } frame(1,1,80,20,#0); { put up directions } gotoxy(3,19); write('Up/Down Arrows or Spacebar to Advance'); gotoxy(48,19); write('Press Return to Make Selection'); if menu.menu_number > 0 then begin width := 58; GotoXY(61,2); Write('Menu Number: ',Menu.menu_number:4); end else width := 78; { Center menu.header on line depending on presence of menu number } startpos := (((width - length(menu.header)) div 2) + 2); Gotoxy(startpos,2); Write(Menu.header); { put the menu options on the screen } line := 5; for option_count := 1 to menu.number_of_options do begin { put option name on the screen } gotoxy(25,line); writeln(menu.option_list[option_count].option_name); writeln; Line := Line + 2; end; end else begin writeln; writeln(' Menu number ',menu.menu_number,' contains too many options'); writeln(' redefine this menu with seven or fewer options.'); end; gotoxy(2,23); { put cursor in an innocuous place } end; {Make_Menu} procedure place_frame(option_count: option_count_type); { Put a frame around a menu option based on the option number } begin with first_menu_box do begin frame(top_left.xpos,2*option_count+2, bottom_right.xpos, 2*option_count+4,#0); end; end; procedure remove_frame(option_count: option_count_type); { Remove a frame around a menu option based on the option number } begin with first_menu_box do begin frame(top_left.xpos,2*option_count+2, bottom_right.xpos, 2*option_count+4,' '); end; end; Procedure Clear_Help_Lines; begin gotoxy(1,22); clreol; gotoxy(1,23); clreol; end; Procedure Clear_Alert_Line; Begin gotoxy(1,21); clreol; end; Procedure Alert(line: long_string); { Position cursor on line 21, beep and issue an alert message } Begin Clear_Alert_Line; gotoxy(1,21); write(bell,line); end; Procedure Option_Not_Implemented; Begin Alert( 'Sorry, that option is not yet implemented. Press a key.'); Wait_For_Keypress(no); {no prompt desired} Clear_Alert_Line; end; Procedure Show_Selection(option_name: short_string); begin clear_alert_line; clear_help_lines; gotoxy(20,23); write(option_name,' selected.'); end; Function Select_Option(menu: menu_type): integer; { put box around each menu item and take inputs i.e. arrow keys and return } var option_count: integer; selection : char; continue : boolean; begin continue := true; option_count := 1; repeat Clear_alert_line; Clear_help_lines; { put the frame around the proper option } Place_Frame(option_count); { display the descriptive text for this option} if length(menu.option_list[option_count].help_line1) <> 0 then { show the first line if any } begin gotoxy(3,22); write(menu.option_list[option_count].help_line1); clreol; end else begin gotoxy(3,22); clreol; end; if length(menu.option_list[option_count].help_line2) <> 0 then { show the second line if any } begin gotoxy(3,23); write(menu.option_list[option_count].help_line2); clreol; end else begin gotoxy(3,22); clreol; end; { read the response to these prompts } read(kbd, selection); remove_frame(option_count); case (ord(selection)) of {Warning: the codes for arrow keys often differ on different systems} 13: begin { carriage return - selection made } show_selection( menu.option_list[option_count].option_name); { Set select_option and return to main program } Select_Option := option_count; continue := false; end; 10, 32: begin { down arrow or space bar - advance to next option } Clear_Alert_Line; option_count := option_count + 1; end; 11: begin { up arrow - move back to previous option } Clear_Alert_line; option_count := option_count - 1; end else { bad input - issue error message } Alert( 'ERROR: Use up/down arrows or space bar to advance, return to select.'); wait_for_keypress(no); {no prompt desired } end; if option_count > menu.number_of_options then option_count := 1; if option_count < 1 then option_count := menu.number_of_options; until continue = false; { for now do forever } GotoXY(1,24); end; {Select_Option} Procedure dumpme(menu: menu_type); { Put the entire menu contents on the screen for debugging or whatever } var count: integer; Begin writeln(menu.header); writeln(menu.menu_number); writeln(menu.number_of_options); for count := 1 to menu.number_of_options do; begin writeln; writeln(' Option ',count); with menu.option_list[count] do begin writeln(option_name); writeln(help_line1); writeln(help_line2); end; end; end; {dumpme} {************************ End of module Menutil ************************}