home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / lang / perl / 7524 < prev    next >
Encoding:
Text File  |  1992-12-21  |  46.9 KB  |  1,513 lines

  1. Newsgroups: comp.lang.perl
  2. Path: sparky!uunet!cs.utexas.edu!zaphod.mps.ohio-state.edu!uwm.edu!ux1.cso.uiuc.edu!news.iastate.edu!corvette.cc.iastate.edu!skunz
  3. From: skunz@iastate.edu (Steven L Kunz)
  4. Subject: menu.pl v1.3 - curseperl menu facility
  5. Message-ID: <skunz.724699100@corvette.cc.iastate.edu>
  6. Sender: news@news.iastate.edu (USENET News System)
  7. Organization: Iowa State University, Ames IA
  8. Date: Fri, 18 Dec 1992 17:18:20 GMT
  9. Lines: 1502
  10.  
  11. This is a new/improved distribution of my "menu.pl" package.
  12. The current version is "menu.pl version 1.3".  The last version I
  13. distributed via "comp.lang.perl" was version 1.1.
  14.  
  15. For PREVIOUS users of "menu.pl", this version contains bug fixes, "top" level
  16. menu support, "latched" (remembered) menu position support, and (maybe most
  17. important) a user document for the routines.  This version is compatible
  18. with all old calls (so your old code should still work with the new
  19. package).
  20.  
  21. For NEW menu.pl package users (from the top of MENU_DOC) ...
  22.                   
  23. --------
  24. Overview
  25. --------
  26.  
  27.   The "menu.pl" package is a perl package (built into your perl program
  28.   with a "require menu.pl" command) that automates curses-based full screen
  29.   menus.  Using three simple calls, any number of items may be selected from a
  30.   single or multiple-page menu by moving an arrow to the desired item or
  31.   directly entering the selection number displayed on the screen.  Paging
  32.   through multiple-page menus is handled automatically.  Menu titles and 
  33.   prompts are supported. 
  34.  
  35.   The "menu.pl" package uses curses interface routine calls supplied by the
  36.   "curseperl" package.  The "curseperl" package is distributed with the normal
  37.   perl distribution in the "usub" directory.  The "curseperl" binary is a
  38.   complete perl interpreter with the addition of many "curses" routines
  39.   dealing with screen manipulation (cursor positioning, display of text at the
  40.   current cursor location, etc).  Applications using "menu.pl" must be
  41.   constructed to use "curseperl" instead of "perl". 
  42.  
  43.   Most applications using perl menus will use the following three calls
  44.   (with the "menu_item" routine used multiple times to provide the menu
  45.   selections) as follows:
  46.  
  47.      #!/usr/bin/curseperl
  48.      ...
  49.      &menu_init(1,"Select an Animal"); # Init menu
  50.  
  51.      &menu_item("Collie","dog"); # Add item
  52.      &menu_item("Shetland","pony"); # Add item
  53.      &menu_item("Persian","cat"); # Add last item
  54.  
  55.      $sel = &menu_display("Which animal?"); # Get user selection
  56.  
  57.      if ($sel eq "dog") { ... }
  58.      ...
  59.  
  60. ---------------------- menu.pl version 1.3 distribution --------------------
  61. #!/bin/sh
  62. # to extract, remove the header and type "sh filename"
  63. if `test ! -s ./demo`
  64. then
  65. echo "writing ./demo"
  66. cat > ./demo << '\End\Of\Shar\'
  67. #!../bin/curseperl
  68. #
  69. # demo --  Simple perl menu demo
  70. #
  71. # Note:    Requires curseperl
  72. #          Demonstrates "latched" (remembered) menu position technique 
  73. #          in "long" menu routine.
  74. #
  75. # Author:  Steven L. Kunz
  76. #          Networking & Communications
  77. #          Iowa State University Computation Center
  78. #          Ames, IA  50011
  79. #          Email: skunz@iastate.edu
  80. #
  81. # Date:    Dec, 1992
  82. #
  83.  
  84. require "./menu.pl";
  85.  
  86.   $menu_default_top = 0; # Storage for mainline top item number.
  87.   $menu_default = 0;     # Storage for mainline arrow location.
  88.  
  89.   while (1) {
  90.     &menu_init(1,"Demo Selection");
  91.     &menu_item("Exit this demo","exit");
  92.     &menu_item("See a single-page menu demo","test_short_menu");
  93.     &menu_item("See a multiple-page menu demo","test_long_menu");
  94.  
  95.     $sel = &menu_display("Which demo would you like to see?",
  96.                          $menu_default,$menu_default_top);
  97.  
  98.     if ($sel eq "exit") { last; }
  99.     if ($sel ne "%UP%") { 
  100.       
  101.       &$sel; # Note that this assumes the "action_text" is a subroutine name    
  102.     }
  103.   }
  104.   exit;
  105.  
  106. #
  107. #  Build a short (one page) demo menu.
  108. #
  109. sub test_short_menu {
  110.   local($sel);
  111.  
  112.   while (1) {
  113.  
  114. # Init a numbered menu with a title
  115.     &menu_init(1,"Short Menu (fits on one page)");
  116.  
  117. # Add item to return to main menu.
  118.     &menu_item("Exit \"Short Menu\" demo","exit");
  119.  
  120. # Add several items
  121.     &menu_item("Dog","animal");
  122.     &menu_item("Cat","animal");
  123.     &menu_item("Granite","mineral");
  124.     &menu_item("Mouse","animal");
  125.     &menu_item("Shale","mineral");
  126.     &menu_item("Onion","vegetable");
  127.     &menu_item("Carrot","vegetable");
  128.  
  129. # Display menu and process selection.
  130. # Note that previous position is not remembered because parms 2 and 3 
  131. # are not supplied to store values used on subsequent call.
  132.     $sel= &menu_display("");
  133.  
  134.     if (($sel eq "%UP%") || ($sel eq "exit")) { return; }
  135.     print "You picked a $sel.\n";
  136.     $ch = <>;
  137.   }
  138. }
  139.  
  140. #
  141. # Build demo long menu (several pages)
  142. #
  143. sub test_long_menu {
  144.   local($sel_num);
  145.  
  146.   local($menu_default_top) = 0; # Storage for local top menu item number.
  147.   local($menu_default) = 0;     # Storage for local arrow location.
  148.  
  149.   while (1) {
  150.  
  151. # Init a numbered menu with title
  152.     &menu_init(1,"Long Menu (fits on several pages)");
  153.  
  154. # Add item to return to main menu.
  155.     &menu_item("Exit \"Long Menu\" demo","exit");
  156.  
  157. # Build 50 entries in the menu
  158.     $i = 1;
  159.     while ($i < 50) {
  160.       $sel_num = $i + 1;
  161.       &menu_item("Item $sel_num","action-$sel_num");
  162.       $i++;
  163.     }
  164.  
  165. # Get user selection.
  166. # Note that local parms 2 and 3 are provided to provide storage of the
  167. # default arrow location and top menu item on the screen for subsequent call.
  168.     $sel = &menu_display("",$menu_default,$menu_default_top);
  169.  
  170.     if (($sel eq "%UP%") || ($sel eq "exit")) { return; }
  171.     print "You picked the item with selection-action $sel.\n";
  172.     $ch = <>;
  173.   }
  174. }
  175. \End\Of\Shar\
  176. else
  177.   echo "will not over write ./demo"
  178. fi
  179. if [ `wc -c ./demo | awk '{printf $1}'` -ne 2867 ]
  180. then
  181. echo `wc -c ./demo | awk '{print "Got " $1 ", Expected " 2867}'`
  182. fi
  183. if `test ! -s ./README`
  184. then
  185. echo "writing ./README"
  186. cat > ./README << '\End\Of\Shar\'
  187.                                    menu.pl
  188.                                  Perl Menus
  189.                                  Version 1.3
  190.                               December 18, 1992
  191.  
  192.                                Steven L. Kunz
  193.                          Networking & Communications
  194.                   Iowa State University Computation Center
  195.                             Iowa State University
  196.                                  Ames,  Iowa
  197.                   
  198.  
  199. This is "menu.pl" - a set of perl routines that will perform full screen
  200. menu functions using "curseperl".  What you should have after unpacking 
  201. this package is the following:
  202.  
  203.   README         (this file)
  204.  
  205.   RELEASE_NOTES  Differences between this version and previous versions.
  206.  
  207.   MENU_DOC       A user's guide to the menu.pl routines.
  208.  
  209.   demo           A simple menu demo.
  210.  
  211.   demotop        A simple menu demo with "top" menus.
  212.  
  213.   ezview         A more involved demo showing how menus can be used to call
  214.                  routines, select files, etc.
  215.  
  216.   menu.pl        The perl menu subroutines in a package (usually placed 
  217.                  somewhere like /usr/local/lib/perl/menu.pl)
  218.  
  219.   ultpatch       Patches I had to apply to the bsdcurses.mus file to make 
  220.                  it work on an ULTRIX (BSD based) system.
  221.  
  222. Installation:
  223.  
  224.   1) If you don't have curseperl working and installed somewhere, go into
  225.      your perl.4.35 distribution (in the "usub" directory) and construct it
  226.      following the instructions there.  Be forewarned that when I put it 
  227.      together it didn't work on my ULTRIX 4.2a system - I had to install some
  228.      patches I got off comp.lang.perl (posted by drw@nevanlinna.mit.edu)
  229.      and some changes I had to add myself.  The file "ultpatch" is the
  230.      diffs between what I run and what is distributed with perl.  Patch
  231.      your original bsdcurses.mus with this if you are having trouble
  232.      getting curseperl to work with ULTRIX.  These patches mainly involve
  233.      commenting out routine calls absent in the ULTRIX curses package.
  234.  
  235.      Install your "curseperl" in the same location as your normal "perl"
  236.      binary.
  237.  
  238.      You will probably have to modify the first lines of the demo scripts
  239.      ("demo", "demotop", and "ezmail") to point to where your "curseperl" 
  240.      is installed.
  241.  
  242.   2) Put "menu.pl" with the rest of your perl packages (usually in something
  243.      like "/usr/local/lib/perl").  The demo programs will work by just leaving
  244.      a copy of "menu.pl" in the same directory as the demo scripts.
  245.  
  246.  
  247. ---
  248. Steven L. Kunz
  249. Networked Applications
  250. Iowa State University Computation Center, Iowa State University, Ames  IA
  251. INET: skunz@iastate.edu     BITNET: gr.slk@isumvs.bitnet
  252. \End\Of\Shar\
  253. else
  254.   echo "will not over write ./README"
  255. fi
  256. if [ `wc -c ./README | awk '{printf $1}'` -ne 2682 ]
  257. then
  258. echo `wc -c ./README | awk '{print "Got " $1 ", Expected " 2682}'`
  259. fi
  260. if `test ! -s ./ezview`
  261. then
  262. echo "writing ./ezview"
  263. cat > ./ezview << '\End\Of\Shar\'
  264. #!../bin/curseperl
  265. #
  266. # EasyView -- Unix File Viewer/Editor Interface
  267. #             (a "practical" demo for menu.pl)
  268. #
  269. # Note:    Requires curseperl
  270. #
  271. # Author:  Steven L. Kunz
  272. #          Networking & Communications
  273. #          Iowa State University Computation Center
  274. #          Ames, IA  50011
  275. #          Email: skunz@iastate.edu
  276. #
  277. # Date:    May, 1992
  278. #
  279.  
  280. require "./menu.pl";
  281.  
  282.     $lines = $LINES; $lines1 = $lines - 1; $lines2 = $lines - 2;
  283.     $cols = $COLS;   $cols1  = $cols  - 1; $cols2  = $cols  - 2;;
  284.  
  285.     $SIG{'INT'} = 'cleanup';
  286.     $| = 1;        # command buffering on stdout
  287.  
  288.   $last_arrow = 0;
  289.   $last_top = 0;
  290. #
  291. #  MAIN_MENU -- Main (top level) menu
  292. #
  293.   while (1) {
  294.     &menu_init(1,"EasyView Version 1.1");
  295.     &menu_item("Exit","%UP%");
  296.     &menu_item("List files in current directory","dir_list");
  297.     &menu_item("Page through a text file","page_file");
  298.     &menu_item("Edit a text file","edit_file");
  299.  
  300.     $subr = &menu_display("",$last_arrow,$last_top);
  301.     if ($subr eq "%UP%") { 
  302.       &cleanup;
  303.     }
  304.     if ($subr ne "") { &$subr; }    # Call subroutine selected
  305.   }
  306.  
  307. #**********
  308. #  DIR_LIST -- Provide directory list
  309. #**********
  310. sub dir_list {
  311.    &dir_select(0,".","Directory Contents");
  312. }
  313.  
  314. #***********
  315. #  PAGE_FILE -- Page through a file in the current directory
  316. #
  317. #  Arguments:  None
  318. #
  319. #  Returns:    Nothing
  320. #
  321. #  Note: Uses file as an unnumbered menu
  322. #***********
  323. sub page_file {
  324.   local($filename,$last_arrow,$last_top);
  325.  
  326. # Call utility function to select file
  327.   $title = "Select file to page through";
  328.   $filename = &dir_select(1,".","Select file to page through");
  329.   if ($filename eq "%UP%") {
  330.     return;
  331.   }
  332.  
  333. # Load file as an unnumbered menu - let menu_display do the paging
  334. #
  335. # Special thanks: The tab expansion used here was lifted from the
  336. # "pager" program distributed with perl.4.19 in the "usub" directory.
  337. # Don't know who wrote it but it fit the bill.  SLK
  338. #
  339.   &menu_init(0,"File: $filename");
  340.   open(TEMP,$filename);
  341.   while (<TEMP>) {
  342.     s/^(\t+)/'        ' x length($1)/e;
  343.     &expand($_) if /\t/;
  344.     &menu_item($_,"");
  345.   }
  346.   &menu_display("",$last_arrow,$last_top);
  347.   close(TEMP);
  348. }
  349.  
  350. sub expand {
  351.     while (($off = index($_[0],"\t")) >= 0) {
  352.         substr($_[0], $off, 1) = ' ' x (8 - $off % 8);
  353.     }
  354. }
  355.  
  356.  
  357. #***********
  358. #  EDIT_FILE -- Edit a file in the current directory
  359. #***********
  360. sub edit_file {
  361.   &clear;
  362.   $title = "Select file to edit";
  363.   $filename = &dir_select(1,".","Select file to edit");
  364.   if ($filename eq "%UP%") {
  365.     return;
  366.   }
  367.   system("vi $filename");
  368. }
  369.  
  370. #************
  371. #  DIR_SELECT -- Load a formatted directory list into a menu.
  372. #
  373. #  Arguments:  Boolean flag indicating numbered menu (1=yes), directory 
  374. #              name string and top-title string for menu
  375. #
  376. #  Returns:    File name (or "%UP%")
  377. #************
  378. sub dir_select {
  379.   local($numbered,$directory,$title) = @_;
  380.   local($last_arrow,$last_top) = 0;
  381.   opendir(DIR,$directory);
  382.   &menu_init($numbered,$title);
  383. dir_entry:
  384.   while ($filename = readdir(DIR)) {
  385.     next dir_entry if ($filename eq "."); 
  386.     next dir_entry if ($filename eq ".."); 
  387.     ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
  388.      $blksize,$blocks) = stat($filename);
  389.     ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($mtime);
  390.     $mon++;
  391.     $sel_action = $filename;
  392.     $filename=$filename.substr("                    ",0,20-length($filename));
  393.     $sel_text = sprintf("%s%s%02d/%02d/%02d %02d:%02d  %s\n",
  394.                 $filename,$filler,$mon,$mday,$year,$hour,$sec,getpwuid($uid));
  395.     &menu_item($sel_text,$sel_action);
  396.   }
  397.   $fn = &menu_display("",$last_arrow,$last_top);
  398.   $fn;
  399. }
  400.  
  401. sub cleanup {
  402.   &clear;
  403.   &refresh;
  404.   exit;
  405. }
  406. \End\Of\Shar\
  407. else
  408.   echo "will not over write ./ezview"
  409. fi
  410. if [ `wc -c ./ezview | awk '{printf $1}'` -ne 3670 ]
  411. then
  412. echo `wc -c ./ezview | awk '{print "Got " $1 ", Expected " 3670}'`
  413. fi
  414. if `test ! -s ./menu.pl`
  415. then
  416. echo "writing ./menu.pl"
  417. cat > ./menu.pl << '\End\Of\Shar\'
  418. #****************************************************************************
  419. # menu.pl -- Perl Menu Support Facility 
  420. #
  421. # Version: 1.3
  422. #
  423. # Author:  Steven L. Kunz
  424. #          Networking & Communications
  425. #          Iowa State University Computation Center
  426. #          Ames, IA  50011
  427. #
  428. # Bugs:    skunz@iastate.edu
  429. # Cheers:  skunz@iastate.edu
  430. #
  431. # Date:    Version 1.0 -- May, 1992 -- Original version 
  432. #          Version 1.1 -- Aug, 1992 -- Minor enhancements, bugfixes
  433. #          Version 1.2 -- Nov, 1992 -- Selection bugfix
  434. #          Version 1.3 -- Dec, 1992 -- "top" and "latch" functions added
  435. #
  436. # Notes:   This package requires curseperl
  437. #          (distributed with perl 4.35 in the usub directory).
  438. #
  439. #          Use:
  440. #             &menu_init(1,"title");
  441. #             &menu_item("Topic 1","got_1");
  442. #             &menu_item("Topic 2","got_2");
  443. #             ...
  444. #             &menu_item("Topic n","got_n");
  445. #             $sel_text = &menu_display("Select using arrow keys");
  446. #
  447. #****************************************************************************
  448.  
  449. package perlmenu;
  450.  
  451. $did_initterm = 0;
  452. $curses_application = 0;
  453. $menu_exit_routine = "main'clear";
  454. $menu_is_first_one = 1;
  455. $menu_is_top_one = 0;
  456. $menu_top_activated = 0;
  457. $finding_top = 0;
  458.  
  459. #**********
  460. #  MENU_CURSES_APPLICATION
  461. #
  462. #  Function:    Indicate application is using curses calls.  If called, 
  463. #        the menu routines will not do initscr and endwin calls 
  464. #        (the application must do them).
  465. #
  466. #  Call format:    &menu_curses_application;
  467. #
  468. #  Arguments:    None
  469. #
  470. #  Returns:    Nothing
  471. #**********
  472. sub main'menu_curses_application { $curses_application = 1; }
  473.  
  474. #**********
  475. #  MENU_QUIT_ROUTINE
  476. #
  477. #  Function:    Specify a "cleanup" routine to be called before a "quit"
  478. #        from the application is processed.
  479. #
  480. #  Call format:    &menu_quit_routine("string");
  481. #
  482. #  Arguments:    String containing name of exit routine to call.
  483. #
  484. #  Returns:    Nothing.
  485. #
  486. #**********
  487. sub main'menu_quit_routine { $menu_exit_routine = "main'@_"; }
  488.  
  489. #**********
  490. #  MENU_INIT
  491. #
  492. #  Function:    Initialize menu type (numbered or unnumbered), arrays, 
  493. #        title, and "top" flags.
  494. #
  495. #  Call format:    &menu_init([0|1],"Top Title");
  496. #
  497. #  Arguments:   Boolean flag indicating whether or not a arrows and numbers
  498. #               are desired (0=no, 1=yes) and title text (for the top line
  499. #               of menu) and an optional boolean top-menu indicator.
  500. #
  501. #  Returns:    Nothing
  502. #
  503. #  Notes:    1) If the title string begins with a "-" the title is not
  504. #           presented in reverse-video ("standout") representation.
  505. #               2) If this is the FIRST menu_init call and the optional
  506. #                  third opernd is "1", it is the "top" menu.
  507. #**********
  508. sub main'menu_init {
  509.   ($menu_numbered,$menu_top_title,$menu_is_top_one) = @_;
  510.  
  511. # Perform initscr if not a curses application
  512.   if (!$curses_application) { &main'initscr; }
  513.  
  514. # Load "magic sequence" array based on terminal type
  515.   if (!$did_initterm) {        # Get terminal info (if we don't have it).
  516.     &defbell unless defined &bell;
  517.  
  518.     $ku = &main'getcap('ku');    # Cursor-up
  519.     $kd = &main'getcap('kd');    # Cursor-down
  520.     $cr = &main'getcap('cr');    # Carriage-return
  521.     $nl = &main'getcap('nl');    # New-line
  522.     $ansi_ku = "\033[A";    # Ansi cursor-up (for DEC xterm)
  523.     $ansi_kd = "\033[B";    # Ansi cursor-down (for DEC xterm)
  524.  
  525.     @magic_seq = ($ku,$ansi_ku,$kd,$ansi_kd,$cr,$nl,"\n",
  526.           "n","N","p","P","f","F"," ","b","B");
  527.     $did_initterm = 1;
  528.   }
  529.  
  530. # Check for title format character.
  531.   $menu_top_title_attr = 0;
  532.   if (substr($menu_top_title,0,1) eq '-') {
  533.     $menu_top_title = substr($menu_top_title,1);
  534.     $menu_top_title_attr = 1;
  535.   }
  536.  
  537. # Center top title
  538.   if (length($menu_top_title) > $main'COLS) {
  539.     $menu_top_title = substr($menu_top_title,0,$main'COLS);
  540.     $menu_top_title_col = 0;
  541.   }
  542.   else {
  543.     $menu_top_title_col = int($main'COLS/2) - int(length($menu_top_title)/2);
  544.   }
  545.  
  546. # Enable "top menu" functions if first menu is a top menu.
  547.   if (($menu_is_first_one) && ($menu_is_top_one)) { $menu_top_activated = 1; }
  548.   $menu_is_first_one = 0;
  549.  
  550. # Init selection array
  551.   @menu_sel_text = ();        # Clear menu arrays
  552.   @menu_sel_action = ();
  553.   $menu_index = 0;        # Reset flags
  554.  
  555.   $first_line = 2;
  556.   $last_line = $main'LINES - 3;
  557.   $items_per_screen = $last_line - $first_line + 1;
  558.   $arrow_line = $first_line;
  559.   $menu_top_item = 0;
  560. }
  561.  
  562. #***********
  563. #  MENU_ITEM
  564. #
  565. #  Function:    Add an item to the active menu.
  566. #
  567. #  Call format:    &menu_item("What you see","test_rtn");
  568. #
  569. #  Arguments:    String presented in menu, string returned if selected
  570. #
  571. #  Returns:    Number of items currently in the menu.
  572. #***********
  573. sub main'menu_item {
  574.   local($item_text,$item_sel) = @_;
  575.   local($sel_num,$sel_str);
  576.  
  577. # Prepend selection number (if a numbered menu)
  578.   if ($menu_numbered) {
  579.     $sel_num = $menu_index + 1;
  580.     $sel_str = "  ";
  581.     if ($sel_num < 1000) { $sel_str .= " "; }
  582.     if ($sel_num < 100) { $sel_str .= " "; }
  583.     if ($sel_num < 10) { $sel_str .= " "; }
  584.     $sel_str .= "$sel_num) ";
  585.     $item_text = $sel_str.$item_text;
  586.   }
  587.  
  588. # Truncate lines that would wrap
  589.   if (length($item_text) > $main'COLS - 1) {
  590.     $item_text = substr($item_text,0,$main'COLS - 1);
  591.   }
  592.  
  593. # Load into arrays and adjust index
  594.   @menu_sel_text[$menu_index] = $item_text;
  595.   @menu_sel_action[$menu_index] = $item_sel;
  596.   $menu_index++;
  597. }
  598.  
  599. #**********
  600. #  MENU_DISPLAY 
  601. #
  602. #  Function:    Display items in menu_sel_text array, allow selection, and
  603. #        return appropriate selection-string.
  604. #
  605. #  Call format:    $sel = &menu_display("Prompt text");
  606. #
  607. #  Arguments:   Prompt text (for the bottom line of menu)
  608. #
  609. #  Returns:     Select action string (from second param on &menu_init) OR
  610. #        "%UP%" (if "u"|"U" pressed or "t"|"T" and looking for top) OR
  611. #               "%EMPTY% if nothing in menu to display
  612. #
  613. #  Notes:    1) This routine ALWAYS sets "nocbreak" and "echo" terminal 
  614. #           modes before returning.
  615. #        2) This routine exits directly (after calling the optional 
  616. #           "quit" routine) if "q"|"Q" is pressed.
  617. #**********
  618. sub main'menu_display {
  619.   ($menu_prompt,$arrow_spec,$menu_top_item) = @_;
  620.  
  621. # If looking for top menu, return with "%UP%".
  622.   if ($finding_top) {
  623.     if ($menu_is_top_one) { $finding_top = 0; } 
  624.     else { return("%UP%"); }
  625.   }
  626.  
  627. # Check for no "menu_item" calls.
  628.   $total_items = $#menu_sel_text + 1;
  629.   if ($total_items <= 0) {
  630.     &main'nocbreak;        # ALWAYS turn off "cbreak" mode
  631.     &main'echo;            # ALWAYS turn on "echo"
  632.     return("%EMPTY%");
  633.   }
  634.  
  635.   &main'cbreak;            # cbreak mode (each character available)
  636.   &main'noecho;            # Menus are always "noecho"
  637.  
  638.   if ($total_items <= $items_per_screen) { $menu_single_page = 1; }
  639.   else { $menu_single_page = 0; }
  640.  
  641.   if ($menu_prompt eq "") {
  642.     $menu_prompt = "Move w/up&down-arrows q=quit";
  643.     if (! $menu_single_page) { $menu_prompt .= " f=fwd-pg b=back-pg"; }
  644.     if (! $menu_top_activated) {
  645.       $menu_prompt .= " u=up-a-menu";
  646.     } else {
  647.       if (! $menu_is_top_one) { $menu_prompt .= " u=up-a-menu t=top-menu"; }
  648.     }
  649.   }
  650.   if (length($menu_prompt) > $main'COLS - 7) {
  651.     $menu_prompt = substr($menu_prompt,0,$main'COLS - 7);
  652.   }
  653.  
  654. # Validate/adjust paramaters.
  655.   $arrow_line = $arrow_spec + $first_line;
  656.   if ($menu_top_item + 1 > $total_items) { $menu_top_item = $total_items - 1; }
  657.   if ($arrow_line < $first_line) { $arrow_line = $first_line; }
  658.   if ($arrow_line > $last_line) { $arrow_line = $last_line; }
  659.  
  660. # Clear screen and add top title and bottom prompt
  661.   &menu_top_bot;
  662.   $move_amt = 0;
  663.   $number = 0;
  664.    
  665.   while (1) {
  666.     $number_shown = $menu_top_item + $items_per_screen;
  667.     if ($number_shown > $total_items) { $number_shown = $total_items; }
  668.     $percent = int($number_shown * 100 /$total_items);
  669.  
  670.     &menu_page;            # Display current page
  671.     &main'refresh;        # Update screen
  672.  
  673. # Collect key sequences until something we recoginize 
  674. # (or we know we don't care)
  675.     $collect = "";
  676.     $action = "";
  677.     $possible = $#magic_seq;    # Set number of possible matches 
  678.  
  679. seq_seek:
  680.     while ($possible > 0) {
  681.       $ch = &main'getch;
  682.  
  683.       if ($collect eq "") {    # Numbers/refresh allowed yet ...
  684.     if (($ch eq "r") || ($ch eq "R")) {        # Refresh
  685.       &main'clear;
  686.       &menu_top_bot;
  687.       &menu_page;
  688.       &main'refresh;
  689.       next seq_seek;
  690.     }
  691.     if (($ch eq "\177") || ($ch eq "\010")) {    # Delete/BS num-reset
  692.       $number = 0;
  693.       $arrow_line = $first_line;
  694.       &menu_page;
  695.       &main'refresh;
  696.       next seq_seek;
  697.     }
  698.     $digit_val = index("0123456789",$ch);
  699.     if ($digit_val >= 0) {                # It IS a number ...
  700.       $number = $number * 10 + $digit_val;
  701.       if ($number >= $menu_top_item + 1) { 
  702.         if ($number <= $menu_bot_item + 1) {
  703.           $arrow_line = $number - $menu_top_item + $first_line - 1;
  704.         } else {
  705.           &bell;
  706.           $number = 0;
  707.           $arrow_line = $first_line;
  708.         }
  709.         &menu_page;
  710.         &main'refresh;
  711.       }
  712.       next seq_seek;
  713.     }
  714.       }
  715.  
  716.       $collect = $collect.$ch;
  717.  
  718.       if (($collect eq "Q") || ($collect eq "q")) {
  719.         &main'clear;
  720.     &main'move(0,0);
  721.     &main'addstr("Do you really want to quit? y");
  722.     &main'move(0,28);
  723.     &main'refresh;
  724.     $ch = &main'getch;
  725.     if (($ch eq $cr) || ($ch eq $nl) || ($ch eq "\n")) { $ch = "y"; }
  726.     $ch =~ tr/A-Z/a-z/;
  727.     if ($ch eq "y") {
  728.       if ($menu_exit_routine ne "") { &$menu_exit_routine; }
  729.       &menu_return_prep;
  730.       exit(0);
  731.     }
  732.     &menu_top_bot;        # Re-display current page
  733.     &menu_page;
  734.     &main'refresh;
  735.     $collect = "";
  736.       }
  737.       if (($collect eq "U") || ($collect eq "u")) {
  738.     &menu_return_prep;
  739.     $finding_top = 0;
  740.     return("%UP%");
  741.       }
  742.       if (($collect eq "T") || ($collect eq "t")) {
  743.         if (($menu_top_activated) && (! $menu_is_top_one)) {
  744.       &menu_return_prep;
  745.       $finding_top = 1;
  746.       return("%UP%");
  747.     }
  748.       }
  749.       $i = 0;
  750.       $possible = 0;
  751. try:
  752.       while ($i <= $#magic_seq) {
  753.         if (length($collect) > length($magic_seq[$i])) {
  754.       $i++;
  755.       next try;
  756.         }
  757.     if (substr($magic_seq[$i],0,length($collect)) eq $collect) {
  758.           $possible++;
  759.       if ($collect eq $magic_seq[$i]) {
  760.             $action = $magic_seq[$i];
  761.             last seq_seek;
  762.           }
  763.         }
  764.         $i++;
  765.       } # end while
  766.     }
  767.  
  768. #  Perform action based on keystroke(s) received
  769.     $move_amt = 0;
  770.     if ($action ne "") {
  771.       $last_arrow_line = $arrow_line;
  772.       if (($action eq $kd) || ($action eq $ansi_kd)) {        # down-arrow
  773.         $number = 0;
  774.         if ($arrow_line < $max_sel_line) { $arrow_line++; }
  775.         else {
  776.       if ($arrow_line == $last_line) { $move_amt = 1; }
  777.         }
  778.       }
  779.       elsif (($action eq $ku) || ($action eq $ansi_ku)) {    # up-arrow
  780.         $number = 0;
  781.         if ($arrow_line > $min_sel_line) { $arrow_line--; }
  782.         else { $move_amt = -1; }
  783.       }
  784.       elsif (($action eq "n") || ($action eq "N") ||     # next/forward
  785.          ($action eq "f") || ($action eq "F") || ($action eq " ")) {
  786.         $number = 0;
  787.     $move_amt = $items_per_screen;
  788.       }
  789.       elsif (($action eq "p") || ($action eq "P") ||    # previous/backward
  790.          ($action eq "b") || ($action eq "B")) {
  791.         $number = 0;
  792.     $move_amt = -$items_per_screen;
  793.       }
  794.       elsif (($action eq $cr) || ($action eq $nl) || 
  795.          ($action eq "\n")) {            # select
  796.     if ($number) { $item = $number - 1; }
  797.     else { $item = $menu_top_item + $arrow_line - $first_line; }
  798.     if (($item < $menu_top_item) || ($item > $menu_bot_item)) {
  799.       &bell;
  800.       $number = 0;
  801.     }
  802.     else {
  803.       &menu_return_prep;
  804.           if ($#_ > 0) { @_[1] = $arrow_line - $first_line; }
  805.           if ($#_ > 0) { @_[2] = $menu_top_item; }
  806.       return(@menu_sel_action[$item]);
  807.     }
  808.       }
  809.  
  810. # Check for paging of the menu text
  811.       if ($move_amt != 0) {
  812.     if ($move_amt < 0) { # Move backward
  813.       $menu_top_item = $menu_top_item + $move_amt;
  814.       if ($menu_top_item < 0) { $menu_top_item = 0; }
  815.     }
  816.     else { # Move forward
  817.       if ($menu_top_item + $move_amt < $total_items) {
  818.         $menu_top_item = $menu_top_item + $move_amt;
  819.       }
  820.     } 
  821.       }
  822.  
  823. # Erase the last selection arrow
  824.       if ($menu_numbered) {
  825.     &main'move($last_arrow_line,0);
  826.     &main'addstr("  ");
  827.       }
  828.     }
  829.   }
  830. }
  831.  
  832. #**********
  833. #  MENU_TOP_BOT -- Display top and bottom lines of current menu
  834. #**********
  835. sub menu_top_bot {
  836.   &main'clear;
  837.   &main'move(0,$menu_top_title_col);
  838.   if ($menu_top_title_attr == 0) { &main'standout; }
  839.   &main'addstr($menu_top_title);
  840.   if ($menu_top_title_attr == 0) { &main'standend; }
  841.   &main'move($last_line+2,7);
  842.   &main'addstr($menu_prompt);
  843. }
  844.  
  845. #**********
  846. #  MENU_PAGE -- Display one page of menu selection items.
  847. #**********
  848. sub menu_page {
  849.  
  850. # Update percentage on bottom line
  851.   &main'move($last_line+2,0);
  852.   &main'standout;
  853.   if ($menu_single_page) { &main'addstr("(All) "); }
  854.   else { &main'addstr(sprintf("\(%3d%%\)",$percent)); }
  855.   &main'standend;
  856.  
  857. # Display current page of menu
  858.   $item = $menu_top_item;
  859.   $menu_bot_item = $menu_top_item;
  860.   $curr_line = $first_line;
  861.   $min_sel_line = $first_line;
  862.   $max_sel_line = $first_line;
  863.   while ($curr_line <= $last_line) {
  864.     &main'move($curr_line,0);
  865.     &main'clrtoeol;
  866.     $sel_num = $item + 1;
  867.     if ($item < $total_items) {
  868.       &main'addstr("$menu_sel_text[$item]");
  869.       $max_sel_line = $curr_line;
  870.       $menu_bot_item = $item;
  871.     }
  872.     $item++;
  873.     $curr_line++;
  874.   }
  875.  
  876. #  Position the selection arrow on the screen (if numbered menu)
  877.   if ($arrow_line > $max_sel_line) { $arrow_line = $max_sel_line; }
  878.   &main'move($arrow_line,0);
  879.   if ($menu_numbered) { &main'addstr("->"); }
  880. }
  881.  
  882. sub menu_return_prep {
  883.   if (!$curses_application) { &main'endwin; }
  884.   &main'nocbreak;
  885.   &main'echo; 
  886.   &main'clear;
  887.   &main'refresh; 
  888. }
  889.  
  890. sub defbell {
  891.   eval q#
  892.     sub bell { print "\007"; }
  893.   #;
  894. }
  895.  
  896. 1;
  897. \End\Of\Shar\
  898. else
  899.   echo "will not over write ./menu.pl"
  900. fi
  901. if [ `wc -c ./menu.pl | awk '{printf $1}'` -ne 13453 ]
  902. then
  903. echo `wc -c ./menu.pl | awk '{print "Got " $1 ", Expected " 13453}'`
  904. fi
  905. if `test ! -s ./ultpatch`
  906. then
  907. echo "writing ./ultpatch"
  908. cat > ./ultpatch << '\End\Of\Shar\'
  909. *** bsdcurses.mus.dist    Tue Jun  9 11:02:56 1992
  910. --- bsdcurses.mus    Tue Jun  9 11:04:40 1992
  911. ***************
  912. *** 54,60 ****
  913.       US_erase,
  914.       US_werase,
  915.       US_flushok,
  916. -     US_idlok,
  917.       US_insch,
  918.       US_winsch,
  919.       US_insertln,
  920. --- 54,59 ----
  921. ***************
  922. *** 83,101 ****
  923.       US_noraw,
  924.       US_scanw,
  925.       US_wscanw,
  926. -     US_baudrate,
  927.       US_delwin,
  928.       US_endwin,
  929. -     US_erasechar,
  930.       US_getcap,
  931.       US_getyx,
  932.       US_inch,
  933.       US_winch,
  934.       US_initscr,
  935. -     US_killchar,
  936.       US_leaveok,
  937.       US_longname,
  938. -     US_fullname,
  939.       US_mvwin,
  940.       US_newwin,
  941.       US_nl,
  942. --- 82,96 ----
  943. ***************
  944. *** 102,109 ****
  945.       US_nonl,
  946.       US_scrollok,
  947.       US_subwin,
  948. -     US_touchline,
  949. -     US_touchoverlap,
  950.       US_touchwin,
  951.       US_unctrl,
  952.       US_gettmode,
  953. --- 97,102 ----
  954. ***************
  955. *** 161,167 ****
  956.       make_usub("erase",        US_erase,    usersub, filename);
  957.       make_usub("werase",        US_werase,    usersub, filename);
  958.       make_usub("flushok",    US_flushok,    usersub, filename);
  959. -     make_usub("idlok",        US_idlok,    usersub, filename);
  960.       make_usub("insch",        US_insch,    usersub, filename);
  961.       make_usub("winsch",        US_winsch,    usersub, filename);
  962.       make_usub("insertln",    US_insertln,    usersub, filename);
  963. --- 154,159 ----
  964. ***************
  965. *** 190,208 ****
  966.       make_usub("noraw",        US_noraw,    usersub, filename);
  967.       make_usub("scanw",        US_scanw,    usersub, filename);
  968.       make_usub("wscanw",        US_wscanw,    usersub, filename);
  969. -     make_usub("baudrate",    US_baudrate,    usersub, filename);
  970.       make_usub("delwin",        US_delwin,    usersub, filename);
  971.       make_usub("endwin",        US_endwin,    usersub, filename);
  972. -     make_usub("erasechar",    US_erasechar,    usersub, filename);
  973.       make_usub("getcap",        US_getcap,    usersub, filename);
  974.       make_usub("getyx",        US_getyx,    usersub, filename);
  975.       make_usub("inch",        US_inch,    usersub, filename);
  976.       make_usub("winch",        US_winch,    usersub, filename);
  977.       make_usub("initscr",    US_initscr,    usersub, filename);
  978. -     make_usub("killchar",    US_killchar,    usersub, filename);
  979.       make_usub("leaveok",    US_leaveok,    usersub, filename);
  980.       make_usub("longname",    US_longname,    usersub, filename);
  981. -     make_usub("fullname",    US_fullname,    usersub, filename);
  982.       make_usub("mvwin",        US_mvwin,    usersub, filename);
  983.       make_usub("newwin",        US_newwin,    usersub, filename);
  984.       make_usub("nl",        US_nl,        usersub, filename);
  985. --- 182,196 ----
  986. ***************
  987. *** 209,216 ****
  988.       make_usub("nonl",        US_nonl,    usersub, filename);
  989.       make_usub("scrollok",    US_scrollok,    usersub, filename);
  990.       make_usub("subwin",        US_subwin,    usersub, filename);
  991. -     make_usub("touchline",    US_touchline,    usersub, filename);
  992. -     make_usub("touchoverlap",    US_touchoverlap,usersub, filename);
  993.       make_usub("touchwin",    US_touchwin,    usersub, filename);
  994.       make_usub("unctrl",        US_unctrl,    usersub, filename);
  995.       make_usub("gettmode",    US_gettmode,    usersub, filename);
  996. --- 197,202 ----
  997. ***************
  998. *** 312,322 ****
  999.   I    bool        boolf
  1000.   END
  1001.   
  1002. - CASE int idlok
  1003. - I    WINDOW*        win
  1004. - I    bool        boolf
  1005. - END
  1006.   CASE int insch
  1007.   I    char        c
  1008.   END
  1009. --- 298,303 ----
  1010. ***************
  1011. *** 466,474 ****
  1012.   CASE int noraw
  1013.   END
  1014.   
  1015. - CASE int baudrate
  1016. - END
  1017.   CASE int delwin
  1018.   I    WINDOW*        win
  1019.   END
  1020. --- 447,452 ----
  1021. ***************
  1022. *** 476,484 ****
  1023.   CASE int endwin
  1024.   END
  1025.   
  1026. - CASE int erasechar
  1027. - END
  1028.       case US_getcap:
  1029.       if (items != 1)
  1030.           fatal("Usage: &getcap($str)");
  1031. --- 454,459 ----
  1032. ***************
  1033. *** 522,530 ****
  1034.   CASE WINDOW* initscr
  1035.   END
  1036.   
  1037. - CASE int killchar
  1038. - END
  1039.   CASE int leaveok
  1040.   I    WINDOW*        win
  1041.   I    bool        boolf
  1042. --- 497,502 ----
  1043. ***************
  1044. *** 535,545 ****
  1045.   IO    char*        name
  1046.   END
  1047.   
  1048. - CASE int fullname
  1049. - I    char*        termbuf
  1050. - IO    char*        name
  1051. - END
  1052.   CASE int mvwin
  1053.   I    WINDOW*        win
  1054.   I    int        y
  1055. --- 507,512 ----
  1056. ***************
  1057. *** 570,587 ****
  1058.   I    int        cols
  1059.   I    int        begin_y
  1060.   I    int        begin_x
  1061. - END
  1062. - CASE int touchline
  1063. - I    WINDOW*        win
  1064. - I    int        y
  1065. - I    int        startx
  1066. - I    int        endx
  1067. - END
  1068. - CASE int touchoverlap
  1069. - I    WINDOW*        win1
  1070. - I    WINDOW*        win2
  1071.   END
  1072.   
  1073.   CASE int touchwin
  1074. --- 537,542 ----
  1075. \End\Of\Shar\
  1076. else
  1077.   echo "will not over write ./ultpatch"
  1078. fi
  1079. if [ `wc -c ./ultpatch | awk '{printf $1}'` -ne 4098 ]
  1080. then
  1081. echo `wc -c ./ultpatch | awk '{print "Got " $1 ", Expected " 4098}'`
  1082. fi
  1083. if `test ! -s ./RELEASE_NOTES`
  1084. then
  1085. echo "writing ./RELEASE_NOTES"
  1086. cat > ./RELEASE_NOTES << '\End\Of\Shar\'
  1087.  
  1088. Changes between menu.pl version 1.1 and version 1.3:
  1089.  
  1090. - Fixed bug in the "numeric direct entry code".  Once a number was entered 
  1091.   it was not cleared if an arrow key was used to move the pointer off the
  1092.   selection.
  1093. - Added the "top menu" feature.  Allows for a "t" ("top") menu hot-key to
  1094.   move to the top (first displayed) menu.
  1095. - Added the "latched" menu feature.  Allows calls to "menu_display" to have
  1096.   two additional parameters that remember the screen/arrow location upon
  1097.   return from the call.  When recalling "menu_display" (with the same
  1098.   parameters) the menu will be restored to the original location/selection.
  1099.  
  1100. Changes between menu.pl version .9 (beta) and version 1.1:
  1101.  
  1102. - Declaration of "curses_application" fixed ("main`" prepended).
  1103. - Cleanup of "cbreak" and "echo" handling.  Calls to "menu_display"
  1104.   always return with "echo" and "cbreak" set.
  1105. - Return key now functions on systems that do not have termcap entries
  1106.   for either a "newline" or "return" key.
  1107. - "menu_display" will return "%EMPTY%" if no calls to "menu_item" were
  1108.   done between a "menu_init" call and a "menu_display" call.
  1109. - Hitting the "space bar" is now the same as "f" or "n" for forward movement
  1110.   within a multi-page selection menu.
  1111. - The title strings in "menu_init" calls can now begin with a "-" to suppress
  1112.   the "standout" attribute (normally a bold or reverse-video rendition).
  1113. - menu_display will no longer return "%QUIT%" - returns "%UP" instead.  The
  1114.   menu routines process a "q" (for "quit") locally and will exit from
  1115.   there (after the user responds to a "Do you really want to quit?" prompt).
  1116. - Direct number entry for selecting entries "pops" the arrow to the 
  1117.   "best fit" selection on the screen, indicating what selection will be 
  1118.   made when return is hit.
  1119. - The "ezview" demo now displays the correct modification date on its file
  1120.   display.
  1121. \End\Of\Shar\
  1122. else
  1123.   echo "will not over write ./RELEASE_NOTES"
  1124. fi
  1125. if [ `wc -c ./RELEASE_NOTES | awk '{printf $1}'` -ne 1858 ]
  1126. then
  1127. echo `wc -c ./RELEASE_NOTES | awk '{print "Got " $1 ", Expected " 1858}'`
  1128. fi
  1129. if `test ! -s ./demotop`
  1130. then
  1131. echo "writing ./demotop"
  1132. cat > ./demotop << '\End\Of\Shar\'
  1133. #!../bin/curseperl
  1134. #
  1135. # demo --  Perl menu demo - Usage of "top menu" functions.
  1136. #
  1137. # Note:    Requires curseperl.
  1138. #          Demonstrates technique to use "top" menu feature.
  1139. #
  1140. # Author:  Steven L. Kunz
  1141. #          Networking & Communications
  1142. #          Iowa State University Computation Center
  1143. #          Ames, IA  50011
  1144. #          Email: skunz@iastate.edu
  1145. #
  1146. # Date:    Dec, 1992
  1147. #
  1148.  
  1149. require "./menu.pl";
  1150.  
  1151. while (1) {
  1152.   &menu_init(1,"Top Menu",1);
  1153.   &menu_item("Exit this demo","exit");
  1154.   &menu_item("Animal","animal");
  1155.   &menu_item("Mineral","mineral");
  1156.   &menu_item("Vegetable","vegetable");
  1157.  
  1158. # Get selection
  1159.   $sel= &menu_display("");
  1160.  
  1161. # Process selection (ignore "up" at top level)
  1162.   if ($sel ne "%UP%") {
  1163.     if ($sel eq "exit") { exit; }
  1164.     if ($sel eq "animal") { &animal; }
  1165.     elsif ($sel eq "mineral") { &mineral; }
  1166.     elsif ($sel eq "vegetable") { &vegetable; }
  1167.   }
  1168. }
  1169.  
  1170. sub animal {
  1171.   while (1) {
  1172.     &menu_init(1,"Lower animal menu");
  1173.     &menu_item("Dog","dog");
  1174.     &menu_item("Cat","cat");
  1175.     $sel = &menu_display("");
  1176.     if ($sel eq "%UP%") { return; } # "up" or "top"
  1177.     if ($sel eq "dog") { &dog; }
  1178.     if ($sel eq "cat") { &cat; }
  1179.   }
  1180. }
  1181.  
  1182. sub dog {
  1183.   while (1) {
  1184.     &menu_init(1,"Lower dog menu");
  1185.     &menu_item("Lab","");
  1186.     &menu_item("Collie","");
  1187.     $sel = &menu_display("");
  1188.     if ($sel eq "%UP%") { return; } # "up" or "top"
  1189.   }
  1190. }
  1191.  
  1192. sub cat {
  1193.   while (1) {
  1194.     &menu_init(1,"Lower cat menu");
  1195.     &menu_item("Tabby","");
  1196.     &menu_item("Siamese","");
  1197.     $sel = &menu_display("");
  1198.     if ($sel eq "%UP%") { return; } # "up" or "top"
  1199.   }
  1200. }
  1201.  
  1202. sub mineral {
  1203.   while (1) {
  1204.     &menu_init(1,"Lower mineral menu");
  1205.     &menu_item("Shale","");
  1206.     &menu_item("Limestone","");
  1207.     $sel = &menu_display("");
  1208.     if ($sel eq "%UP%") { return; } # "up" or "top"
  1209.   }
  1210. }
  1211.  
  1212. sub vegetable {
  1213.   while (1) {
  1214.     &menu_init(1,"Lower vegetable menu");
  1215.     &menu_item("Carrot","");
  1216.     &menu_item("Pea","");
  1217.     $sel = &menu_display("");
  1218.     if ($sel eq "%UP%") { return; } # "up" or "top"
  1219.   }
  1220. }
  1221. \End\Of\Shar\
  1222. else
  1223.   echo "will not over write ./demotop"
  1224. fi
  1225. if [ `wc -c ./demotop | awk '{printf $1}'` -ne 2002 ]
  1226. then
  1227. echo `wc -c ./demotop | awk '{print "Got " $1 ", Expected " 2002}'`
  1228. fi
  1229. if `test ! -s ./MENU_DOC`
  1230. then
  1231. echo "writing ./MENU_DOC"
  1232. cat > ./MENU_DOC << '\End\Of\Shar\'
  1233.                                    menu.pl
  1234.                                  Perl Menus
  1235.                                  Version 1.3
  1236.                               December 18, 1992
  1237.  
  1238.                                Steven L. Kunz
  1239.                            Networked Applications
  1240.                   Iowa State University Computation Center
  1241.                             Iowa State University
  1242.                                  Ames,  Iowa
  1243.                   
  1244. --------
  1245. Overview
  1246. --------
  1247.  
  1248.   The "menu.pl" package is a perl package (built into your perl program
  1249.   with a "require menu.pl" command) that automates curses-based full screen
  1250.   menus.  Using three simple calls, any number of items may be selected from a
  1251.   single or multiple-page menu by moving an arrow to the desired item or
  1252.   directly entering the selection number displayed on the screen.  Paging
  1253.   through multiple-page menus is handled automatically.  Menu titles and 
  1254.   prompts are supported. 
  1255.  
  1256.   The "menu.pl" package uses curses interface routine calls supplied by the
  1257.   "curseperl" package.  The "curseperl" package is distributed with the normal
  1258.   perl distribution in the "usub" directory.  The "curseperl" binary is a
  1259.   complete perl interpreter with the addition of many "curses" routines
  1260.   dealing with screen manipulation (cursor positioning, display of text at the
  1261.   current cursor location, etc).  Applications using "menu.pl" must be
  1262.   constructed to use "curseperl" instead of "perl". 
  1263.  
  1264.   Most applications using perl menus will use the following three calls
  1265.   (with the "menu_item" routine used multiple times to provide the menu
  1266.   selections) as follows:
  1267.  
  1268.      #!/usr/bin/curseperl
  1269.      ...
  1270.      &menu_init(1,"Select an Animal"); # Init menu
  1271.  
  1272.      &menu_item("Collie","dog"); # Add item
  1273.      &menu_item("Shetland","pony"); # Add item
  1274.      &menu_item("Persian","cat"); # Add last item
  1275.  
  1276.      $sel = &menu_display("Which animal?"); # Get user selection
  1277.  
  1278.      if ($sel eq "dog") { ... }
  1279.      ...
  1280.  
  1281.   When this code is executed, only the call to "menu_display" will actually 
  1282.   cause the constructed menu to be displayed to the user for selection.
  1283.   The title is centered and displayed at the top of the screen in reverse
  1284.   video.  The selection items are automatically numbered and presented in
  1285.   the order they were added.  The prompt is displayed at the bottom of the
  1286.   screen preceded by an indication of how many of the items in the menu
  1287.   are presented on the current screen ("All" or some percentage).  In the 
  1288.   above example, the menu would look like:
  1289.  
  1290.                               Select an Animal
  1291.  
  1292.      -> 1) Collie
  1293.         2) Shetland
  1294.         3) Persian
  1295.  
  1296.      (All)  Which animal?
  1297.  
  1298.   Only one menu may be active at a time.  In applications with "layers" of
  1299.   menus, only the "current layer" menu is maintained in memory.  As you use
  1300.   the "up" function to "pop up" to a previous menu, your application must
  1301.   return to a subroutine (or upper program layer) that reconstructs the menu
  1302.   for that layer of the application and displays it.  Since the lower layer
  1303.   used a "menu_init" to construct that menu, the "upper layer" must reconstruct
  1304.   the entire menu appropriate at that level.  Support is provided (with
  1305.   proper programming of the application) to go directly to the "top" (first)
  1306.   menu and to remember the selection position in a previous menu. 
  1307.  
  1308.  
  1309. -------------------------------------
  1310. Initializing a new menu - "menu_init"
  1311. -------------------------------------
  1312.  
  1313.   Syntax:    &menu_init(num_flag,"title string")
  1314.  
  1315.   The "menu_init" call resets the menu array and indexes.  It must be called
  1316.   to reset/clear any old menu.  The first parameter is a boolean flag
  1317.   indicating whether or not the menu should be numbered and have a selection
  1318.   arrow "->" provided (a non-zero value indicates a numbered menu).  By
  1319.   default, the "title string" is centered at the top of the screen and
  1320.   presented in "standout" rendition (usually reverse video or bold).  If the
  1321.   first character of the title is a dash ("-") then the title will be
  1322.   presented in "normal" rendition ("standout" will be suppressed).  Title
  1323.   text that exceeds the width of the screen is automatically truncated on
  1324.   the right to fit the available width. 
  1325.  
  1326.  
  1327. ------------------------------------
  1328. Adding items to a menu - "menu_item"
  1329. ------------------------------------
  1330.  
  1331.   Syntax:    &menu_item("Selection text","action_text");
  1332.  
  1333.   The "menu_item" call provides selection text (what the user sees on the
  1334.   screen) and "action_text" (not seen - but returned if that item is
  1335.   selected).  There is no practical limit (other than memory or maximum
  1336.   array index size) on the number of items in a menu.  The items are
  1337.   presented in the order you add them and the top (first) item is always
  1338.   the default (except when using the "latched" menu support outlined in
  1339.   a later section).  Selection text that exceeds the width of the terminal
  1340.   is automatically truncated on the right by the "menu_item" call.  The 
  1341.   "action_text" may be a null string (in which case a null string is 
  1342.   returned upon selection).
  1343.  
  1344.  
  1345. -------------------------------------------------
  1346. Displaying/selecting from a menu - "menu_display"
  1347. -------------------------------------------------
  1348.  
  1349.   Syntax:    $sel_var = &menu_display("Prompt text");
  1350.  
  1351.   The "menu_display" call is the only call that actually writes data on the
  1352.   screen.  When it returns you have one of the following strings:
  1353.  
  1354.     "%UP%"          -- indicating the user did not select anything but 
  1355.                        pressed "u" (or possibly "t" - for "top menu", see
  1356.                        below) to exit the menu.
  1357.  
  1358.     "%EMPTY%"       -- indicating no calls were made to "menu_item" since 
  1359.                        the last "menu_init" call.
  1360.  
  1361.     "<action-text>" -- one of the selection-action strings given on a 
  1362.                        "menu_item" call.  
  1363.  
  1364.   You can either provide your own prompt as a call parameter to
  1365.   "menu_display"  or you can provide a null string (&menu_display("")) in
  1366.   which an automatic prompt is provided.  All paging functions are handled
  1367.   within the call to "menu_display" automatically.  
  1368.  
  1369.   Support is provided for just simply typing the selection number of the
  1370.   item on the screen - you do not have to move the selection arrow to the item
  1371.   if you prefer to type the number (followed by "return").  The arrow ("->")
  1372.   displayed on the screen will automatically jump to the selection that is the
  1373.   "best fit" for what is typed so far.  For example, if items 1-20 are
  1374.   currently on the screen, pressing a "2" will cause the arrow to jump to the
  1375.   "2)" selection.  Typing "0" (to indicate "20") causes the arrow to next jump
  1376.   to the "20)" selection.  A "return" key actually activates the selection.  A
  1377.   "delete" or "backspace" key (or any cursor-movement key) clears the "direct
  1378.   entry" selection process at any time before "return" is pressed.  
  1379.  
  1380.   One final note.  The call to "menu_display" will ALWAYS turn back on echo
  1381.   - so if you really want it off you will have to call "noecho" again after 
  1382.   each call to "menu_display". 
  1383.  
  1384.  
  1385. --------------------
  1386. "Top" Menu Support
  1387. (New in version 1.3)
  1388. --------------------
  1389.  
  1390.   There is limited support for "top" menus.  By following a careful program
  1391.   structure you can allow the user to type a "t" at any menu display and have
  1392.   the next menu presented be the "top" (first) menu presented.  This provides
  1393.   a convenient means for the user to jump to the top of a multiple-level menu
  1394.   structure from several menu-levels down. 
  1395.  
  1396.   Since there is only one menu active at a time, pressing "t" to indicate
  1397.   the "top" menu merely generates a "%UP%" return from the current menu
  1398.   (refer to the "menu_display" call).  However, top's "%UP%" return is
  1399.   different from a normal "u" up-action in that an internal flag is set so
  1400.   that all subsequent calls to ANY "menu_display" immediately return with an
  1401.   "%UP%" selection.  This action continues until a menu is displayed that was
  1402.   initialized with a special flag in the "menu_init" call that indicates it is
  1403.   the "top" menu.  Once a "menu_display" is called for a menu that has this
  1404.   special "menu_init" call, the "automatic %UP% return" stops and the "top
  1405.   menu" is displayed.  This special "top menu" is initialized as follows:  
  1406.  
  1407.       &menu_init(num_flag,"title string",1); # A "top" menu_init call
  1408.  
  1409.   The third parameter (a "1") indicates this is the "top" menu.
  1410.  
  1411.   The "top" menu support requires special care in programming.  With
  1412.   careless programming you could enter a loop if a "t" was pressed and the
  1413.   curseperl program provided no "top menu_init" call.  To provide some level
  1414.   of protection, the "t" menu hot-key and "top" support is disabled
  1415.   automatically UNLESS the FIRST "menu_init" call is also a "top menu_init"
  1416.   call (indicating the software was programmed with "top" menus in mind). 
  1417.  
  1418.   The "demotop" program distributed with this release of "menu.pl" provides
  1419.   an example of correct usage of the "top menu" features.   
  1420.  
  1421.  
  1422. --------------------
  1423. "Latched" Menus
  1424. (New in version 1.3)
  1425. --------------------
  1426.  
  1427. "Latched" menu support offers the ability to remember where you were in a
  1428. menu when it is re-displayed later.  This is often useful in traversing
  1429. a menu-tree down and them returning to previous menus (and selection
  1430. locations) when "popping back up" the tree (with the "up" hot-key).  The
  1431. only action necessary to remember position is the addition to two parameters
  1432. on the "menu_display" call as follows:
  1433.  
  1434.      $sel_var = &menu_display("Prompt text",$arrow_loc_var,$top_item_var);
  1435.  
  1436. These two values indicate the location of the arrow line on the menu screen
  1437. and the index number of the top "menu_item" on the menu screen.  If you want
  1438. the first item the first time, these values should both be initialized to
  1439. zero (first item on the first page).  This will generate the same action as
  1440. if they were not specified - the default "non-latched" call.  These two
  1441. optional parameters also are used to RETURN the value of the top item on
  1442. a menu-page and arrow location AFTER the user selected something (and the
  1443. "menu_display" routine returns).  If you do not modify the two parameters,
  1444. rebuild the menu the same way, and call "menu_display" supplying the returned
  1445. values, the menu will be displayed in the original "selection" location.
  1446.  
  1447. By letting "menu_display" store selection locations before moving to a lower
  1448. level in your "menu-tree" (via a subroutine call to another menu-generator),
  1449. a return from the lower level can regenerate any given levels menu and
  1450. reposition the selection location automatically.  Make sure you store your
  1451. "latch" variables in "local" storage (one set for each menu-generator
  1452. routine that has a "menu_display" call).
  1453.  
  1454. One final note - the "menu_display" routine will check and automatically
  1455. adjust the values to meet current menu limits.  For example, if your menus
  1456. are "dynamic" and items "disappeared" (making your last latch position off
  1457. the end of the reconstructed menu), the "menu_display" routine will adjust
  1458. to point to the the last item in the menu (adjusting the "top item" as
  1459. needed). 
  1460.  
  1461.  
  1462. ------------------------
  1463. Other "menu.pl" Routines
  1464. ------------------------
  1465.  
  1466.   Routine: menu_curses_application
  1467.  
  1468.   Syntax:  &menu_curses_application;
  1469.  
  1470.   It is assumed that the application calling the menu routines is not a
  1471.   "curseperl" application (i.e. it is a "stock" perl script except for calls
  1472.   to "menu.pl" routines).  However, if you are writing an "all-curses"
  1473.   application (calling curses functions from your routines) you should call
  1474.   "menu_curses_application" FIRST (once).  This sets a flag so that the
  1475.   "initscr" and "endwin" calls are NOT done by the menu.pl package calls (and
  1476.   assumes you will do them).  
  1477.  
  1478.   Routine: menu_quit_routine
  1479.  
  1480.   Syntax:  &menu_quit_routine("routine_name");
  1481.  
  1482.   The menu routines will process a "q" for "quit" locally.  In other words,
  1483.   if the user presses "q" while a menu is displayed (and responds to the
  1484.   "Do you really want to quit?" prompt with a "y") the perl program will
  1485.   immediately exit.  However, support is provided for a "user" exit that
  1486.   will be called just before dropping out the program (to perform any
  1487.   "cleanup" duties).  Calling "&menu_quit_routine("rtn_name");" will set
  1488.   the exit routine.
  1489.    
  1490.  
  1491. \End\Of\Shar\
  1492. else
  1493.   echo "will not over write ./MENU_DOC"
  1494. fi
  1495. if [ `wc -c ./MENU_DOC | awk '{printf $1}'` -ne 12238 ]
  1496. then
  1497. echo `wc -c ./MENU_DOC | awk '{print "Got " $1 ", Expected " 12238}'`
  1498. fi
  1499. echo "Finished archive 1 of 1"
  1500. exit
  1501. -- 
  1502. Steven L. Kunz
  1503. Networked Applications | Usenet News Admin.
  1504. Iowa State University Computation Center, Iowa State University, Ames  IA
  1505. INET: skunz@iastate.edu     BITNET: gr.slk@isumvs.bitnet
  1506.