home *** CD-ROM | disk | FTP | other *** search
/ RBBS in a Box Volume 1 #3.1 / RBBSIABOX31.cdr / mlpc / menu.inc < prev    next >
Encoding:
Text File  |  1990-09-29  |  9.1 KB  |  252 lines

  1.  
  2. { Program: General Interface Utilities
  3.   Module: Menu Generator
  4.   File: MENU.INC
  5.   System: Turbo Pascal - Version 3, Generic MSDOS
  6.   Version: 2.0  10/12/85
  7.   Author: Michael H. Hughes [75766,1455]
  8.  
  9.   This material is hereby placed in the Public Domain
  10.   Please give credit where credit is due }
  11.  
  12.  
  13. { This module contains the function "menu" which generates a very nice
  14.   kind of menu display.  This general type of menu has been common on Wang
  15.   equipment for years, but has not caught on elsewhere.  It is a neater and
  16.   quicker menu than most of the common types.
  17.  
  18.   Pass the function a list of descriptive lines and it will display them
  19.   on the screen along with a heading and instructions.  A pointer is displayed
  20.   beside the first line of the list, and that line is highlighted.  Press
  21.   a key (usually the space-bar) and the pointer will drop one line down the
  22.   list.  Another key (backspace) will move the pointer back up the list.
  23.   Pressing any character key will cause the routine to search for a line
  24.   beginning with that character.  If found, the pointer will be positioned
  25.   on that line.  Another key (RETURN/ENTER/EXEC) will cause the routine to
  26.   exit and return the number of the selected line.  Another key (CANCEL/ESC)
  27.   can be used as a "cancel" and will return a zero.
  28.  
  29.   The list is passed as an array of strings of length 30 with up to 40
  30.   elements.  The array may contain less than 40 elements, however.
  31.   Note the use of a typeless parameter and an absolute address to pass an
  32.   array of uknown length to the routine.  The routine will position the
  33.   list on the screen automatically, using two columns if necessary.
  34.  
  35.   The routine requires a single-keystroke input routine which does not echo
  36.   to the screen or require a return/enter to respond.  This routine must
  37.   also return a unique value for any function keys used.
  38.  
  39.   The display will look better if the cursor is turned off.  If this can't
  40.   be done, move it out of the way while waiting for input.  Note the ANSI
  41.   code for this function in the "display header" section.  This will work
  42.   on IBM systems using the ANSI.SYS driver.  Otherwise, a BIOS call will
  43.   be required.
  44.  
  45.   The existing set-up is for IBM PC, but is easily changed for other
  46.   systems. }
  47.  
  48.  
  49.  
  50.   { "keyin" checks to see if there is a character in the keyboard buffer
  51.     and returns its numeric value if there is.  Otherwise it returns a
  52.     zero immediately.  It does not wait for a character, or echo it to
  53.     the screen.  Note the machine dependent section for handling function
  54.     keys; it can simply be eliminated in most cases. This routine can be
  55.     placed inside "menu" if desired. }
  56.  
  57.   Function keyin: Byte;
  58.   Var ch: Char;
  59.   Begin
  60.     keyin:=0;
  61.     If keypressed Then
  62.       Begin
  63.         Read(KBD,ch);
  64.         keyin:=ord(ch);
  65.  
  66.         { The next 5 lines handle function keys on the Wang PC;
  67.           delete them or modify as required on other systems
  68.         If ch = chr(31) Then
  69.           Begin
  70.             Read(KBD,ch);
  71.             keyin:=ord(ch)
  72.           End  }
  73.  
  74.        End
  75.   End;
  76.  
  77.  
  78. { "menu" generates the menu display, allows the operator to select the desired
  79.   pick, and returns the number of the picked choice.  It returns a zero if
  80.   the "cancel" key is pressed.
  81.  
  82.   The parameter "number" specifies the number of choices on the menu, not
  83.   counting the heading item, which is considered item zero.
  84.  
  85.   The parameter "data" is an array of strings containing number+1 elements,
  86.   each with a maximum length of 30 characters.  The first element contains
  87.   the header line.  Note that the number of elements in the array is
  88.   undefined; it is up to the programmer to insure that "number" contains the
  89.   correct value, and the elements of the array are defined as String[30].  }
  90.  
  91.  
  92. Function menu(number: Integer; Var data): Integer;
  93.  
  94.   Const llen=80;      { screen line length }
  95.         slen=20;      { maximum number of items in one column }
  96.         maxnumber=40; { maximum size of list array }
  97.  
  98.         { The following constants describe the values returned by "keyin"
  99.           for the various keys used to control the display.  }
  100.  
  101.         uplistkey = 8;      { BACKSPACE }
  102.         downlistkey = 32;   { SPACE BAR }
  103.  
  104.  
  105.         { For IBM PC and others use the following }
  106.         cancelkey = 27;   { ESC }
  107.         executekey = 13;  { RETURN/ENTER }
  108.  
  109. (*      { The Following values are for Wang PC only }
  110.         cancelkey = 224;    { CANCEL }
  111.         executekey = 197;   { EXECUTE }  *)
  112.  
  113.  
  114.         { The following constants specify graphic characters which are used
  115.           to mark selected and non-selected items on the menu.  }
  116.  
  117.         { Use these for IBM PC and video compatibles }
  118.         menupointer = $FE;
  119.         menumarker = $1C;
  120.  
  121. (*      { Use these values for Wang PC }
  122.         menupointer = $87;
  123.         menumarker = $85;  *)
  124.  
  125. (*      { Use these for ASCII systems
  126.         menupointer = $3E;
  127.         menumarker = $2D;   }  *)
  128.  
  129.   Type  listtype=Array[0..maxnumber] Of String[30]; {Dummy type for menu list}
  130.   Var   list: listtype Absolute data;               { Dummy variable }
  131.         posn, len, margin, vmargin, maxlen: Integer;{ Positioning variables }
  132.         count, chval, cnumber: Integer;             { Position counters }
  133.         pointer, marker: String[3];                 { Graphic markers }
  134.         ch: Char;                                   { Temporary }
  135.  
  136.   Begin
  137.     pointer:='   '; pointer[2]:=chr(menupointer);  { Create graphic markers }
  138.     marker:='   '; marker[2]:=chr(menumarker);
  139.  
  140.     { Display Heading }
  141.     ClrScr; NormVideo;
  142.     write(chr(27),'[5h');  { ANSI cursor-off command; modify as required }
  143.     gotoxy(39-length(list[0]) Div 2,1);
  144.     write(list[0]);     { Title line }
  145.     { Insert any additional header line(s) here }
  146.     LowVideo;
  147.  
  148.     { Compute positioning parameters for single or double column }
  149.     If number > maxnumber Then number:=maxnumber;
  150.     If number <= slen Then len:=number Else len:=slen;
  151.     If number > slen Then margin:=0
  152.     Else
  153.       Begin
  154.         maxlen:=0;
  155.         For count:=1 to number Do
  156.            If length(list[count]) > maxlen Then maxlen:=length(list[count]);
  157.         margin:=39-((maxlen+2) Div 2)
  158.       End;
  159.     If number < slen Then vmargin:=(slen-number) Div 2
  160.     Else vmargin:=(slen-(number Div 2)) Div 2;
  161.     vmargin:=vmargin+3;
  162.     If number > slen Then cnumber:=number Div 2
  163.     Else cnumber:=number;
  164.  
  165.     { Display list }
  166.     For posn:=1 To cnumber Do
  167.       Begin
  168.         gotoxy(margin,posn+vmargin);
  169.         write(marker,list[posn]);
  170.         If ((number) > slen) And ((posn+cnumber) < number) Then
  171.           Begin
  172.             gotoxy(36,posn+vmargin);
  173.             write(marker,list[posn+cnumber])
  174.           End;
  175.         writeln
  176.       End;
  177.  
  178.     { Display Instructions; modify as required }
  179.     gotoxy(1,24); LowVideo;
  180.     writeln('Press SPACE or BACKSPACE or First Letter of Line to Select');
  181.     write('Press ENTER to run your choice, ESC for previous function');
  182.  
  183.     { Pick menu }
  184.     posn:=1;
  185.     Repeat
  186.       { Display current pick }
  187.       gotoxy(((posn-1) Div cnumber)*40+margin,
  188.              ((posn-1) Mod cnumber)+1+vmargin);
  189.       NormVideo;
  190.       write(pointer,list[posn]);
  191.       { Get Keyboard and clear current pick }
  192.       Repeat chval:=keyin Until chval <> 0;
  193.       gotoxy(((posn-1) Div cnumber)*40+margin,
  194.              ((posn-1) Mod cnumber)+1+vmargin);
  195.       LowVideo;
  196.       If chval <> executekey Then write(marker,list[posn]);
  197.  
  198.       { Determine new Pick }
  199.       If chval = executekey Then menu:=posn
  200.       Else If chval = cancelkey Then menu:=0
  201.       Else If chval = uplistkey Then
  202.         If posn > 1 Then posn:=posn-1
  203.         Else posn:=number
  204.       Else If chval = downlistkey Then
  205.         If posn < (number) Then posn:=posn+1
  206.         Else posn:=1
  207.       Else   { Check for first character of line }
  208.         Begin
  209.           count:=posn;
  210.           ch:=UpCase(chr(chval));
  211.           Repeat
  212.             count:=succ(count);
  213.             If count > number Then count:=1
  214.           Until (count = posn) Or (ch = UpCase(copy(list[count],1,1)));
  215.           posn:=count
  216.         End
  217.     Until (chval = executekey) Or (chval = cancelkey)
  218.   End;
  219.  
  220.  
  221.  
  222.  
  223. { The following program shows the use of "menu" as a basic program loader.
  224.   The typed constants are used to set up the menu, and can be changed to
  225.   provide any desired choice.  The program list is simply in the same order as
  226.   the descriptive lines.  Lines[0] defines the menu heading while progs[0] is
  227.   the program to be loaded if the "cancel" key is pressed.  }
  228.  
  229.  
  230. Const maxlines = 4; { number of lines in menu }
  231.  
  232.       lines: Array[0..maxlines] Of String[30] =
  233.          ('General Business Menu',
  234.           'Accounts Receivable',
  235.           'Accounts Payable',
  236.           'Payroll',
  237.           'General Ledger');
  238.  
  239.       progs: Array[0..maxlines] Of String[30] =  { list of programs to load }
  240.          ('MAINMENU.COM',
  241.           'AR.COM',
  242.           'AP.COM',
  243.           'PA.COM',
  244.           'GL.COM');
  245.  
  246. Var nextprog: File;
  247.  
  248. Begin  { Main Program }
  249.   assign(nextprog,progs[menu(maxlines,lines)]);
  250.   execute(nextprog)
  251. End.
  252.