
{ Used by Menu procedure to highlight menu choice. }

Procedure Select(x,y : Integer; choice : Str80);
  Begin
    GotoXY(x,y); NormVideo; InVideo(1);
    Write(choice);
  End;

{ Used by Menu procedure to un-highlight menu choice. }

Procedure DeSelect(x,y : Integer; choice : Str80);
  Begin
    GotoXY(x,y); InVideo(0); LowVideo;
    Write(choice);
  End;

{ Pass this function a number equal to the number of menu choices you
  want and an array of strings of 40 or less characters each.  It will
  clear the screen and build the menu for you.  Each choice is highlighted
  as you move down the menu with the space bar, up with the back-space.
  Pressing the first letter of a menu choice moves you to the first choice
  that starts with the same letter.  Uses the above four procedures to
  put instructions in status line.

  example:     const maxlines = 5;
                     lines: Array[0..maxlines] Of String[40] =
                            (' General Business Menu', <-- menu title
                         /   ' Accounts Payable',      <-- first choice
                         |   ' Accounts Recievable ',  <-- second choice
    (Note leading space)-|   ' Payroll',          ^    <-- third choice
                         |   ' General Ledger',   |    <-- fourth choice
                         \   ' Exit Program');    |    <-- fifth choice
           var  Choice : Integer;                 |
             begin                                +------- trailing space
               Choice := menu(maxlines,lines);  <-- Choice will equal 1 -> 5
             end. }

Function menu (number : Integer; Var data) : Integer;
  Type   listtype  = Array[0..16] Of String[40];
  Var    list      : listtype Absolute data;
         total_len, ave_len, max_len, col, cur_choice, i : Byte;
         chr       : Char;
         Top       : integer;
  Begin
    total_len := 0; max_len := 0;
    For i := 1 To number Do
    Begin
      If Length(list[i]) > max_len then max_len := Length(list[i])
    End;
    col := (80 - max_len + 2) Div 2;
    For i := 1 To number Do
    Begin
      list[i] := list[i] + copy(Spaces,1,max_len - Length(list[i]));
    End;
    Top := (21 - number) div 2;
    ClrScr; Draw_Status_Border;
    Write_Status('{Space} = Down, {Left-Arrow} = Up, {First Letter} to Find, {Return} to Select');
    GotoXY(((80 - Length(list[0])) Div 2),Top); Write(list[0]); LowVideo;
    For i := 1 To number Do
    Begin
      GotoXY(col,i + Top + 1); Write(list[i]);
    End;
    GotoXY(col,Top + 2); NormVideo; InVideo(1);
    cur_choice := 1; Write(list[1]);
    repeat
      Read(Kbd,Chr);
      Case Chr Of
        #08 : Begin
                DeSelect(col, Top + 1 + cur_choice, list[cur_choice]);
                cur_choice := cur_Choice - 1;
                If cur_choice = 0 Then cur_choice := number;
                Select(col, Top + 1 + cur_choice, list[cur_choice]);
              End;
        #32 : Begin
                DeSelect(col, Top + 1 + cur_choice, list[cur_choice]);
                cur_choice := cur_choice + 1;
                If cur_choice > number Then cur_choice := 1;
                Select(col, Top + 1 + cur_choice, list[cur_choice]);
              End;
        #13 : menu := cur_choice;
        Else  Begin
                 DeSelect(col, Top + 1 + cur_choice, list[cur_choice]);
                 i := cur_choice;
                 chr := UpCase(chr);
                 Repeat
                   i := succ(i);
                   If i > number Then i := 1
                 Until (i = cur_choice) Or (chr = UpCase(Copy(list[i],2,1)));
                 cur_choice:=i;
                 Select(col, Top + 1 + cur_choice, list[cur_choice]);
               End;
      End;
    until Chr = #13;
    InVideo(0); Cursor_on;
  End;
