                                   menu.pl
                                 Perl Menus
                                 Version 2.1
                              September 15, 1993

                               Steven L. Kunz
                           Networked Applications
                  Iowa State University Computation Center
                            Iowa State University
                                 Ames,  Iowa
                  
--------
Overview
--------

  The "menu.pl" package is a perl package (built into your perl program
  with a "require menu.pl" command) that automates curses-based full screen
  menus.  Using three simple calls, any number of items may be selected from
  a single or multiple-page menu by moving an arrow to the desired item (or
  directly entering the selection number displayed on the screen).  In
  addition to simple "single one-shot selection menus", "radio button"
  style menus and "multiple-item-selection" menus are provided. Paging
  through multiple-page menus is handled automatically.  Menu titles and 
  prompts are supported.

  The "menu.pl" package uses curses interface routine calls supplied by the
  "curseperl" package.  The "curseperl" package is distributed with the normal
  perl distribution in the "usub" directory.  The "curseperl" binary is a
  complete perl interpreter with the addition of many "curses" routines
  dealing with screen manipulation (cursor positioning, display of text at the
  current cursor location, etc).  Applications using "menu.pl" must be
  constructed to use "curseperl" instead of "perl". 

  Most applications using perl menus will use the following three calls
  (with the "menu_item" routine used multiple times to provide the menu
  selections) as follows:

     #!/usr/local/bin/curseperl
     ...
     &menu_init(1,"Select an Animal"); # Init menu

     &menu_item("Collie","dog");       # Add item
     &menu_item("Shetland","pony");    # Add item
     &menu_item("Persian","cat");      # Add last item

     $sel = &menu_display("Which animal?"); # Get user selection

     if ($sel eq "%UP%") { ... }
     if ($sel eq "dog") { ... }
     ...

  When this code is executed, only the call to "menu_display" will actually 
  cause the constructed menu to be displayed to the user for selection.
  The title is centered and displayed at the top of the screen in reverse
  video.  The selection items are automatically numbered and presented in
  the order they were added.  The prompt is displayed at the bottom of the
  screen preceded by an indication of how many of the items in the menu
  are presented on the current screen ("All" or some percentage).  In the 
  above example, the menu would look like:

                              Select an Animal

     -> 1) Collie
        2) Shetland
        3) Persian

     (All)  Which animal?

  Only one menu may be active at a time.  In applications with "layers" of
  menus, only the "current layer" menu is maintained in memory.  As you use
  the "up" function to "pop up" to a previous menu, your application must
  return to a subroutine (or upper program layer) that reconstructs the menu
  for that layer of the application and displays it.  Since the lower layer
  used a "menu_init" to construct that menu, the "upper layer" must reconstruct
  the entire menu appropriate at that level.  Support is provided (with
  proper programming of the application) to go directly to the "top" (first)
  menu and to remember the selection position in a previous menu. 


-------------------------
Solicitation for Comments
-------------------------

  If you like "menu.pl" and have put it to a useful purpose, I would
  appreciate a few lines indicating where you are and what you are using it
  for.  Likewise, if you have found a bug, documentation problem, or would
  really like to see a certain feature, feel free to let me know about those,
  too.  Send your e-mail cheers/jeers to "skunz@iastate.edu".  


--------------
Card of Thanks
--------------

  A big "thank you" to the following people who have taken time to notice
  some improvements that could be made in the menu.pl code and mail them
  to me.  Specifically:

  - Greg Kresko (National Research Council Canada)
    Found some problems with "endwin" statement placement (or lack thereof). 
    Incorporated in the version 2.1 release.


