NAME

Term::Menus - Create Powerful Terminal, Console and CMD Enviroment Menus

SYNOPSIS

use Term::Menus;

see METHODS section below

DESCRIPTION

Term::Menus allows you to create powerful Terminal, Console and CMD environment menus. Any perl script used in a Terminal, Console or CMD environment can now include a menu facility that includes sub-menus, forward and backward navigation, single or multiple selection capabilities, dynamic item creation and customized banners. All this power is simple to implement with a straight forward and very intuitive configuration hash structure that mirrors the actual menu architechture needed by the application. A separate configuration file is optional. Term::Menus is cross platform compatible.

Term::Menus is a stand-alone - other CPAN modules are not needed for its implementation ( so it's *easy* to install! ;-) )

Term::Menus was initially conceived and designed to work seemlessly with the perl based Network Process Automation Utility Module called Net::FullAuto (Available in CPAN :-) - however, it is not itself dependant on other Net::FullAuto components, and will work with *any* perl script/application.

Reasons to use this module are:

  • You have a list (or array) of items, and wish to present the user a simple CMD enviroment menu to pick a single item and return that item as a scalar (or simple string). Example:

    use Term::Menus;
    
    my @list=('First Item','Second Item','Third Item');
    my $banner="  Please Pick an Item:";
    my $selection=&pick(\@list,$banner);
    print "SELECTION = $selection\n";

    The user sees ==>

    Please Pick an Item:
    
       1.        First Item
       2.        Second Item
       3.        Third Item
    
    (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 2 >-<ENTER>----------------------------------

    The user sees ==>

    SELECTION = Second Item
  • You have a large list of items and need scrolling capability:

    use Term::Menus;
    
    my @list=`ls -1 /bin`;
    my $banner="   Please Pick an Item:";
    my $selection=&pick(\@list,$banner);
    print "SELECTION = $selection\n";

    The user sees ==>

    Please Pick an Item:
    
       1.        arch
       2.        ash
       3.        awk
       4.        basename
       5.        bash
       6.        cat
       7.        chgrp
       8.        chmod
       9.        chown
       10.       cp
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --<ENTER>--------------------------------------

    Please Pick an Item:
    
       11.       cpio
       12.       csh
       13.       cut
       14.       date
       15.       dd
       16.       df
       17.       echo
       18.       ed
       19.       egrep
       20.       env
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 14 >-<ENTER>----------------------------------

    The user sees ==>

    SELECTION = date
  • You need to select multiple items and return the selected list:

    use Term::Menus;
    
    my %Menu_1=(
    
       Item_1 => {
    
          Text    => "/bin Utility - ]Convey[",
          Convey  => [ `ls -1 /bin` ],
    
       },
    
       Select => 'Many',
       Banner => "\n   Choose a /bin Utility :"
    );
    
    my @selections=&Menu(\%Menu_1);
    print "SELECTIONS = @selections\n";

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 3 >-<ENTER>----------------------------------

    --< 7 >-<ENTER>----------------------------------

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
    *  3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
    *  7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< f >-<ENTER>----------------------------------

    The user sees ==>

    SELECTIONS = /bin Utility - awk /bin Utility - chgrp
  • You need sub-menus:

    use Term::Menus;
    
    my %Menu_2=(
    
       Name   => 'Menu_2',
       Item_1 => {
    
          Text   => "]Previous[ is a ]Convey[ Utility",
          Convey => [ 'Good','Bad' ]
    
       },
    
       Select => 'One',
       Banner => "\n   Choose an Answer :"
    );
    
    my %Menu_1=(
    
       Name   => 'Menu_1',
       Item_1 => {
    
          Text   => "/bin/Utility - ]Convey[",
          Convey => [ `ls -1 /bin` ],
          Result => \%Menu_2,
    
       },
    
       Select => 'One',
       Banner => "\n   Choose a /bin Utility :"
    );
    
    my $selection=&Menu(\%Menu_1);
    print "\n   SELECTION=$selection\n";

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 5 >-<ENTER>----------------------------------

    Choose an Answer :
    
       1.        bash is a Good Utility
       2.        bash is a Bad Utility
    
    (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 1 >-<ENTER>----------------------------------

    The user sees ==>

    SELECTIONS = bash is a Good Utility
  • You want to use perl subroutines to create the text items and/or banner:

    use Term::Menus;
    
    sub create_items {
    
       my $previous=shift;
       my @textlines=();
       push @textlines, "$previous is a Good Utility";
       push @textlines, "$previous is a Bad Utility";
       return @textlines;
              ## return value must NOT be an array
              ## not an array reference
    
    }
    
    sub create_banner {
    
       my $previous=shift;
       return "\n   Choose an Answer for $previous :"
              ## return value MUST be a string for banner
    
    }
    
    my %Menu_2=(
    
       Name   => 'Menu_2',
       Item_1 => {
    
          Text   => "]Convey[",
          Convey => "create_items(]Previous[)",
    
       },
    
       Select => 'One',
       Banner => "create_banner(]Previous[)",
    
    );
    
    my %Menu_1=(
    
       Name   => 'Menu_1',
       Item_1 => {
    
          Text   => "/bin/Utility - ]Convey[",
          Convey => [ `ls -1 /bin` ],
          Result => \%Menu_2,
    
       },
    
       Select => 'One',
       Banner => "\n   Choose a /bin Utility :"
    );
    
    my @selection=&Menu(\%Menu_1);
    print "\n   SELECTION=@selection\n";

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 5 >-<ENTER>----------------------------------

    Choose an Answer for bash :
    
       1.        bash is a Good Utility
       2.        bash is a Bad Utility
    
    (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 1 >-<ENTER>----------------------------------

    The user sees ==>

    SELECTION = bash is a Good Utility
  • You want to use anonymous subroutines to create the text items and/or banner (see the more detailed treatment of anonymous subroutines and Term::Menus macros in a later section of this documentation):

    use Term::Menus;
    
    my $create_items = sub {
    
       my $previous=shift;
       my @textlines=();
       push @textlines, "$previous is a Good Utility";
       push @textlines, "$previous is a Bad Utility";
       return \@textlines;
              ## return value must an array reference
    
    };
    
    my $create_banner = sub {
    
       my $previous=shift;
       return "\n   Choose an Answer for ]Previous[ :"
              ## return value MUST be a string for banner
    
    };
    
    my %Menu_2=(
    
       Name   => 'Menu_2',
       Item_1 => {
    
          Text   => "]Convey[",
          Convey => $create_items->(']Previous['), # Subroutine executed
                                                   # at runtime by Perl
                                                   # and result is passed
                                                   # to Term::Menus.
    
                                                   # Do not use this argument
                                                   # construct with Result =>
                                                   # elements because only Menu
                                                   # blocks or subroutines can
                                                   # be passed. (Unless the
                                                   # return item is itself
                                                   # a Menu configuration
                                                   # block [HASH] or an
                                                   # anonymous subroutine
                                                   # [CODE])
    
       },
    
       Select => 'One',
       Banner => $create_banner, # Perl passes sub itself at runtime and
                                 # execution is carried out by Term::Menus.
    
    );
    
    my %Menu_1=(
    
       Name   => 'Menu_1',
       Item_1 => {
    
          Text   => "/bin/Utility - ]Convey[",
          Convey => [ `ls -1 /bin` ],
          Result => \%Menu_2,
    
       },
    
       Select => 'One',
       Banner => "\n   Choose a /bin Utility :"
    );
    
    my @selection=&Menu(\%Menu_1);
    print "\n   SELECTION=@selection\n";

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 5 >-<ENTER>----------------------------------

    Choose an Answer for bash :
    
       1.        bash is a Good Utility
       2.        bash is a Bad Utility
    
    (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 1 >-<ENTER>----------------------------------

    The user sees ==>

    SELECTION = bash is a Good Utility

Usage questions should be directed to the Usenet newsgroup comp.lang.perl.modules.

Contact me, Brian Kelly <Brian.Kelly@fullautosoftware.net>, if you find any bugs or have suggestions for improvements.

What To Know Before Using

  • There are two methods available with Term::Menus - &pick() and &Menu(). &Menu() uses &pick() - you can get the same results using only &Menu(). However, if you need to simply pick one item from a single list - use &pick(). The syntax is simpler, and you'll write less code. ;-)

  • You'll need to be running at least Perl version 5.002 to use this module.

METHODS

pick - create a simple menu
$pick = &pick ($list|\@list|['list',...],[$Banner]);

Where $list is a variable containing an array or list reference. This argument can also be a escaped array (sending a reference) or an anonymous array (which also sends a reference).

$Banner is an optional argument sending a customized Banner to top the simple menu - giving instructions, descriptions, etc. The default is "Please Pick an Item:"

$pick  = &Menu ($list|\@list|['list',...],[$Banner]);

Where $pick is a variable containing an array or list reference of the pick or picks.

@picks = &Menu ($Menu_1|\%Menu_1|{ Name => 'Menu_1' });

Where $Menu_1 is a hash reference to the top level Menu Configuration Hash Structure.

    These are the building blocks of the overall Menu architecture. Each hash structure represents a menu screen. A single menu layer, has only one hash structure defining it. A menu with a single sub-menu will have two hash structures. The menus connect via the Result element of an Item - Item_1 - hash structure in parent menu %Menu_1:

    my %Menu_2=(
    
       Name   => 'Menu_2',
       Item_1 => {
    
          Text   => "]Previous[ is a ]Convey[ Utility",
          Convey => [ 'Good','Bad' ]
       },
    
       Select => 'One',
       Banner => "\n   Choose an Answer :"
    );
    
    my %Menu_1=(
    
       Name   => 'Menu_1',
       Item_1 => {
    
          Text   => "/bin/Utility - ]Convey[",
          Convey => [ `ls -1 /bin` ],
          Result => \%Menu_2,
    
       },
    
       Select => 'One',
       Banner => "\n   Choose a /bin Utility :"
    );

Each Menu Configuration Hash Structure consists of elements that define and control it's behavior, appearance, constitution and purpose. An element's syntax is as you would expect it to be in perl - a key string pointing to an assocaited value: key => value. The following items list supported key names and ther associated value types:

  • Display => 'Integer'

      The Display key is an optional key that determines the number of Menu Items that will be displayed on each screen. This is useful when the items are multi-lined, or the screen size is bigger or smaller than the default number utilizes in the most practical fashion. The default number is 10.

      Display => 15,
  • Name => 'Char String consisting of ASCII Characters'

      The Name key provides a unique identifier to each Menu Structure. This element is not "strictly" required for most Menu construts to function properly. Term::Menus goes to great lengths to discover and utilize the Menu's name provided on the left side of the equals character of a Menu block using the following construct:

      my %MenuName=(
      
         [ Menu Contents Here ]
      
      );

      In the above example, the Menu name is "MenuName". Most of the time Term::Menus will discover this name successfully, affording the user or Menu developer one less requirement to worry about. Allowing Term::Menus to discover this name will cut down on opportunities for coding errors (and we all have enough of those already). HOWEVER, there are "edge cases" and more complex Menu constructs that will prevent Term::Menus from accurately discovering this name. Therefore, it is recommended and is considered a "best practice" to always explicitly "Name" Menu blocks as follows:

      my %MenuName=(
      
         Name => 'MenuName',
      
         [ Menu Contents Here ]
      
      );

      Be careful to always use the SAME NAME for the Name element as for the Menu block itself. This can be a source of error, especially when one is using Macros that reference Menu Names explicitly (So be CAREFUL!) One case where the Name element must ALWAYS be used (if one wishes to reference that Menu with an explicit Named Macro) is when creating anonymous Menu blocks to feed directly to Result elements:

      my %ContainingMenu=(
      
         Name   => 'ContainingMenu',
         Item_1 => {
      
             Text => "Some Text",
             Result => {
      
                Name => "Anonymous_Menu", # MUST use "Name" element
                                          # if planning to use
                                          # explicit Macros
      
                [ Menu Contents Here ]
      
             },
         },
      
      );
  • Item_<int> => { Item Configuration Hash Structure }

      The Item_<int> elements define customized menu items. There are essentially two methods for creating menu items: The Item_<int> elements, and the ]Convey[ macro (described later). The difference being that the ]Convey[ macro turns an Item Conguration Hash into an Item Template -> a powerful way to Item-ize large lists or quantities of data that would otherwise be difficult - even impossible - to anticipate and cope with manually.

      Item_1 => { Text => 'Item 1' },
      Item_2 => { Text => 'Item 2' },

      Items created via ]Convey[ macros have two drawbacks:

      • They all have the same format.

      • They all share the same Result element.

      The syntax and usage of Item_<int> elements is important and extensive enough to warrant it's own section. See Item Configuration Hash Structures below.

  • Select => 'One' --or-- 'Many'

      The MENU LEVEL Select element determines whether this particular menu layer allows the selection of multiple items - or a single item. The default is 'One'.

      Select => 'Many',
  • Banner => 'Char String consisting of ASCII Characters' or anonymous subroutine or subroutine reference for generating dynamic banners.

      The Banner element provides a customized descriptive header to the menu. $Banner is an optional element - giving instructions, descriptions, etc. The default is "Please Pick an Item:"

      Banner => "The following items are for selection,\n".
                "\tEnjoy the Experience!",

      --or--

      Banner => sub { <generate dynamic banner content here> },

      --or--

      my $create_banner = sub { <generate dynamic banner content here> },
      
      Banner => $create_banner,

      Creating a reference to a Banner subroutine enables the sharing of Banner generation code between multiple Menus.

      NOTE: Macros (like ]Previous[ ) can be used in Banners! :-) ( See Item Configuration Macros below )

Item Congfiguration Hash Structures

Each Menu Item can have an independant configurtion. Each Menu Configuration Hash Structure consists of elements that define and control it's behavior, appearance, constitution and purpose. An element's syntax is as you would expect it to be in perl - a key string pointing to an assocaited value: key => value. The following items list supported key names and ther associated value types:

  • Text => 'Char String consisting of ASCII Characters'

      The Text element provides a customized descriptive string for the Item. It is the text the user will see displayed, describing the selection.

      Text => 'This is Item_1',
  • Convey => [ List ] --or-- @List --or-- $Scalar --or-- 'ASCII String'

      The Convey element has a twofold purpose; it provides for the contents of the ]Convey[ macro, and defines or contains the string or result that is passed on to child menus - if any. Use of this configuration element is optional. If Convey is not a list, then it's value is passed onto child menus. If Convey is a list, then the Item selected is passed onto the children - if any. It is important to note, when used, that only the resulting Convey string - NOT the the Item Text value or string, is conveyed to child menus. When the Convey element is not used, the full Item Text value is conveyed to the children - if any. However, the full contents of the Text element is returned as the Result of the operation when the user completes all menu activity. See the Macro section below for more information.

      Convey => [ `ls -1` ] ,
  • Default => 'Char String' --or-- Perl regular expression - qr/.../

      The Default element provides a means to pre-select certain elements, as if the items were selected by the user. This can be done with two constructs - simple string or pre-compiled regular expression. Note: The Default element is available only when the Select element is set to 'Many' - Select = 'Many',>

      Default => 'base|chown',
      
      Default => qr/base|chown/i,

      The user sees ==>

      Choose a /bin Utility :
      
         1.        /bin Utility - arch
         2.        /bin Utility - ash
         3.        /bin Utility - awk
      *  4.        /bin Utility - basename
         5.        /bin Utility - bash
         6.        /bin Utility - cat
         7.        /bin Utility - chgrp
         8.        /bin Utility - chmod
      *  9.        /bin Utility - chown
         10.       /bin Utility - cp
      
      a.  Select All.   c.  Clear All.
      f.  Finish.
      
      93 Total Choices
      
      Press ENTER (or "d") to scroll downward
      
      OR "u" to scroll upward  (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:
  • Select => 'One' --or-- 'Many'

      The ITEM LEVEL Select element provides a means to inform Term::Menus that the specific items of a single ITEM BLOCK (as opposed to full menu) are subject to multiple selecting - or just single selection. This is useful in particular for Directory Tree navigation - where files can be multi-selected (or tagged), yet when a directory is selectedi, it forces an immediate navigation and new menu - showing the contents of the just selected directory.

      NOTE: See the RECURSIVELY CALLED MENUS section for more information.

      Select => 'More',

      The user sees ==>

      d  1.        bin
      d  2.        blib
      d  3.        dist
      d  4.        inc
      d  5.        lib
      d  6.        Module
      d  7.        t
         8.        briangreat2.txt
      *  9.        ChangeLog
         10.       close.perl
      
      a.  Select All.   f.  Finish.
      
      49 Total Choices
      
      Press ENTER (or "d") to scroll downward
      
      OR "u" to scroll upward  (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:
  • Exclude => 'Char String' --or-- Perl regular expression - qr/.../

      The Exclude element provides a means to remove matching elements from the Menu seen by the user. This element is useful only when the ]Convey[ macro is used to populate items. This can be done with two constructs - simple string or pre-compiled regular expression.

      Exclude => 'base|chown',
      
      Exclude => qr/base|chown/i,
  • Include => 'Char String' --or-- Perl regular expression - qr/.../

      The Include element provides a means to create items filtered from a larger list of potential items available via the ]Convey[ macro. This element is useful only when the ]Convey[ macro is used to populate items. The Exclude element can be used in conjunction with Include to further refine the final list of items used to construct the menu. The Include element - when used - always takes presidence, and the Exclude will be used only on the Include filtered results. This element can be used with two value constructs - simple string or pre-compiled regular expression.

      Include => 'base|chown',
      
      Include => qr/base|chown/i,
  • Result => \%Menu_2 --or -- "&any_method()",

      Result is an optional element that also has two important uses:

      For selecting the child menu next in the chain of operation and conveyance,

      Result => \%Menu_2,

      --or--

      For building customized method arguements using &Menu()'s built-in macros.

      Result => "&any_method($arg1,\"]Selected[\",\"]Previous[\")",

      NOTE: ALWAYS be sure to surround the subroutine or method calling syntax with DOUBLE QUOTES. (You can use single quotes if you don't want interpolation). Quotes are necessary because you're telling &Menu() - not Perl - what method you want invoked. &Menu() won't invoke the method until after all other processing - where Perl will try to invoke it the first time it encounters the line during runtime - lo----ng before a user gets a chance to see or do anything. BUT - be sure NOT to use quotes when assigning a child menu reference to the Result value.

      Again, Result is an optional element. The default behavior when Result is omitted from the Item Configuration element, is for the selection to be returned to the &Menu()'s calling script/module/app. If the Select element was set to 'One', then that item is returned regardless of whether the Perl structure receiving the output is an array or scalar. If there were multiple selections - i.e., Select is set to 'Many' - then, depending on what structure is set for receiving the output, will determine whether &Menu() returns a list (i.e. - array), or reference to an array.

Item Configuration Macros

Each Menu Item can utilize a very powerful set of configuration Macros. These constructs principally act as purveyors of information - from one menu to another, from one element to another. There are currently three available Macros:

  • ]Convey[

      ]Convey[ is used in conjunction with the Convey element (described) earlier. It's purpose to "convey" or transport or carry a list item associated with the Convey element - and replace the ]Convey[ Macro in the Text element value with that list item. The Convey mechanism utilizing the Convey Macro is essentially an Item multiplier. The entire contents of the list associated with the Convey element will be turned into it's own Item when the menu is displayed. Both ordinary and anonymous subroutines can be use to dynamically generate Convey lists. (With ]Convey[, macros can be used only as subroutine arguments or in the body of anonymous subroutines - see other examples.)

      use Term::Menus;
      
      my %Menu_1=(
      
         Name   => 'Menu_1',
         Item_1 => {
      
            Text   => "/bin/Utility - ]Convey[",
            Convey => [ `ls -1 /bin` ],
            Result => \%Menu_2,
      
         },
      
         Select => 'One',
         Banner => "\n   Choose a /bin Utility :"
      );
      
      my @selections=&Menu(\%Menu_1);
      print "SELECTIONS=@selections\n";

      The user sees ==>

      Choose a /bin Utility :
      
         1.        /bin Utility - arch
         2.        /bin Utility - ash
         3.        /bin Utility - awk
         4.        /bin Utility - basename
         5.        /bin Utility - bash
         6.        /bin Utility - cat
         7.        /bin Utility - chgrp
         8.        /bin Utility - chmod
         9.        /bin Utility - chown
         10.       /bin Utility - cp
      
      a.  Select All.   c.  Clear All.
      f.  Finish.
      
      93 Total Choices
      
      Press ENTER (or "d") to scroll downward
      
      OR "u" to scroll upward  (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:

      NOTE: ]C[ can be used as a shorthand for ]Convey[.

  • ]Previous[

      ]Previous[ can be used in child menus. The ]Previous[ Macro contains the Selection of the parent menu. Unlike the ]Convey[ Macro, the ]Previous[ Macro can be used in both the Text element value, and the Result element values (when constructing method calls):

      The ]Previous[ Macro can also be used in the Banner.

      use Term::Menus;
      
      my %Menu_2=(
      
         Name   => 'Menu_2',
         Item_1 => {
      
            Text   => "]Previous[ is a ]Convey[ Utility",
            Convey => [ 'Good','Bad' ]
         },
      
         Select => 'One',
         Banner => "\n   Choose an Answer :"
      );
      
      my %Menu_1=(
      
         Name   => 'Menu_1',
         Item_1 => {
      
            Text   => "/bin/Utility - ]Convey[",
            Convey => [ `ls -1 /bin` ],
            Result => \%Menu_2,
      
         },
      
         Select => 'One',
         Banner => "\n   Choose a /bin Utility :"
      );
      
      my @selections=&Menu(\%Menu_1);
      print "SELECTIONS=@selections\n";

      The user sees ==>

      Choose a /bin Utility :
      
         1.        /bin Utility - arch
         2.        /bin Utility - ash
         3.        /bin Utility - awk
         4.        /bin Utility - basename
         5.        /bin Utility - bash
         6.        /bin Utility - cat
         7.        /bin Utility - chgrp
         8.        /bin Utility - chmod
         9.        /bin Utility - chown
         10.       /bin Utility - cp
      
      a.  Select All.   c.  Clear All.
      f.  Finish.
      
      93 Total Choices
      
      Press ENTER (or "d") to scroll downward
      
      OR "u" to scroll upward  (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:

      --< 5 >-<ENTER>----------------------------------

      Choose an Answer :
      
         1.        bash is a Good Utility
         2.        bash is a Bad Utility
      
      (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:

      --< 1 >-<ENTER>----------------------------------

      The user sees ==>

      SELECTIONS = bash is a Good Utility

      NOTE: ]P[ can be used as a shorthand for ]Previous[.

  • ]Previous[{ <Menu_Name> } i.e. Explicit Named Macro

      ]Previous[{Menu_Name} (i.e. Explicit Named Macros) can be used in child menus. The ]Previous[{Menu_Name} Macro contains the Selection of any preceding menu specified with the Menu_Name string. The ]Previous[{Menu_Name} follows the same conventions as the ]Previous[ Macro - but enables access to the selection of i<any> preceding menu. This is very useful for Menu trees more than two levels deep.

      The ]Previous[{Menu_Name} Macro can also be used in the Banner.

      use Term::Menus;
      
      my %Menu_3=(
      
         Name   => 'Menu_3',
         Item_1 => {
      
            Text   => "]Convey[ said ]P[{Menu_1} is a ]Previous[ Utility!",
            Convey => [ 'Bob','Mary' ]
         },
      
         Select => 'One',
         Banner => "\n   Who commented on ]Previous[{Menu_1}? :"
      );
      
      my %Menu_2=(
      
         Name   => 'Menu_2',
         Item_1 => {
      
            Text   => "]Previous[ is a ]C[ Utility",
            Convey => [ 'Good','Bad' ],
            Result => \%Menu_3,
         },
      
         Select => 'One',
         Banner => "\n   Is ]P[ Good or Bad? :"
      );
      
      my %Menu_1=(
      
         Name   => 'Menu_1',
         Item_1 => {
      
            Text   => "/bin/Utility - ]Convey[",
            Convey => [ `ls -1 /bin` ],
            Result => \%Menu_2,
      
         },
      
         Select => 'One',
         Banner => "\n   Choose a /bin Utility :"
      );
      
      my @selections=&Menu(\%Menu_1);
      print "SELECTIONS=@selections\n";

      The user sees ==>

      Choose a /bin Utility :
      
         1.        /bin Utility - arch
         2.        /bin Utility - ash
         3.        /bin Utility - awk
         4.        /bin Utility - basename
         5.        /bin Utility - bash
         6.        /bin Utility - cat
         7.        /bin Utility - chgrp
         8.        /bin Utility - chmod
         9.        /bin Utility - chown
         10.       /bin Utility - cp
      
      PLEASE ENTER A CHOICE:

      --< 5 >-<ENTER>----------------------------------

      Is bash Good or Bad? :
      
         1.        bash is a Good Utility
         2.        bash is a Bad Utility
      
      (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:

      --< 1 >-<ENTER>----------------------------------

      Who commented on bash? :
      
         1.        Bob said bash is a Good Utility!
         2.        Mary said bash is a Good Utility!
      
      (Type "quit" to quit)
      
      PLEASE ENTER A CHOICE:

      --< 2 >-<ENTER>----------------------------------

      The user sees ==>

      SELECTIONS = Mary said bash is a Good Utility!

      NOTE: ]P[ can be used as a shorthand for ]Previous[.

      ]P[{Menu_Name} can be used as a shorthand for ]Previous[{Menu_Name}.

      ]C[ can be used as a shorthand for ]Convey[.

  • ]Selected[

      ]Selected[ can only be used in a terminal menu. ( A terminal menu is the last menu in the chain, or the last menu the user sees. It is the menu that defines the Result element with a method Result => &any_method(), or does not have a Result element included or defined. ) ]Selected[ is used to pass the selection of the current menu to the Result element method of the current menu:

      use Term::Menus;
      
      sub selected { print "\n   SELECTED ITEM = $_[0]\n" }
      
      my %Menu_1=(
      
         Name   => 'Menu_1',
         Item_1 => {
      
            Text   => "/bin/Utility - ]Convey[",
            Convey => [ `ls -1 /bin` ],
            Result => "&selected(]Selected[)", # ]Selected[ macro passed to
                                               # ordinary perl subroutine.
                                               # The '&' characater is optional
                                               # but the quotes are NOT. Ordinary
                                               # subroutine calls MUST be
                                               # surrounded by either double or
                                               # single quotes. (DO NOT use
                                               # quotes around anonymous
                                               # subroutine calls, however!) 
      
         },
      
         Select => 'One',
         Banner => "\n   Choose a /bin Utility :"
      );
      
      my $selection=&Menu(\%Menu_1);
      print "\n   SELECTION=$selection\n";

      NOTE: ]S[ can be used as a shorthand for ]Selected[.

      NOTE: if you want to return output from the Result subroutine, you must include a 'return' statement. So the sub above:

         sub selected { print "\n   SELECTED ITEM = $_[0]\n" }
      
      Becomes:
      
         sub selected { print "\n   SELECTED ITEM = $_[0]\n";return $_[0] }

      NOTE: There is also an Explicit Named Macro construct with this Macro as well - but it has a very limited and "explicit" application. It can be very useful and powerful to dynamically construct child Menus in Result blocks - Embedded Menus are another way to describe these. These can be problematic however for this reason: When a menu is parsed for Macros and Term::Menus finds them, ALL Macros will expanded or replaced - including the ones found in Embedded Menus! To prevent this, explicitly name embedded ]Selected[ macros as follows in the example:

         my %Top_Menu = (
      
            Name   => 'Top_Menu',
            Item_1 => {
      
               Text   => 'Some Top_Menu Text',
               Result => {
      
                  Name   => 'Embedded_Menu',
                  Item_1 => {
      
                     Text => 'Some Embedded_Menu Text'
                     Result => sub { print ]Selected[{Embedded_Menu} }
      
                  },
      
               },
            },
      
         );
      
      The Embedded Menu is an anonymous hash, and requires a Name
      element. If one were to use a naked ]Selected[ Macro rather
      than an Explicit Named Macro here, the printed result would
      be "Some Top_Menu Text" rather than "Some Embedded_Menu Text"
      which is probably what the user or Menu developer is really
      after.

ANONYMOUS SUBROUTINES AND MACROS

Term::Menus macros can be used directly in the body of anonymous subroutines! Ordinary subroutines can be used as illustrated above of course, but the macro values can only be passed as arguments to ordinary subroutines. This is much more complicated and less intuitive than using macros directly in the code itself. Below is an example of their usage. The author received a request a while back from a user, asking if it was possible to return the item number rather than it's text value. The answer of course is YES! The code below illustrates this:

    use Term::Menus;
    
    my @list=('One','Two','Three');
    
    my %Menu_1=(
    
       Item_1 => {
    
          Text    => "NUMBER - ]Convey[",
          Convey  => \@list,
          Result  => sub {
                            my $cnt=-1;my $selection=']Selected[';
                            foreach my $item (@list) {
                               $cnt++;
                               chomp($item);
                               last if -1<index $selection, $item;
                            } return "$cnt";
                         }
                         # Note use of ]Selected[ macro in
                         # anonymous subroutine body
    
       },
    
       Select => 'One',
       Banner => "\n   Choose a /bin Utility :"
    );
    
    my $selection=Menu(\%Menu_1);
    print "   \nSELECTION = $selection\n";

Anonymous subroutines can be assigned directly to "Item_1" (or Item_2, etc.) elements 'Convey' and 'Result' as well as to the Menu "Banner" element. Use of the these constructs over more traditional subroutines is encouraged because it means writing less code, while enabling the code that is written to be less complex, more intuitive and readable, and certainly easier to maintain. The same anonymous routine can be use in multipe Menus or Items of a single Menu by assigning that routine to a variable, and then assigning the variable instead.

NOTE: To force a return to a parent menu (assuming there is one) from a subroutine assigned to a Result element, just return '<' from the subroutine. This is extremely useful when there is a desire to process a selection, and then return to the parent menu when processing is complete. :-)

    use Term::Menus;
    
    my @list=('One','Two','Three');
    
    my $result = sub {
                        my $cnt=-1;my $selection=']Selected[';
                        foreach my $item (@list) {
                           $cnt++;
                           chomp($item);
                           last if -1<index $selection, $item;
                        } return "$cnt";
                     };
                     # Anonymous subroutine assigned to "$result" variable
    
    my %Menu_1=(
    
       Item_1 => {
    
          Text    => "NUMBER - ]Convey[",
          Convey  => \@list,
          Result  => $result, # Anonymous subroutine assisned via
                              # "$result" variable
    
       },
    
       Select => 'One',
       Banner => "\n   Choose a /bin Utility :"
    );
    
    my $selection=Menu(\%Menu_1);
    print "   \nSELECTION = $selection\n";

RECURSIVELY CALLED MENUS

There are occasions where it is desirable to re-use the same Menu template/hash configuration with dynamically discovered data. One obvious example of this is navigating directory trees. Each subsequent directory selection could potentially contain deeper levels of directories. Essentially, any data structured in any kind of relational tree layout is subject to this kind of navigation approach. Be warned however, unlike most other functionality that is handled almost entirely by the Term::Menus module, the code for doing recursive templating is mostly contained in the template/hash configuration itself. There is a "helper routine" (&get_Menu_map) that Term::Menus provides to assist with the creation of recursively-friendly configurations, but given the highly data-centric characteristics of such functionality, most of the working code must be left to the authoring and management of the user.

&get_Menu_map()

This is a helper routine that returns a list of ancestor menu results. This is needed when wanting to navigate a directory tree for instance. Imagine a directory path that looks like this: /one/two/three. A call to &get_Menu_map() when processing directory three with return this list: ('one','two').

    The following code is an example of how to use recursion for navigating a directory tree.

    use Term::Menus;
    
    my %dir_menu=(
    
       Name   => 'dir_menu',
       Item_1 => {
    
          Text => "]C[",
          Mark => "d",
          Convey => sub {
    
             if ("]P[") {
    
                my $dir="]P[";
                if ($^O eq 'cygwin') {
                   $dir='/cygdrive/c/';
                } else {
                   $dir='/';
                }
                my @xfiles=();
                my @return=();
                my @map=get_Menu_map;
                my $path=join "/", @map;
                opendir(DIR,"$dir$path") || die $!;
                @xfiles = readdir(DIR);
                closedir(DIR);
                foreach my $entry (sort @xfiles) {
                   next if $entry eq '.';
                   next if $entry eq '..';
                   if (-1<$#map) {
                      next unless -d "$dir$path/$entry";
                   } else {
                      next unless -d "$dir/$entry";
                   }
                   push @return, "$entry";
                }
                return @return;
    
             }
             my @xfiles=();
             my @return=();
             if ($^O eq 'cygwin') {
                opendir(DIR,'/cygdrive/c/') || die $!;
             } else {
                opendir(DIR,'/') || die $!;
             }
             @xfiles = readdir(DIR);
             closedir(DIR);
             foreach my $entry (@xfiles) {
                next if $entry eq '.';
                next if $entry eq '..';
                next unless -d "$entry";
                push @return, "$entry";
             }
             return @return;
    
          },
          Result => { 'dir_menu'=>'recurse' },
    
       },
       Item_2 => {
    
          Text => "]C[",
          Select => 'Many',
          Convey => sub {
    
             if ("]P[") {
    
                my $dir="]P[";
                if ($^O eq 'cygwin') {
                   $dir='/cygdrive/c/';
                } else {
                   $dir='/';
                }
    
                my @xfiles=();
                my @return=();
                my @map=get_Menu_map;
                my $path=join "/", @map;
                opendir(DIR,"$dir/$path") || die $!;
                @xfiles = readdir(DIR);
                closedir(DIR);
                foreach my $entry (sort @xfiles) {
                   next if $entry eq '.';
                   next if $entry eq '..';
                   if (-1<$#map) {
                      next if -d "$dir/$path/$entry";
                   } else {
                      next if -d "$dir/$entry";
                   }
                   push @return, "$entry";
                }
                return @return;
    
             }
             my @xfiles=();
             my @return=();
             if ($^O eq 'cygwin') {
                opendir(DIR,'/cygdrive/c/') || die $!;
             } else {
                opendir(DIR,'/') || die $!;
             }
             @xfiles = readdir(DIR);
             closedir(DIR);
             foreach my $entry (@xfiles) {
                next if $entry eq '.';
                next if $entry eq '..';
                next if -d "$entry";
                push @return, "$entry";
             }
             return @return;
    
          },
       },
       Banner => "   Current Directory: ]P[\n",
    
    );
    
    my $selection=Menu(\%dir_menu);
    
    if (ref $selection eq 'ARRAY') {
       print "\nSELECTION=",(join " ",@{$selection}),"\n";
    } else {
       print "\nSELECTION=$selection\n";
    }

USAGE and NAVIGATION

Usage of &pick() and/or &Menu() during the runtime of a script in which one or both are included, is simple and intuitive. Nearly everything the end user needs in terms of instruction is included on-screen. The script-writer/developer/programmer can also include whatever instructions s/he deems necessary and/or helpful in the customizable Banner (as described above). There is however, one important feature about using &Menu() with sub-menus that's important to know about.

Forward ' > ' and Backward ' < ' Navigation

When working with more than one &Menu() screen, it's valuable to know how to navigate back and forth between the different &Menu() levels/layers. For example, above was illustrated the output for two layers of menus - a parent and a child:

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< 5 >-<ENTER>----------------------------------

    The user sees ==>

    Choose an Answer :
    
       1.        bash is a Good Utility
       2.        bash is a Bad Utility
    
    (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    In the above example, suppose that the user "fat-fingered" his/her choice, and really didn't want to "bash" bash, but wanted to bash awk instead. Is restarting the whole script/application now necessary? Suppose it was a process that had run overnight, and the user is seeing this menu through fogged glasses from the steam rising out of their morning coffee? Having to run the whole job again would not be welcome news for the BOSS. THANKFULLY, navigation makes this situation avoidable. All the user would have to do is type ' < ' to go backward to the previous menu, and ' > ' to go forward to the next menu (assuming there is one in each case):

    The user sees ==>

      Choose an Answer :
    
         1.        bash is a Good Utility
         2.        bash is a Bad Utility
    
      (Type "quit" to quit)
    
      PLEASE ENTER A CHOICE:
    
    --<  >  >-<ENTER>-----------------------------

    The user sees ==>

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
    -  5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    Note in the above example the Dash ' - ' in front of item 5. This informs the user that s/he had previously selected this item. To clear the selection, the user would simply choose item 5 again. This effectively deletes the previous choice and restores the menu for a new selection. If the user was satisfied with the choice, and was simply double checking thier selection, they simply repeat the navigation process by typing ' > ' - then <ENTER> - and returning to the child menu they left.

    If the child menu was a multiple-selection menu, and the user had made some selections before navigating back to the parent menu, the user would see a ' + ' rather than a ' - '. This informs the user that selections were made in the child menu.

    Choose a /bin Utility :
    
       1.        /bin Utility - arch
       2.        /bin Utility - ash
       3.        /bin Utility - awk
       4.        /bin Utility - basename
    +  5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
       9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

View Sorted Items ' % '

When working with numerous items in a single menu, it may be desirable to see the set of choices organized in either descending or reverse acscii order. Term::Menus provides this feature with the Percent ' % ' key. Simply type ' % ' and the items will be sorted in descending ascii order. Type ' % ' again, and you will see the items reverse sorted. Assume that we have the following menus.

    The user sees ==>

    Please select all files for immediate transfer:
    
    *  1.        addr2name.awk has  **NOT**  been transferred
    *  2.        awk.exe has  **NOT**  been transferred
       3.        gawk-3.1.4.exe has  **NOT**  been transferred
    *  4.        gawk.exe has  **NOT**  been transferred
       5.        igawk has  **NOT**  been transferred
       6.        pgawk-3.1.4.exe has  **NOT**  been transferred
       7.        pgawk.exe has  **NOT**  been transferred
    *  8.        822-date has been transferred
       9.        DllPlugInTester.exe has been transferred
    *  10.       ELFDump.exe has been transferred
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    929 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< % >-<ENTER>----------------------------------

    The user sees ==>

    Please select all files for immediate transfer:
    
    *  8.        822-date has been transferred
       9.        DllPlugInTester.exe has been transferred
    *  10.       ELFDump.exe has been transferred
       11.       GraphicsMagick++-config has been transferred
       12.       GraphicsMagick-config has been transferred
       13.       X11 has been transferred
       14.       [.exe has been transferred
       15.       a2p.exe has been transferred
       16.       aclocal has been transferred
       17.       aclocal-1.4 has been transferred
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    929 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    And if we choose to enter ' % ' again

    --< % >-<ENTER>----------------------------------

    The user sees ==>

    Please select all files for immediate transfer:
    
       929.      znew has been transferred
       928.      zmore has been transferred
       927.      zless has been transferred
       926.      zipsplit.exe has been transferred
       925.      zipnote.exe has been transferred
       924.      zipinfo has been transferred
       923.      zipgrep has been transferred
       922.      zipcloak.exe has been transferred
       921.      zip.exe has been transferred
       920.      zgrep has been transferred
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    929 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    This submenu of selections works just like any other menu. The user can deselect an item, clear all items, re-choose all items, etc. The choices made here are preserved when-or-if the user navigates back to the original (parent) menu. In other words, if Item 1. is deselected in the sorted menu, Item 1. will also be deselected in the parent menu above.

View Summary of Selected Items ' * '

When working with numerous items in a single menu, it is desirable to see the set of choices made before leaving the menu and committing to a non-returnable forward (perhaps even critical) process. Term::Menus provides this feature with the Star ' * ' key. Assume we have the following menu with 93 Total Choices. Assume further that we have selected items 1,3,9 & 11. Note that we cannot see Item 11 on the first screen since this menu is configured to show only 10 Items at a time.

    The user sees ==>

    Choose a /bin Utility :
    
    *  1.        /bin Utility - arch
       2.        /bin Utility - ash
    *  3.        /bin Utility - awk
       4.        /bin Utility - basename
       5.        /bin Utility - bash
       6.        /bin Utility - cat
       7.        /bin Utility - chgrp
       8.        /bin Utility - chmod
    *  9.        /bin Utility - chown
       10.       /bin Utility - cp
    
    a.  Select All.   c.  Clear All.
    f.  Finish.
    
    93 Total Choices
    
    Press ENTER (or "d") to scroll downward
    
    OR "u" to scroll upward  (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    --< * >-<ENTER>----------------------------------

    The user sees ==>

    Choose a /bin Utility :
    
    *  1.        /bin Utility - arch
    *  3.        /bin Utility - awk
    *  9.        /bin Utility - chown
    *  11.       /bin Utility - cpio
    
    (Type "quit" to quit)
    
    PLEASE ENTER A CHOICE:

    This submenu of selections works just like any other menu. The user can deselect an item, clear all items, re-choose all items, etc. The choices made here are preserved when-or-if the user navigates back to the original (parent) menu. In other words, if Item 1. is deselected in the summary menu, Item 1. will also be deselected in the parent menu above.

AUTHOR

Brian M. Kelly <Brian.Kelly@fullautosoftware.net>

COPYRIGHT

Copyright (C) 2000-2013 by Brian M. Kelly.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License. (http://opensource.org/licenses/gpl-3.0.html).

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 6412:

You can't have =items (as at line 6417) unless the first thing after the =over is an =item

Around line 6920:

=back without =over