-------------------------------------
Initializing a new menu - "menu_init"
-------------------------------------

  Routine:      menu_init

  Syntax:       &menu_init(num_flag,"title string",top_flag);

  Input args:   - Boolean flag (0=unnumbered menu, 1=numbered menu).
                  Required, no default.
                - Title string (string centered at top of menu).
                  Required, no default.
                - Boolean flag (0=non-top menu, 1=top menu).
                  Optional, defaults to zero.

  Returns:      Nothing.

  The "menu_init" call resets the menu array and indexes.  It must be called
  to reset/clear any old menu.  The first parameter is a boolean flag
  indicating whether or not the menu should be numbered and have a selection
  arrow "->" provided (a non-zero value indicates a numbered menu).  By
  default, the "title string" is centered at the top of the screen and
  presented in "standout" rendition (usually reverse video or bold).  If the
  first character of the title is a dash ("-") then the title will be
  presented in "normal" rendition ("standout" will be suppressed).  Title
  text that exceeds the width of the screen is automatically truncated on
  the right to fit the available width.

  The "top flag" is used to provide support for "top level" menus, discussed
  further in a later section of this document.


------------------------------------
Adding items to a menu - "menu_item"
------------------------------------

  Routine:      menu_item

  Syntax:       &menu_item("Selection text","action_text");

  Input args:   - Selection text (the string the user sees).
                  Required, no default.
                - Action text (string returned if item is selected).
                  Required, no default.

  Returns:      Current number of items in the menu.

  The "menu_item" call provides selection text (what the user sees on the
  screen) and "action_text" (not seen - but returned if that item is
  selected).  There is no practical limit (other than memory or maximum
  array index size) on the number of items in a menu.  The items are
  presented in the order you add them and the top (first) item is always
  the default (except when using the "latched" menu support outlined in
  a later section).  Some "menu_display_" calls ("menu_display_radio" and
  "menu_display_mult") will automatically add a top item selection for you.
  Refer to those commands for more information.  Selection text that exceeds
  the width of the terminal is automatically truncated on the right by the
  "menu_item" call.  The "action_text" may be a null string (in which case a
  null string is returned upon selection).


-----------------------------------------------------
Simple display/selection from a menu - "menu_display"
-----------------------------------------------------

  Routine:      menu_display

  Syntax:       $sel_var = &menu_display("Prompt text",$arrow_loc,$top_item);

  Input args:   - Prompt text (string for bottom line).
                  Optional, defaults appropriate for menu.
                - Item line on screen to place the arrow.
                  Optional, defaults to zero (the first item).
                - Index of item to place at top of screen.
                  Optional, defaults to zero (the first item).

  Returns:      "<action-text>" or "%UP%" or "%EMPTY%"

  The "menu_display" call is the only call that actually writes data on the
  screen.  When it returns you have one of the following strings:

    "%UP%"          -- indicating the user did not select anything but 
                       pressed "u" (or possibly "t" - for "top menu", see
                       below) to exit the menu.

    "%EMPTY%"       -- indicating no calls were made to "menu_item" since 
                       the last "menu_init" call.

    "<action-text>" -- one of the selection-action strings given on a 
                       "menu_item" call.  

  You can either provide your own prompt as a call parameter to
  "menu_display"  or you can provide a null string (&menu_display("")) in
  which an automatic prompt is provided.  All paging functions are handled
  within the call to "menu_display" automatically.  The last two arguments
  are used for "latched" menus, discussed in a later section.

  Support is provided for just simply typing the selection number of the
  item on the screen - you do not have to move the selection arrow to the item
  if you prefer to type the number (followed by "return").  The arrow ("->")
  displayed on the screen will automatically jump to the selection that is the
  "best fit" for what is typed so far.  For example, if items 1-20 are
  currently on the screen, pressing a "2" will cause the arrow to jump to the
  "2)" selection.  Typing "0" (to indicate "20") causes the arrow to next jump
  to the "20)" selection.  A "return" key actually activates the selection.  A
  "delete" or "backspace" key (or any cursor-movement key) clears the "direct
  entry" selection process at any time before "return" is pressed.  

  One final note.  The call to "menu_display" will ALWAYS turn back on echo
  - so if you really want it off you will have to call "noecho" again after 
  each call to "menu_display". 


----------------------------------------------------------------------
Displaying/selecting from a "radio button" menu - "menu_display_radio"
----------------------------------------------------------------------

  Routine:      menu_display_radio

  Syntax:       $sel_var = &menu_display_radio("Prompt","current","Accept");

  Input args:   - Prompt text (string for bottom line).
                  Optional, defaults appropriate for menu.
                - Current "action-text" deemed as "set".  Any menu-item
                  with this "action-text" will have the selection box X'd.
                  Optional, if not set no selections will be set at start.
                - Text supplied for first item (which indicates selections
                  are done.
                  Optional, defaults to "(Accept this setting)".

  Returns:      "<action-text>" or "%UP%"

  The "menu_display_radio" call is similar to the "menu_display" call, 
  except that it provides a "pushbutton radio" style of menu display which
  indicates the current setting (selection) in the menu while providing an
  opportunity to change it.  A "radio button" menu uses the same "menu_init"
  and "menu_item" calls as any other menu.  However, the "menu_display_radio"
  call produces a menu similar to the following example:

                           Delete Confirmation

      ->   1) (Accept this setting)
           2) [X] Ask permission first
           3) [ ] Just do it

      (All) h)elp q)uit u)p t)op b)egin e)nd r)efresh

  Here a "button box" ("[ ]" is presented in front of the selection text
  indicating the current setting/selection.  The user is given the
  opportunity to select another item (moving the "X" from box to box).
  When the desired setting/selection is set, item 1 (which is automatically
  provided for you by the "menu_display_radio" call) is selected and the
  menu function returns to the caller.  You can override the default text
  for the item 1 selection on the "menu_display_radio" call.
 
  When it returns you have one of the following strings:

    "%UP%"          -- indicating the user did not select anything but 
                       pressed "u" (or possibly "t" - for "top menu", see
                       below) to exit the menu.

    "%EMPTY%"       -- indicating no calls were made to "menu_item" since 
                       the last "menu_init" call.

    "<action-text>" -- one of the selection-action strings given on a 
                       "menu_item" call.  

  You can either provide your own prompt as a call parameter to
  "menu_display_radio"  or you can provide a null string 
  (&menu_display_radio("",...)) in which an automatic prompt is provided.
  All paging functions are handled within the call to "menu_display_radio"
  automatically.


-------------------------------------------------------------------------
Displaying/selecting from a multiple selection menu - "menu_display_mult"
-------------------------------------------------------------------------

  Routine:      menu_display_mult

  Syntax:       $sel = &menu_display_mult("Prompt text","Done text");

  Input args:   - Prompt text (string for bottom line).
                  Optional, defaults appropriate for menu.
                - Text supplied for first item (which indicates selections
                  are done).
                  Optional, defaults to "(Done with selections)".

  Returns:      "<action-text>" or "%UP%" or "%NONE%"

  The "menu_display_mult" call is similar to the "menu_display" call, 
  except that it provides a multiple-selection style of menu display which
  returns the "<action-text>" values in comma-separated string (instead of a
  single value variable).  A multiple-selection menu uses the same
  "menu_init" and "menu_item" calls as any other menu.  However, the
  "menu_display_mult" call produces a menu similar to the following example:

                           Select one or more items

      ->   1) (Done with selections)
           2) [X] Cat
           3) [ ] Dog
           4) [X] Goldfish
           5) [ ] Mouse 

      (All) h)elp q)uit u)p a)ll m)atch c)lear n)ext-pg p)rev-pg b)egin e)nd

  In this type of menu display the user can toggle selections on or off
  until the desired set is chosen.  Indicating "(Done with selections)"
  results in the multiple-selection string being returned to the caller.
  When it returns you have one of the following strings:

    "%UP%"          -- indicating the user pressed "u" (or possibly 
                       "t" - for "top menu", see below) to exit the menu.
                       Note that even if they HAD selected something, 
                       returning from the menu with a "u" discards the
                       selections.

    "%NONE%"        -- indicating no items were selected by the user
                       the last "menu_init" call.

    "<action-text>" -- one or more of the selection-action strings (comma
                       separated) given on a "menu_item" call.  


  Typically, this string will be broken by the caller into individual
  items for processing by perl code similar to the following: 

      $sel = &menu_display_mult("");
      if ($sel eq "%UP%") { return; }
      if ($sel eq "%NONE%") {
        print "(You didn't select anything)\n";
      } else {
        print "You selected the following:\n";
        split(/[,]/,$sel);  # Put return in @_
        foreach (@_) { print "  $_\n"; }
      }

  Note that you should normally be careful not to use commas on the "action
  text" portions of menu_item calls (UNLESS you know you want one item to
  be parsed out as multiple selections - a subtle "feature").


--------------------
"Top" Menu Support
--------------------

  There is limited support for "top" menus.  By following a careful program
  structure you can allow the user to type a "t" at any menu display and have
  the next menu presented be the "top" (first) menu presented.  This provides
  a convenient means for the user to jump to the top of a multiple-level menu
  structure from several menu-levels down. 

  Since there is only one menu active at a time, pressing "t" to indicate
  the "top" menu merely generates an "%UP%" return from the current menu
  (refer to the "menu_display" call).  However, top's "%UP%" return is
  different from a normal "u" up-action in that an internal flag is set so
  that all subsequent calls to ANY "menu_display" immediately return with an
  "%UP%" selection.  This action continues until a menu is displayed that was
  initialized with a special flag in the "menu_init" call that indicates it is
  the "top" menu.  Once a "menu_display" is called for a menu that has this
  special "menu_init" call, the "automatic %UP% return" stops and the "top
  menu" is displayed.  This special "top menu" is initialized as follows:  

      &menu_init(num_flag,"title string",1); # A "top" menu_init call

  The third parameter (a "1") indicates this is the "top" menu.

  The "top" menu support requires special care in programming.  With
  careless programming you could enter a loop if a "t" was pressed and the
  curseperl program provided no "top menu_init" call.  To provide some level
  of protection, the "t" menu hot-key and "top" support is disabled
  automatically UNLESS the FIRST "menu_init" call is also a "top menu_init"
  call (indicating the software was programmed with "top" menus in mind). 

  The "demotop" program distributed with this release of "menu.pl" provides
  an example of correct usage of the "top menu" features.   


--------------------
"Latched" Menus
--------------------

"Latched" menu support offers the ability to remember where you were in a
menu when it is re-displayed later.  This is often useful in traversing
a menu-tree down and then returning to previous menus (and selection
locations) when "popping back up" the tree (with the "up" hot-key).  The
only action necessary to remember position is the addition to two parameters
on the "menu_display" call as follows:

     $sel_var = &menu_display("Prompt text",$arrow_loc_var,$top_item_var);

These two values indicate the location of the arrow line on the menu screen
and the index number of the top "menu_item" on the menu screen.  If you want
the first item the first time, these values should both be initialized to
zero (first item on the first page).  This will generate the same action as
if they were not specified - the default "non-latched" call.  These two
optional parameters also are used to RETURN the value of the top item on
a menu-page and arrow location AFTER the user selected something (and the
"menu_display" routine returns).  If you do not modify the two parameters,
rebuild the menu the same way, and call "menu_display" supplying the returned
values, the menu will be displayed in the original "selection" location.

By letting "menu_display" store selection locations before moving to a lower
level in your "menu-tree" (via a subroutine call to another menu-generator),
a return from the lower level can regenerate any given levels menu and
reposition the selection location automatically.  Make sure you store your
"latch" variables in "local" storage (one set for each menu-generator
routine that has a "menu_display" call).

One final note - the "menu_display" routine will check and automatically
adjust the values to meet current menu limits.  For example, if your menus
are "dynamic" and items "disappeared" (making your last latch position off
the end of the reconstructed menu), the "menu_display" routine will adjust
to point to the the last item in the menu (adjusting the "top item" as
needed). 
 

------------------------
Other "menu.pl" Routines
------------------------

  --------
  Routine:      menu_curses_application

  Syntax:       &menu_curses_application;

  Input args:   None.

  Returns:      Nothing.

  It is assumed that the application calling the menu routines is not a
  "curseperl" application (i.e. it is a "stock" perl script except for calls
  to "menu.pl" routines).  However, if you are writing an "all-curses"
  application (calling curses functions from your routines) you should call
  "menu_curses_application" FIRST (once).  This sets a flag so that the
  "initscr" and "endwin" calls are NOT done by the menu.pl package calls (and
  assumes you will do them).  

  --------
  Routine:      menu_quit_routine

  Syntax:       &menu_quit_routine("routine_name");

  Input args:   String with name of routine to be called.
                Required, no default.

  Returns:      Nothing.

  The menu routines will process a "q" for "quit" locally.  In other words,
  if the user presses "q" while a menu is displayed (and responds to the
  "Do you really want to quit?" prompt with a "y") the perl program will
  immediately exit.  However, support is provided for a "user" exit that
  will be called just before dropping out the program (to perform any
  "cleanup" duties).  Calling "&menu_quit_routine("rtn_name");" will set
  the exit routine.
   
  --------
  Routine:      menu_shell_command

  Syntax:       &menu_shell_command("shell-path");

  Input args:   String with command to issue to spawn a shell ("/bin/csh",
                for example).  If null, ability to use "!" from a menu to
                get a command prompt is disabled (the default condition).
                
  Returns:      Nothing.

  If you want to give your users the ability to suspend the perl menu
  program at any menu and spawn off a subshell (and get a command prompt),
  you can issue this call with the shell-path as the argument.  When any
  menu is displayed, a user can press the exclamation point ("!") and get a
  command prompt.  Exiting the shell re-displays the menu exited from and
  continues processing.  Many systems have an environment variable indicating
  the current shell such as "SHELL".  If so, the best way to activate this
  ability is to issue a command such as "&menu_shell_command($ENV{"SHELL"});"
  early in the program.  Shell-escaping can be disabled by issuing the
  command with a null string as the argument (reverting to the default mode).

  --------
  Routine:      menu_getstr

  Syntax:       $str_var = &menu_getstr(row,col,"prompt text",0|1);

  Input args:   - Row and column for input of data. (Required)
                - Prompt text (optional).  Default to no prompt.
                - Boolean flag (0=no-clear, 1=clear-after-user-entry)

  Returns:      String (may be null)
                
  This is a utility routine written for "match string" prompting that proves
  useful in any perl-based curses application.  The row and column of a 
  position on the screen where you want to input text is supplied (with an
  optional prompt).  Character entry is allowed from the right edge of the
  prompt to the right edge of the screen.  The left and right cursor keys
  may be used to move within text already typed in, with the cursor location
  being an "insert/delete" point.  This allows for C-shell-like data entry.

  The call to "menu_getstr" will ALWAYS turn back on echo - so if you
  really want it off you will have to call "noecho" again after each call
  to "menu_getstr". 


--------------
For the record
--------------

Copyright (C) 1992-93  Iowa State University Computation Center
                       Ames, Iowa (USA)

menu.pl is free software; you can redistribute it and/or modify it under the 
terms of the GNU General Public License as published by the Free Software 
Foundation; either version 1, or (at your option) any later version.  

menu.pl is distributed in the hope that it will be useful, but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
details.  

You should have received a copy of the GNU General Public License along with 
menu.pl.  If not, write to:

  The Free Software Foundation 
  675 Mass Ave
  Cambridge, MA 02139, USA
