perlmenu-4.0.orig/ 40770 1750 1750 0 6301170052 14006 5ustar jgoerzenjgoerzenperlmenu-4.0.orig/ARTISTIC100660 1750 1750 13740 6122026566 15311 0ustar jgoerzenjgoerzen The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End perlmenu-4.0.orig/COPYING100660 1750 1750 61262 6122026567 15202 0ustar jgoerzenjgoerzen GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any OTHER LIbraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! perlmenu-4.0.orig/MENUUTIL_DOC100660 1750 1750 24105 6301157732 16012 0ustar jgoerzenjgoerzen menuutil.pl Perl Menu Support Utilities Version 1.1 February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa -------- Overview -------- After writing several Perl+Curses programs which used PerlMenus I learned there was often a set of utility routines that I used in each program. I eventually collected these in a module ("menuutil.pl") which I included in each source. These routines provide titles, text display, and prompting - all the while maintaining global row and column positions. These routines are probably best understood by studying the "demo_util" program supplied in this distribution. In any case, some routines rely on standard "perlmenu.pm" routines (menu_getstr, specifically) so you add 'require "menuutil.pl";' to existing PerlMenu programs. -------------------------- Official Distribution Site -------------------------- The PerlMenu package is distributed via "CPAN" (the "Comprehensive Perl Archive Network"). Pick a CPAN site near you with a WWW browser pointed at "http://www.perl.com/perl/CPAN/CPAN.html" and go into the "authors/Steven L Kunz" folder. You should find "perlmenu.v4.0.tar.Z" in there. The author's official distribution is available via anonymous FTP from: ftp://ftp.iastate.edu/pub/perl/perlmenu.v4.0.tar.Z Other sites on the net may offer this package. New releases are announced in the Usenet Newsgroup "comp.lang.perl.announce". PerlMenu also has an official WWW page at: http://www.cc.iastate.edu/perlmenu/homepage.html --------------------------- Required setup in your code --------------------------- The routines provided in "menuutil.pl" are used for some common curses screen I/O functions (such as clearing the screen, formatting top-titles, placing text on the screen, and prompting for information). The utility routines require some initialization and variable management (or at least preservation) in your own code. There are three REQUIRED variables you must assign before using any menuutil routines. These are: $window - The curses main window value $row - Integer containing screen row offset of the cursor $col - Integer containing screen column offset of the cursor All the menuutil routines use "$row" and "$col" to maintain the current location on the screen. You should initialize both to zero. The "$window" variable can be assigned in two ways (depending on your style of PerlMenu program coding). If you issue the curses "initscr" call yourself, the front of your program should have the following statements: use perlmenu; # PerlMenu package (main routines) require "menuutil.pl"; # PerlMenu package (utility routines) [...] $row = $col = 0; # Init row and col variables $window = &initscr(); # Get main screen window value &menu_curses_application($window); # Tell PerlMenu what we are using If you use the return value from "menu_init" (letting perlmenu.pm do the "initscr" for you), the following is correct: use perlmenu; # PerlMenu package (main routines) require "menuutil.pl"; # PerlMenu package (utility routines) [...] $row = $col = 0; # Init row and col variables $window = &menu_init(); # Init the curses environment If you do any output to the screen yourself (i.e. you do some of your own "move", "addstr", or other curses commands) then you must maintain "$row" and "$col" so they are accurate for the menuutil routines you may call after that. This has lots of implications. For example, if you "clear" the screen in your code, you must remember to reset the "$row" and "$col" values to zero (since on most systems a "clear" will home the cursor to the upper left corner. For example: &clear(); $row = $col = 0; &refresh(); # Clear the screen. The menuutil routine "clear_screen" does just this action (with the ability to skip the "refresh" for most efficient screen I/O coding). Of course ANY action which moves the screen cursor must be accounted for. If you use "addstr" to place text on the screen, you must adjust "$col" by the length of the string (accounting for screen wrap as necessary). Full-screen manipulation with curses can become involved very fast. The menuutil routines provide some basic actions that hopefully can get most applications up and running with a minimum of effort. ------------------------- Solicitation for Comments ------------------------- If you have found a bug, documentation problem, or would really like to see a new utility routine (or have one you think could be added), feel free to let me know. Send your e-mail cheers/jeers to "skunz@iastate.edu". --------------------- Text Display Routines --------------------- ---------- Routine: clear_screen Syntax: &clear_screen(refresh_flag); Input args: Boolean flag (0=don't do a "refresh", 1=do a "refresh") Returns: Nothing (screen buffer plus row & col variables cleared) The "clear_screen" routine clears the main window buffer and resets the row and column variables. Since you will normally be doing further screen output a "refresh" (to actually cause terminal I/O) is not done unless requested by the option flag. ---------- Routine: top_title Syntax: &top_title("Title string"); Input args: String for the title Returns: Nothing The "top_title" routine clears the main window and centers the title string on the top line. The title is normally presented in "standout" rendition. Normal rendition may be forced by placing a dash ("-") as the first character. Titles longer than the screen width will be truncated. A "refresh" is ALWAYS done before return. ---------- Routine: print_nl Syntax: &print_nl("Text string",new_line_count); Input args: - Text string to put at cursor location - Number of new-lines to add afterwards Returns: Nothing The "print_nl" routine adds text to the screen, maintaining row and col locations. If the text rolls past the bottom of the screen, the screen is cleared and text starts again at the top. Automatic line-wrap is handled. A "refresh" is ALWAYS done before return. ---------- Routine: new_line Syntax: &new_line(new_line_count); Input args: Number of new-lines to add Returns: Nothing The "new_linel" routine adds blank lines to the screen, maintaining row and col locations. If the action rolls past the bottom of the screen, the screen is cleared and action starts again at the top. This routine is useful if you use "menu_getstr" to input data and want to bump the cursor down to the next line after the user hits "Return". A "refresh" is ALWAYS done before return. ------------------ Prompting Routines ------------------ ---------- Routine: query Syntax: &query("Prompt text","allowed_values"); Input args: - Prompt text string - Allowed values string Returns: Single character from "allowed_values" The "query" routine takes the prompt text and appends the list of values allowed (reformatted in "user-friendly format"). For example, if the following were supplied: $val = &query("Delete file?","yn?"); what the user would see would be: Delete file? (y|n|?) If a value other than "y" or "n" or "?" was supplied the routine will automatically indicate the error and re-prompt until a proper value is supplied. When the routine returns you are assured that the value returned is one of those in the "allowed_values" string. ---------- Routine: pause Syntax: &pause("Prompt text"); Input args: Prompt text string Optional. Defaults to "[Press any key to continue]" Returns: Nothing The "pause" routine moves to a new line, supplies the prompt, and pauses until any key is pressed. ---------- Routine: popup_ask Syntax: &popup_ask("Prompt text",max_len,"Default string", hidden_flag,numeric_flag); Input args: Note: All parms are optional - Prompt string - Maximum data input length - Default value string - Boolean flag (0=show, 1=hidden) - Boolean flag (0=alpha-numeric, 1=numeric) Returns: Nothing The "popup_ask" routine builds a popup dialog box in the center of the screen. Calculation of the box size and position is automatic (based on the length of prompt and maximum data length). If no parameters are supplied a box the width of the screen (with the maximum size data area) is built. A default value (pre-loaded in the data area) can be supplied. The "hidden_flag" allows for password-style prompting. The "numeric_flag" indicates that only numeric digits (0-9) are allowed. -------------- For the record -------------- PerlMenu - Perl library module for curses-based menus & data-entry templates Copyright (C) 1992-97 Iowa State University Computation Center This Perl library module is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License (as published by the Free Software Foundation) or the Artistic License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. perlmenu-4.0.orig/MENU_DOC100660 1750 1750 236705 6301157737 15354 0ustar jgoerzenjgoerzen perlmenu.pm Perl Menus Version 4.0 February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa -------- Overview -------- The "perlmenu.pm" package is a Perl5 package (built into your Perl program with a "use perlmenu.pm" command) that automates curses-based full screen menus and data entry. It also functions under Perl4/curseperl. Using three simple calls, any number of items may be selected from a single or multiple-page menu by moving an arrow to the desired item (or directly entering the selection number displayed on the screen). In addition to simple "single one-shot selection menus", "radio button" style menus and "multiple-item-selection" menus are provided. Paging through multiple-page menus is handled automatically. Menu titles, sub-titles, prompts, "single column", and "multiple column" menus are supported. Using two simple calls a full-screen data entry template may be loaded and a fully-titled data entry input screen may be created. Defaults, maximum field lengths, and numeric-only data are supported. --- The "perlmenu.pm" package uses curses interface routine calls supplied by the Curses extension for Perl5. A "menu.pl" package can be created which uses curses interface routine calls supplied by the "curseperl" package for Perl4. All functions and features are identical whether you are using Perl4 or Perl5. The "curseperl" package is distributed with the normal perl4 distribution in the "usub" directory. The "curseperl" binary is a complete perl interpreter with the addition of many "curses" routines dealing with screen manipulation (cursor positioning, display of text at the current cursor location, etc). Applications using "menu.pl" must be constructed to use "curseperl" instead of "perl". The "Curses" extension for Perl5 is maintained by William Setzer (of North Carolina State University). This package is available from any "CPAN" ("Comprehensive Perl Archive Network") site. Point your WWW browser to: http://www.perl.com/perl/CPAN/CPAN.html and look for "Curses" in the "User Interfaces" section. When writing Perl5/Curses programs make sure you include the following two lines at the start of your program (to initialize the Curses environment correctly): BEGIN { $Curses::OldCurses = 1; } use Curses; --- For menus, most applications using will use the following three calls (with the "menu_item" routine used multiple times to provide the menu selections) as follows: #!/usr/local/bin/perl5 BEGIN { $Curses::OldCurses = 1; } use Curses; use perlmenu; ... &menu_init(1,"Select an Animal"); # Init menu &menu_item("Collie","dog"); # Add item &menu_item("Shetland","pony"); # Add item &menu_item("Persian","cat"); # Add last item $sel = &menu_display("Which animal?"); # Get user selection if ($sel eq "%UP%") { ... } if ($sel eq "dog") { ... } ... When this code is executed, only the call to "menu_display" will actually cause the constructed menu to be displayed to the user for selection. The title is centered and displayed at the top of the screen in reverse video. The selection items are automatically numbered and presented in the order they were added. The prompt is displayed at the bottom of the screen preceded by an indication of how many of the items in the menu are presented on the current screen ("All" or some percentage). In the above example, the menu would look like: Select an Animal -> 1) Collie 2) Shetland 3) Persian (All) Which animal? Only one menu may be active at a time. In applications with "layers" of menus, only the "current layer" menu is maintained in memory. As you use the "up" function to "pop up" to a previous menu, your application must return to a subroutine (or upper program layer) that reconstructs the menu for that layer of the application and displays it. Since the lower layer used a "menu_init" to construct that menu, the "upper layer" must reconstruct the entire menu appropriate at that level. Support is provided (with proper programming of the application) to go directly to the "top" (first) menu and to remember the selection position in a previous menu. Many preferences can be set via a "menu_prefs" routine call to control the style of the selection cursor, the arrow-wrap and scrolling actions, single or multiple column menus, and various prompts, defaults, and other features. --- For full-screen data entry, most applications using will use the following two calls: #!/usr/local/bin/perl5 BEGIN { $Curses::OldCurses = 1; } use Curses; use perlmenu; ... @input_data = (); # Define a place to put the input data ... &menu_load_template("/path/to/template.file"); # Load template &menu_display_template(*input_data); When this code is executed, only the call to "menu_display_template" will actually cause the template to be displayed to the user for data entry. For example, assume the file containing the template looked like: Address Information Name: [_______________________________________________] Addr: [_______________________________________________] City: [______________________] State: [__] Zip:[_____] The call to "menu_load_template" would load and parse the template file for locations of text and data fields (data fields denoted by underscores). Optionally, the template can be loaded from a "template array", constructed within the Perl script itself. Templates stored in arrays (as opposed to files) are loaded with "&menu_load_template_array(...)". When "menu_display_template" is called, the user would see the following screen: Address Information Name: [ ] Addr: [ ] City: [ ] State: [ ] Zip:[ ] Field tabbing and insertion/deletion of text is handled by "menu_display_template" until the user hits "Return". Data values for each field are returned in $input_data[0] - $input_data[4]. Defaults, numeric-only, blanked, protected, and required fields are supported, along with the ability to parse and control user input while the "menu_display_template" is active via a user exit. -------------------------- Official Distribution Site -------------------------- The PerlMenu package is distributed via "CPAN" (the "Comprehensive Perl Archive Network"). Pick a CPAN site near you with a WWW browser pointed at "http://www.perl.com/perl/CPAN/CPAN.html" and go into the "authors/Steven L Kunz" folder. You should find "perlmenu.v4.0.tar.Z" in there. The author's official distribution is available via anonymous FTP from: ftp://ftp.iastate.edu/pub/perl/perlmenu.v4.0.tar.Z Other sites on the net may offer this package. New releases are announced in the Usenet Newsgroup "comp.lang.perl.announce". PerlMenu also has an official WWW page at: http://www.cc.iastate.edu/perlmenu/homepage.html ------------------------- Solicitation for Comments ------------------------- If you like "perlmenu.pm" (and "menuutil.pl") and have put it to a useful purpose, I would appreciate a few lines indicating where you are and what you are using it for. Likewise, if you have found a bug, documentation problem, or would really like to see a certain feature, feel free to let me know about those, too. Send your e-mail cheers/jeers to "skunz@iastate.edu". Lately I have been very far behind on responding to problem-questions such as "how do I make it do such-and-such", since other duties which my superiors deem more important (!) call. However, all suggestions, comments, and (if I am lucky) patches ARE saved. I eventually get around to responding when some free time pops up. -------------- Card of Thanks -------------- A big "thank you" to the following people who have taken time to notice some improvements that could be made in the PerlMenu code and mail them to me. Specifically: - Greg Kresko (National Research Council Canada) Found some problems with "endwin" statement placement (or lack thereof). Incorporated in the version 2.1 release. - Tim Goodwin Found a bug in the order of calls to "menu_exit_routine" and "menu_return_prep" when "quit" was processed. Incorporated into the version 2.3 release. - Steve Mitchell (CSU/Fresno) Found a bug in processing of "normal" applications (ones that do not call "menu_curses_application"). He suggested a fix for problems encountered on Sun and other System V systems relating to multiple calls to "initscr". Incorporated into the version 2.3 release. - Ian Phillipps (Pipex) Found a bug in the return value from "menu_init". It returned one too few for the number of items in the menu. Incorporated into the version 3.0 release. - Christopher Candreva (WestNet Internet Services of Westchester) Lots of improvements. Added menu_getstr defaults, max-lengths, and "noshow" support. Contributed "centered menu" code. Provided support code for template processing (menu_setexit, menu_getexit). Added "pre-selected" option to "menu_init" call. Provided idea for "menu_paint_file" loading code. - Jim Sumrall (Intel Corporation) Fixed some problems relating to Perl5 (subroutine calls with no parms called as "&rtn;" instead of "&rtn();"). Also added commented code for systems that use "tigetstr" (terminfo data) instead of "getcap" (termcap). - William Setzer (North Carolina State University) Mr. Setzer is the author of the Curses extension for Perl5 and provided valuable assistance in getting this package to work with his. - Alan Cunningham (NASA Spacelink Project) Alan supplied valuable input into the "real world" needs of the template data input facility. The "menu_display_template" user exit routines were developed with his feedback relating to an actual application. - Charles F. Randall (once with Iowa State University, ISUCC User Services) Charles ("Randy") supplied the code for the "emacs-similar" cursor movement/cut-paste control sequences to menu_getstr and menu_display_template. Last (but not least) a special "Thank you" to William Setzer of North Carolina State University, author of the Perl5 "Curses" extension. William has been very supportive in many ways in relation to my PerlMenu package on "Perl5". He has quickly answered my questions, provided pieces of code and suggestions, and even made mods to his package in support of mine. William has also taken the time to "beta-test" pre-release versions of the PerlMenu package to make sure "all is well" with his current release. Cooperation such as this has been key to making things work smoothly using PerlMenus and the "Curses" extension under Perl5. ------------------------------------- Initializing a new menu - "menu_init" ------------------------------------- Routine: menu_init Syntax: &menu_init(num_flag,"title string",top_flag,"sub-title str", "bottom-title str","item_help_routine_name"); Input args: - Boolean flag (0=unnumbered menu, 1=numbered menu). Required, no default. - Title string (string centered at top of menu). Required, no default. - Boolean flag (0=non-top menu, 1=top menu). Optional, defaults to zero. - Top Sub-title(s) string Optional, defaults to none. - Bottom title(s) string Optional, defaults to none. - Item-Help routine name string Optional, defaults to none. Returns: Window value from "initscr" call. The "menu_init" call resets the menu array and indexes. It must be called to reset/clear any old menu. The first parameter is a boolean flag indicating whether or not the menu should be numbered and have a selection arrow "->" provided (a non-zero value indicates a numbered menu). By default, the "title string" is centered at the top of the screen and presented in "standout" rendition (usually reverse video or bold). If the first character of the title is a dash ("-") then the title will be presented in "normal" rendition ("standout" will be suppressed). Title text that exceeds the width of the screen is automatically truncated on the right to fit the available width. The "top flag" is used to provide support for "top level" menus, discussed further in a later section of this document. The "sub-title string" is used to supply optional sub-title lines. Formatting is the similar to the main title string (centered, with a leading dash indicating normal rendition). However, a second format character is honored to indicate justification of the sub-title text on the screen. A "<" indicates "left-justified" and a ">" indicates "right-justified". This character can be combined with the "-" (indicating "normal rendition") provided it FOLLOWS the dash. Multiple sub-titles (each with it's own leading formatting characters) can be specified on one parameter if they are separated by "newlines" ("\n"). An example of a menu with three sub-titles would be: &menu_init(1,"Menu with sub-titles",0, "Centered\n-Right-justified"); Here the sub-title "Centered" will appear in "standout rendition" (no leading "-") centered on the second line of the menu (no "<" or ">"). The sub-title "Left-justified" will appear left-justified on the third menu line in "normal" rendition (due to the leading "-<"). The sub-title "Right-justified" will appear right-justified on the fourth menu line in "standout" rendition (no leading "-", but has ">"). Note that the "top menu" flat (the "0" as the third parameter in the "menu_init" call list) is required as a placeholder for the menu sub-titles). The "bottom title string" is used to supply optional bottom title lines. This string is formatted exactly like top sub-title lines (using the same rendition, justification and new-line characters). Bottom titles appear between the last line of the menu and the menu "prompt" line (the bottom line on the screen). Both top and bottom title strings can be loaded from a file using the "menu_paint_file" call (refer to the section on the "menu_paint_file" routine. Top sub-title and bottom title strings can be loaded dynamically (at menu display time) by specifying a routine call (which returns the title string) instead of the string itself. A routine is specified by supplying a string with "&" as the first character immediately followed by the routine name (same syntax as a routine call). In the above sub-title example, the following could have been used instead: [...] &menu_init(1,"Menu with sub-titles",0,"&make_subtitle"); [...] sub make_subtitle { local($title); $title = "Centered\n"; $title .= "-") in front of the item. One routine name can handle all items in a menu. This is because your routine is called with two parameters - the "selection text" and the "action_text" strings from the "menu_item" calls that created the menu. So, assuming you supplied an "item_help_routine_name" of "main_menu_help" on your "menu_init" call, your item help routine would look something like: sub main_menu_help { local($selection_text,$action_string) = @_; # Pick up the two parms if ($action_string eq "item1") { # Action text for item one # Display whatever help text for the first item } elsif ($action_string eq "item2") { # Action text for item two # Display whatever help text for the second item } &refresh(); $ch = &getch(); # Pause until keypress } Help on individual items is activated with a question-mark ("?") hot-key. Generic help on menus in general is activated with a "h" (or "H") hot-key. The default menu prompt (and generic menu help screen) automatically indicate if "item-help" is available on the current menu. For backward compatibility with previous versions, if no item help routine is provided, the generic menu help screen (defining what all the current "hot-keys" do) is provided when "?" is pressed. ------------------------------------ Adding items to a menu - "menu_item" ------------------------------------ Routine: menu_item Syntax: &menu_item("Selection text","action_text",preselection_mode); Input args: - Selection text (the string the user sees). Required, no default. - Action text (string returned if item is selected). Optional. Defaults to "". - Pre-selection mode 0 = Not selected, can be toggled 1 = Selected, can be toggled -1 = Locked out of selection process (but displayed) Optional, defaults to "not selected/can be selected". Returns: Current number of items in the menu. The "menu_item" call provides selection text (what the user sees on the screen) and "action_text" (not seen - but returned if that item is selected). There is no practical limit (other than memory or maximum array index size) on the number of items in a menu. The items are presented in the order you add them and the top (first) item is always the default (except when using the "latched" menu support outlined in a later section). Some "menu_display_" calls ("menu_display_radio" and "menu_display_mult") will automatically add a top item selection for you. Refer to those commands for more information. Selection text that exceeds the width of the terminal is automatically truncated on the right by the "menu_item" call. The "action_text" may be a null string (in which case a null string is returned upon selection). The optional pre-selection flag is useful only with "multiple selection menus" (calls to "menu_display_mult"). The default value (zero) indicates the item is available for selection. A "positive one" value indicates that the item is to be "pre-selected" (with an initial "[X]" indication) which the user may toggle off/on). A preselection value of "negative one" value is used to indicate a "locked out" selection (with an "[-]" indication) which the user cannot change. Locked out selections are merely placeholders on the screen and have no values returned (and cannot have their lockout indication cleared). This is useful for multiple menu-selection calls in which items selected for a list in a previous step should not be selected again. An example would be during the composition of a mail message where addresses selected for primary recipients should not be selected again for carbon-copies (but an indication that the address is already selected is desired). ----------------------------------------------------- Simple display/selection from a menu - "menu_display" ----------------------------------------------------- Routine: menu_display Syntax: $sel_var = &menu_display("Prompt text",$arrow_loc_row, $top_item,$arrow_loc_col); Input args: - Prompt text (string for bottom line). Optional, defaults appropriate for menu. - Item row on screen to place the arrow. Optional, defaults to zero (the first item). - Index of item to place at top of screen. Optional, defaults to zero (the first item). - Item column on screen to place the arrow. Applies to "multiple-column" menus only (ignored on single column menus). Optional, defaults to zero (the first item). Returns: "" or "%UP%" or "%EMPTY%" The "menu_display" call is the only call that actually writes data on the screen. When it returns you have one of the following strings: "%UP%" -- indicating the user did not select anything but pressed "u" (or possibly "t" - for "top menu", see below) to exit the menu. "%EMPTY%" -- indicating no calls were made to "menu_item" since the last "menu_init" call. "" -- one of the selection-action strings given on a "menu_item" call. You can either provide your own prompt as a call parameter to "menu_display" or you can provide a null string (&menu_display("")) in which an automatic prompt is provided. All paging functions are handled within the call to "menu_display" automatically. The last two arguments are used for "latched" menus, discussed in a later section. Support is provided for just simply typing the selection number of the item on the screen - you do not have to move the selection arrow to the item if you prefer to type the number (followed by "return"). The arrow ("->") displayed on the screen will automatically jump to the selection that is the "best fit" for what is typed so far. For example, if items 1-20 are currently on the screen, pressing a "2" will cause the arrow to jump to the "2)" selection. Typing "0" (to indicate "20") causes the arrow to next jump to the "20)" selection. A "return" key actually activates the selection. A "delete" or "backspace" key (or any cursor-movement key) clears the "direct entry" selection process at any time before "return" is pressed. One final note. The call to "menu_display" will ALWAYS turn back on echo - so if you really want it off you will have to call "noecho" again after each call to "menu_display". ---------------------------------------------------------------------- Displaying/selecting from a "radio button" menu - "menu_display_radio" ---------------------------------------------------------------------- Routine: menu_display_radio Syntax: $sel_var = &menu_display_radio("Prompt","current","Accept"); Input args: - Prompt text (string for bottom line). Optional, defaults appropriate for menu. - Current "action-text" deemed as "set". Any menu-item with this "action-text" will have the selection box X'd. Optional, if not set no selections will be set at start. - Text supplied for first item (which indicates selections are done. Optional, defaults to "(Accept this setting)". Returns: "" or "%UP%" The "menu_display_radio" call is similar to the "menu_display" call, except that it provides a "pushbutton radio" style of menu display which indicates the current setting (selection) in the menu while providing an opportunity to change it. A "radio button" menu uses the same "menu_init" and "menu_item" calls as any other menu. However, the "menu_display_radio" call produces a menu similar to the following example: Delete Confirmation -> 1) (Accept this setting) 2) [X] Ask permission first 3) [ ] Just do it (All) h)elp q)uit u)p t)op b)egin e)nd r)efresh Here a "button box" ("[ ]" is presented in front of the selection text indicating the current setting/selection. The user is given the opportunity to select another item (moving the "X" from box to box). When the desired setting/selection is set, item 1 (which is automatically provided for you by the "menu_display_radio" call) is selected and the menu function returns to the caller. You can override the default text for the item 1 selection on the "menu_display_radio" call. When it returns you have one of the following strings: "%UP%" -- indicating the user did not select anything but pressed "u" (or possibly "t" - for "top menu", see below) to exit the menu. "%EMPTY%" -- indicating no calls were made to "menu_item" since the last "menu_init" call. "" -- one of the selection-action strings given on a "menu_item" call. You can either provide your own prompt as a call parameter to "menu_display_radio" or you can provide a null string (&menu_display_radio("",...)) in which an automatic prompt is provided. All paging functions are handled within the call to "menu_display_radio" automatically. ------------------------------------------------------------------------- Displaying/selecting from a multiple selection menu - "menu_display_mult" ------------------------------------------------------------------------- Routine: menu_display_mult Syntax: $sel = &menu_display_mult("Prompt text","Done text"); Input args: - Prompt text (string for bottom line). Optional, defaults appropriate for menu. - Text supplied for first item (which indicates selections are done). Optional, defaults to "(Done with selections)". Returns: "" or "%UP%" or "%NONE%" The "menu_display_mult" call is similar to the "menu_display" call, except that it provides a multiple-selection style of menu display which returns the "" values in comma-separated string (instead of a single value variable). A multiple-selection menu uses the same "menu_init" and "menu_item" calls as any other menu. However, the "menu_display_mult" call produces a menu similar to the following example: Select one or more items -> 1) (Done with selections) 2) [X] Cat 3) [ ] Dog 4) [X] Goldfish 5) [ ] Mouse (All) h)elp q)uit u)p a)ll m)atch c)lear n)ext-pg p)rev-pg b)egin e)nd In this type of menu display the user can toggle selections on or off until the desired set is chosen. Indicating "(Done with selections)" results in the multiple-selection string being returned to the caller. When it returns you have one of the following strings: "%UP%" -- indicating the user pressed "u" (or possibly "t" - for "top menu", see below) to exit the menu. Note that even if they HAD selected something, returning from the menu with a "u" discards the selections. "%NONE%" -- indicating no items were selected by the user the last "menu_init" call. "" -- one or more of the selection-action strings (comma separated) given on a "menu_item" call. Typically, this string will be broken by the caller into individual items for processing by perl code similar to the following: $sel = &menu_display_mult(""); if ($sel eq "%UP%") { return; } if ($sel eq "%NONE%") { print "(You didn't select anything)\n"; } else { print "You selected the following:\n"; split(/[,]/,$sel); # Put return in @_ foreach (@_) { print " $_\n"; } } Note that you should normally be careful not to use commas on the "action text" portions of menu_item calls (UNLESS you know you want one item to be parsed out as multiple selections - a subtle "feature"). Certain items in a multiple-selection menu may be "pre-selected" (indicated as selected with "[X]") on the initial menu display if the menu was built with a "menu_item" call with the "pre-selection" option set. -------------------- "Top" Menu Support -------------------- There is limited support for "top" menus. By following a careful program structure you can allow the user to type a "t" at any menu display and have the next menu presented be the "top" (first) menu presented. This provides a convenient means for the user to jump to the top of a multiple-level menu structure from several menu-levels down. Since there is only one menu active at a time, pressing "t" to indicate the "top" menu merely generates an "%UP%" return from the current menu (refer to the "menu_display" call). However, top's "%UP%" return is different from a normal "u" up-action in that an internal flag is set so that all subsequent calls to ANY "menu_display" immediately return with an "%UP%" selection. This action continues until a menu is displayed that was initialized with a special flag in the "menu_init" call that indicates it is the "top" menu. Once a "menu_display" is called for a menu that has this special "menu_init" call, the "automatic %UP% return" stops and the "top menu" is displayed. This special "top menu" is initialized as follows: &menu_init(num_flag,"title string",1); # A "top" menu_init call The third parameter (a "1") indicates this is the "top" menu. The "top" menu support requires special care in programming. With careless programming you could enter a loop if a "t" was pressed and the Perl program provided no "top menu_init" call. To provide some level of protection, the "t" menu hot-key and "top" support is disabled automatically UNLESS the FIRST "menu_init" call is also a "top menu_init" call (indicating the software was programmed with "top" menus in mind). The "demotop" program distributed with this release of PerlMenus provides an example of correct usage of the "top menu" features. -------------------- "Latched" Menus -------------------- "Latched" menu support offers the ability to remember where you were in a menu when it is re-displayed later. This is often useful in traversing a menu-tree down and then returning to previous menus (and selection locations) when "popping back up" the tree (with the "up" hot-key). The only action necessary to remember position is the addition of three parameters on the "menu_display" call as follows: $sel_var = &menu_display("Prompt text",$arrow_loc_row_var, $top_item_var,$arrow_loc_col_var); These three values indicate the row location of the arrow line on the menu screen, the index number of the top "menu_item" on the menu screen, and the column location of the arrow line on the menu screen (item-column, not character position column). If you want the first item the first time, all these values should be initialized to zero (first item on the first page). This will generate the same action as if they were not specified - the default "non-latched" call. These optional parameters also are used to RETURN the value of the top item on a menu-page and arrow location AFTER the user selected something (and the "menu_display" routine returns). If you do not modify the three parameters, rebuild the menu the same way, and call "menu_display" supplying the returned values, the menu will be displayed in the original "selection" location. By letting "menu_display" store selection locations before moving to a lower level in your "menu-tree" (via a subroutine call to another menu-generator), a return from the lower level can regenerate any given levels menu and reposition the selection location automatically. Make sure you store your "latch" variables in "local" storage (one set for each menu-generator routine that has a "menu_display" call). One final note - the "menu_display" routine will check and automatically adjust the values to meet current menu limits. For example, if your menus are "dynamic" and items "disappeared" (making your last latch position off the end of the reconstructed menu), the "menu_display" routine will adjust to point to the the last item in the menu (adjusting the "top item" as needed). -------------------------------- Setting Overall Menu Preferences -------------------------------- A "menu preference setting routine" can be called at any time in your program to change how the menus are formatted and provide some control on what the user may do. This routine, "menu_prefs", has several positional parameters that let you control: - Justification (Left-justified or centered-on-the-screen menus) - Scrolling (line-by-line or page scrolling) - Whether the user may "quit" without selecting anything - What the "quit" prompt will be - What the default response is they see the "quit" prompt - The number of columns (Single-column or multiple-column selections) - The style of the selection cursor ("arrowed" or "highlighted" text) Refer to the "menu_prefs" routine in the next section for complete details. As an example, let us examine changing the number of columns used to display the selection text. Sometimes you may find you have a lot of items with small "selection text" strings to choose from. Examples would be two-character state codes for the United States, zip-code selection, etc. Rather than have these items "one per line" (the default action) and having the user scroll through several pages to make selection, it would be best to place as many on a page as possible. A call to "menu_prefs" is all that is needed, changing the "multiple column" preference. One example would be: &menu_prefs(0,0,0,"","",1,0); The second-to-last parameter ("1") is the one that indicates "do multiple column menus from now on". Nothing needs to be changed at all in any portion of your program that originally built and displayed the menu. Setting the multiple column preference will cause the menu routines to automatically scale the size of the columns based on the size of the LONGEST selection text. As many items as possible will be packed on each line without truncation. As a result, a menu that looked like this: Long Menu (fits on several pages) -> 1) (Exit) 2) Item 2 3) Item 3 4) Item 4 5) Item 5 [...] suddenly looks like this with only a "menu_pref" call change in your program: Long Menu (fits on several pages) -> 1) (Exit) 2) Item 2 3) Item 3 4) Item 4 5) Item 5 6) Item 6 7) Item 7 8) Item 8 9) Item 9 10) Item 10 11) Item 11 12) Item 12 13) Item 13 14) Item 14 15) Item 15 16) Item 16 17) Item 17 18) Item 18 19) Item 19 20) Item 20 21) Item 21 22) Item 22 23) Item 23 24) Item 24 25) Item 25 [...] Of course you can change the preferences to different values before and after each menu you construct (if you want to mix single and multiple column menus in one application). ----------------------------------------- Other Menu-Related "perlmenu.pm" Routines ----------------------------------------- -------- Routine: menu_curses_application Syntax: &menu_curses_application(initscr_window); Input args: Window value returned from your call to "initscr" Returns: Main window value. COMPATIBILITY NOTE: Prior to version 3.0 of PerlMenus this routine did not require the passing of the window value returned from your call to "initscr". As of version 3.0 you SHOULD provide the window value. If perlmenu.pm has not gotten the value of the main window itself, it must be told what you are using. If you do not pass the "initscr_window" value, this routine will perform an "initscr" call to make sure it has a "stdscr" window value. It is assumed that the application calling the menu routines is not a "Perl+curses" application (i.e. it is a "stock" perl script except for calls to PerlMenu routines). However, if you are writing an "all-curses" application (calling curses functions from your routines) you should call "initscr" (to init the curses environment) and pass the value returned to "menu_curses_application". This set of actions need only be done ONCE (at the beginning of our program). The call to "menu_curses_application" saves the window value for subsequent use and sets a flag so that the "initscr" and "endwin" calls are NOT done by the PerlMenu package calls. You should make sure you issue an "endwin" call prior to exiting. On some systems it has been reported that there is "screen flicker" between menu calls. The screen may appear to clear, flash an old screen briefly, and then paint the new menu. This may be due to the fact that PerlMenu by default will issue an "initscr" and "endwin" call around every menu display. If this causes "screen flicker" on your system, make sure you code your application with a call to "initscr" and pass the value to the main window as follows: use perlmenu; $window = &initscr(); &menu_curses_application($window); ... (the rest of your program) ... &endwin(); exit(0); This technique will probably not help things on some Sun systems (which appear to have shortcomings in their "curses" library routines). -------- Routine: menu_getstr Syntax: $str_var = &menu_getstr(row,col,"prompt text",clear, "Default string",max_len,hidden, data_type,window); Input args: - Row and column for input of data. (Required) - Prompt text Optional. Defaults to "no prompt". - Boolean flag (0=no-clear, 1=clear-after-user-entry) Optional. Defaults to "no-clear". - Default-value string. Optional. Defaults to "no default value". - Maximum string length. Optional. Defaults to right edge of screen. - Boolean flag (0=show, 1=hidden). Optional. Defaults to "show". - Data type (0=alpha-numeric, 1=numeric). Optional. Defaults to alpha-numeric. - Window (used mainly by template routines). Optional. Defaults to base screen window. Returns: String (may be null) This is a utility routine written for "match string" prompting (on multiple-selection menus) and data field input (on menu template input) that proves useful in any perl-based curses application. The row and column of a position on the screen where you want to input text is supplied (with an optional prompt). Character entry is allowed from the right edge of the prompt to the right edge of the screen (or for the maximum number of characters allowed). The left and right cursor keys may be used to move within text already typed in, with the cursor location being an "insert/delete" point. This allows for C-shell-like data entry. A special case is provided for "single character" string entry (calling "menu_getstr" with a maximum string length of one). Only in this case will "menu_getstr" function in "overstrike" mode. The user does not need to delete a character first to replace it with another. This is useful for one-character fields such as "Is this correct? [Y]". A few "emacs-similar" control sequences are available to the user when they are editing within a "menu_getstr" call as follows ("^" indicates pressing the "CONTROL/CTRL" key, "^A" meaning "CNTL-A", etc.): ^A - Move to the first character ^E - Move to after the last character ^F - Move to the next character (same as "right cursor") ^N - Move to the next field (same as "tab") ^P - Move to the previous field ^B - Move to the previous character (same as "left cursor") ^D - Delete the character at the cursor (shifting in any text at the right) ^K - Delete (and "cut" into paste-buffer) text to the right (emacs "Kill") ^U - Paste text in paste-buffer at the cursor (emacs "Yank") Note that the "paste text" function is NOT the same control sequence used by emacs (which uses "^Y"). This will be confusing to emacs users, but currently the "^Y" function is processed as "terminal STOP". The call to "menu_getstr" will ALWAYS turn back on echo - so if you really want it off you will have to call "noecho" again after each call to "menu_getstr". -------- Routine: menu_help_routine Syntax: &menu_help_routine("routine_name"); Input args: String with name of routine to be called. Required, no default (Null value of "" allowed). Returns: Nothing. The menu routines have a default generic help screen that is displayed if the user presses "h" while a menu is displayed. This screen explains how to use the menu and the current active "hot-keys". Calling "&menu_help_routine("rtn_name");" will cause the specified routine to be called instead on the default routine. Providing a new generic help routine applies to ALL menus from that point on. You may revert back to the default generic help screen at any time by supplying a null value for the "routine_name" in the call (&menu_help_routine("");). -------- Routine: menu_paint_file Syntax: &menu_paint_file("/filename/path",top_bottom_flag); Input args: - Path to file to use as headers Required. - Position flag (0=top sub-titles, 1=bottom titles) Optional. Defaults to "top sub-titles". Returns: 0=Success, 1=Cannot open file. This is a "shorthand" method of load large blocks of text to be used as menu sub-titles and/or bottom titles. Format each line of text with the same two formatting characters as specified on titles in the "menu_init" call. If not formatting characters are present on a line the default action (centered, standout rendition) will be used. If titles are specified on both the "menu_init" call AND a subsequent "menu_paint_file" call, the "menu_paint_file" will replace the "menu_init" titles. The "menu_paint_file" call must appear AFTER the "menu_init" call and BEFORE the "menu_display" call. A "menu_init" call will erase any previously loaded titles. -------- Routine: menu_prefs Syntax: &menu_prefs(centered_menus,gopher_like,disable_quit, quit_prompt,quit_default,multiple_cols, selection_cursor_type); Input args: - Flag indicating centered menus are desired. - Flag indicating more gopher-like arrow functions desired. - Flag indicating "q" ("quit") is not a valid hot-key. - String with prompt to use in place of the "Do you really want to quit?" prompt. If a null string is supplied, the default string will be used. - A single character string which can be "y", "Y", "n", or "N". This value is used as the default response on the "quit" prompt. Any value other than those listed results in the default reverting to "y". - Flag indicating single-column or multiple-column menus. - Flag indicating selection cursor type (arrowed or highlighted). Returns: Nothing. If the "centered_menus" flag is non-zero all menus will be centered on the screen. If the "gopher_like" flag is non-zero the effect depends on whether "single column" or "multiple column" menus are preferred (see below). For "single column" mode the left-arrow key will act as a "u" ("up") hot-key and the right arrow key will act as a "return" hot-key. Normal action (for "single column" mode) is that left-arrow acts like an up-arrow and the right-arrow acts like a down-arrow. For "multiple column" mode the left-arrow and right-arrow keys are used to move between columns. In addition (for either single or multiple column modes), the scrolling action of menus when the arrow keys are used to move up from the top item or down from the bottom item changes to a more "gopher-like" paging action. Wrapping from the first page to the last page is also activated. If the "disable_quit" flag is non-zero the "quit" hot-key is disabled. Pressing "q" will do nothing (and the "quit" function will not appear on the help screen for menus). If the "multiple_cols" flag is non-zero multiple selection items will be placed on each line of the menu (filling each line left-to-right column-wise first, then moving to the next line, etc). The number of items on each line (and width of each column) is computed automatically by using the length of the LONGEST selection text in the menu and dividing it into the width (in characters) of the screen. For very short selection texts on "radio" or "multiple selection" menus you may want to change the default "first item" text (on the "menu_display_radio" and "menu_display_mult" calls) to shorter values since this item may turn out to be the longest selection text (and therefore limit the number of items you can pack on single line). No provision is made to specify an explicit number of items per line or the column width (although you can somewhat control this by padding the maximum selection text length for an item). The display of items in ascending columns (filling all rows on the left column first, then moving to the next column, etc.) is NOT supported. If "menu_prefs" is never called the following defaults are set: - Left-justified (non-centered) menus - Non-gopher-like right/left arrow keys - "Quit" is a valid menu hot-key. - The default "quit" prompt is "Do you really want to quit?" - The default prompt to the "quit" question is "y" - Single-column menus - "Arrowed" selection cursor ("->" in front of item) These defaults match previous releases of the PerlMenu system. -------- Routine: menu_quit_routine Syntax: &menu_quit_routine("routine_name"); Input args: String with name of routine to be called. Required, no default. Returns: Nothing. The menu routines will process a "q" for "quit" locally. In other words, if the user presses "q" while a menu is displayed (and responds to the "Do you really want to quit?" prompt with a "y") the perl program will immediately exit. However, support is provided for a "user" exit that will be called just before dropping out the program (to perform any "cleanup" duties). Calling "&menu_quit_routine("rtn_name");" will set the exit routine. -------- Routine: menu_setexit menu_getexit Syntax: &menu_setexit(@seq-array); $val = &menu_getexit; Input args: menu_setexit - Array of exit sequences to look for. menu_getexit - None. Returns: menu_getexit returns the last exit sequence (so you can decide what to do based on what it was) These routines are used to provide a "hook" into the menu_display and menu_getstr routines to provide a means of detecting more than one keystroke (or key sequence) to cause a return. This is used primarily within the menu_display_template routine - but you may have other uses for it. For example, the following could be used to allow the "Tab" or "?" keys to exit a menu (or menu_getstr): $exit_array[0] = "\t"; $exit_array[1] = "?"; &menu_setexit(@exit_array); After the menu returns you would use "menu_getexit" to retrieve the type of sequence that caused the exit and process accordingly. -------- Routine: menu_shell_command Syntax: &menu_shell_command("shell-path"); Input args: String with command to issue to spawn a shell ("/bin/csh", for example). If null, ability to use "!" from a menu to get a command prompt is disabled (the default condition). Returns: Nothing. If you want to give your users the ability to suspend the perl menu program at any menu and spawn off a subshell (and get a command prompt), you can issue this call with the shell-path as the argument. When any menu is displayed, a user can press the exclamation point ("!") and get a command prompt. Exiting the shell re-displays the menu exited from and continues processing. Many systems have an environment variable indicating the current shell such as "SHELL". If so, the best way to activate this ability is to issue a command such as "&menu_shell_command($ENV{"SHELL"});" early in the program. Shell-escaping can be disabled by issuing the command with a null string as the argument (reverting to the default mode). ----------------------------------- Templates -- Full Screen Data Entry ----------------------------------- The PerlMenu package contains a facility to allow data-entry from formatted multiple-field full-screen definitions. Definition of the screens is extremely simple and can be done with any full-screen text editor. In essence, you edit the screen exactly as you want it to look (including spacing and titles) and denote data entry fields with special characters. Once a data-entry template file is defined two menu calls are used - one to load the template and a second to perform actual data entry. ------------------- Defining a template ------------------- A template is defined by editing a file (called the "template file") using any text editor (a full-screen editor is best since you can see what the final result is like while you are editing the file). Any text is presented on the data-entry screen exactly as it appears in the file (on the same row and column). Data entry fields are denoted by the following special characters: underscore ("_") -- Alpha-numeric data back-slash ("\") -- Numeric-only data caret ("^") -- Hidden (password-style) data The data entry "field characters" cannot be redefined for use on screen headings (but you can still place them on the screen with a "template overlay", discussed later). Blanks (or other characters) are used to denote field separators. There is no software-imposed limit on the number of fields (unless you have memory constraints). The following is an example of a template for name/address/phone information: Address Data Example Record # ___ Name: [_____________________________________________] Addr: [_____________________________________________] City: [__________________] State: [__] Zip: [\\\\\] Phone: (\\\) \\\-\\\\ Password: [^^^^^^^^] Enter all information available. Edit fields with left/right arrow keys or "delete". Switch fields with "Tab" or up/down arrow keys. Indicate completion by pressing "Return". In this example the "Zip" and "Phone" fields are numeric. The "Password" field is "hidden" (entered text appears on the screen as "*"s). All remaining fields are alpha-numeric. When the template is displayed the screen is cleared and the data-entry template is displayed "as-is" EXCEPT that the data-entry field characters (underscores, back-slashes, and carets) are replaced by spaces. The user is only allowed to enter data (and tab between) the data-entry areas. Note that the brackets are useful to delimit the bounds of the data areas to the user but are not necessary (as apparent in the "Phone" field). Also note that the "Phone" field is actually three separate fields which must be re-assembled (if required) later. This template could have also been written as "Phone: ____________" for less strict formatting (losing some validation in the process). You should make sure that when formatting a template your full screen editor does not rely on tabs for the positioning of text on the page. The template processing routines will not process tabs in the template file properly. Make sure all tabs are expanded to blanks by your editor. --------------------------------------------- Loading a new template - "menu_load_template" --------------------------------------------- Routine: menu_load_template Syntax: &menu_load_template("/filename/path"); Input args: Path to the template file. Returns: 0=success, 1=Cannot open file This routine opens the template file, processes it (detecting the location of the data-entry fields), and returns. All template overlays (normal and "sticky" are cleared. No data is displayed on the screen. If you are performing multiple entry tasks (i.e. looping while calling "menu_display_template" many times, using the same template) you need only call "menu_load_template" once. Multiple calls to this routine are only needed if you want to switch templates. It is not possible to denote "standout" rendition fields in a template file. However, you may leave blank areas and use a "template overlay" to place text in them later with "standout" rendition. Refer to the "menu_template_overlay" routine section for more details. ----------------------------------------------------------------- Loading a new template from an array - "menu_load_template_array" ----------------------------------------------------------------- Routine: menu_load_template_array Syntax: &menu_load_template(@template_array); Input args: Array which defines the template. Returns: 0=success In some cases, it is more convenient to keep the templates in the source file, instead of using separate template files. A template could for instance be declared by a "here-is" string, or it could be built at run-time. This routine uses an array for the template, one element in the array corresponding to one line of output in the template, and otherwise processes it exactly as "menu_load_template". An example: &menu_load_template_array(split("\n", <<'END_OF_TEMPLATE')); Address Information Name: [_______________________________________________] Addr: [_______________________________________________] City: [______________________] State: [__] Zip:[_____] END_OF_TEMPLATE ------------------------------------------------------------------------ Getting user input from a full-screen template - "menu_display_template" ------------------------------------------------------------------------ Routine: menu_display_template Syntax: &menu_display_template(*entered_data,*defaults,*protected, "exit_routine",*required); Input args: - Pointer to array to load with user data. Required. - Pointer to array containing defaults for all fields. Optional (defaults to "no defaults"). - Pointer to array containing protection status for all fields. Optional (defaults to "all unprotected"). - Name of exit routine to call between field tabs and on signal of completion ("Return");. Optional (defaults to no exit routine). - Pointer to array containing required-field status for all fields. Optional (defaults to "none required"). Returns: 0=Success (entered_data array loaded), 1=No template loaded This routine uses a previously-loaded template (loaded with the "menu_load_template" call) and presents the user with a formatted multiple data field screen. The user may use the Tab or down-arrow keys to move forward to the next field on the screen. Moving to a previous field is done with the "up-arrow" key. When within a field normal editing can be performed as with any "menu_getstr" call. The character insertion/deletion point can be changed with the left/right arrow keys. Maximum lengths of fields are enforced. If a field is denoted in the template as "numeric only" the terminal will sound a bell if a non-numeric character struck. It is important to note that the first three (and fifth) parameters to this routine are POINTERS, and are not arrays "passed by value". Declare the arrays in your own program ("@entered_data = ();") and use the pointer in your call to "menu_display_template" as in: &menu_display_template(*entered_data); This routine processes all fields in row/column order and returns the values after user entry (i.e. after they have entered as much data as they choose in all fields) and press "Return". The values are returned in the "entered_data" array. The first field is in array position $entered_data[0], the second in $entered_data[1], etc. If the user entered no data in a field (and there was not default) the value in the array will be null (""). Defaults are supplied using the "defaults" array (of string values). Supply the default string for each field in the proper array location. Defaults for all fields are displayed on the screen the user sees. If no default for a field is provided, load the default array at that position with a null ("") value. Protected fields are denoted using the "protected" array (of boolean values). For each field on the screen you want protected (unable to alter, auto-skipped over during field switching operations) you place a one (1) in the array index for the field. Place zeros in all other positions. You MAY protect fields that have DEFAULT values (allowing you to supply variable data in a default that the user cannot change). You may create a "display only" template to display data in fields by marking ALL fields protected. In this case the template (with data field text supplied in the "defaults") will appear with the cursor in the upper-left corner. Any keypress will exit the "menu_display_template" call. Required fields are denoted using the "required" array (of numerical values). For each field on the screen that is required (i.e. a null value is not allowed) you place a number in the array index for the field. Place zeros in all other positions. The number placed in the position is the character offset of the LAST character of the LEFT marker and the FIRST character of the RIGHT marker from the left and right edges of the required field. This "offset" is used to allow you to denote fields with label or edge markers in your template and not have the required field markers overlay it. Both right and left "required field markers" are supported, although only a "left required field marker" of an asterisk ("*") is provided by default. For example, if your array of required fields is called "REQUIRED", and fields zero and three are required, assigning "2" to $REQUIRED[0] and $REQUIRED[3] will cause an asterisk to be overlayed on the template two characters to the left of the field. The user will not be able to press RETURN and exit the template until all fields marked as "required" have data in them. The template routines will automatically clear the "required field markers" from the screen as values are supplied (and the user hits RETURN). Support is provided for "right edge required field markers" (which are normally disabled) and changing the strings used for the markers. The rendition ("standout" as opposed to "normal") can also be changed. These functions are controlled via the "menu_template_prefs" call. Refer to the "menu_template_prefs" routine documentation for more details. If you want a message displayed emphasizing the fact that required fields are not filled in (and are marked for the user) it must be done in an "exit routine" using a "template overlay" (you check the count of required fields remaining to be filled in to decide whether you need the message or not). The optional "exit routine" is used to gain control each time a field tab ("Tab" or up/down arrows) or "Return" key is pressed. A string containing the name of the exit routine in your code is supplied on the call. When this routine is called (from within "menu_display_routine") the calling parameters (to YOUR routine) are: - A value indicating the direction the user moved: -1 = Tabbed to previous field 0 = Pressed "Return" (no movement) 1 = Tabbed to next field - The index of the field just left (or where "Return" was pressed) - The index of the field about to be entered (same as the field just left if "Return" was pressed). - The number of required fields which still remain to be filled in. When you return from your exit routine you must supply a return value which indicates to "menu_display_template" whether or not you want it to exit (and return to the caller) at this time (and what field you want the cursor placed at if you are not exiting). A non-negative return value indicates "continue data input" (regardless of whether "Return" was pressed by the user or not). The non-negative value is used as the index of the field in which you wish the cursor placed when "menu_display_template" resumes processing. In this way certain processing (such as validating data in fields) can be done by an exit routine when the user indicates data-entry is done. If unacceptable data is found in a field, error messages can be overlayed on the template using the "menu_overlay_template" calls (discussed in the next major section). You should supply the index of the first field with data errors as the return value, which places the cursor on the field with the error for the user. A negative return value indicates "return now" (even if it was just a "field tab" exit routine call). However, there are actually two "negative return values" to consider as follows: -2 indicates "return now" unconditionally (even if all required fields are not filled in). This return value is generally used to abort data entry when using the "required fields" support. Data from fields already filled in is not flushed. The only difference between this value ("-2") and a "-1" is that the check for required fields being filled in is bypassed. -1 indicates "return now" ONLY IF all required fields are filled in. If there are required fields that still need data, the subsequent action taken by "menu_display_template" is to position the cursor on the first required field not filled in. This return value is also the return value to be used if you are not using the "required field" support and wish to "return now" from "menu_display_template" (indicating all data entry is correct and complete). Syntax for a typical exit routine would look like: sub exit_routine { local($direction,$last_field_index,$next_field_index,$still_req) = @_; if ($direction) { return($next_field_index); } # Tab, go to at next field # Must have pressed "Return" &menu_overlay_clear(); # Clear old overlays if ($still_req) { &menu_overlay_template(20,1, "Fields marked with \"*\" are STILL required"); return(-1); # Position at first null required field } if ($all_ok) { return(-1); } # Allow user to be done else { [...] # Construct menu_overlay_template calls to denote errors return($index); # Re-display (at some field) with overlays } } Menu exit routines are not available when all fields are protected (and it is a "display only" template). A few "emacs-similar" control sequences are available to the user when they are editing within a "menu_getstr" call as follows ("^" indicates pressing the "CONTROL/CTRL" key, "^A" meaning "CNTL-A", etc.): ^A - Move to the first character ^E - Move to after the last character ^F - Move to the next character (same as "right cursor") ^N - Move to the next field (same as "tab") ^P - Move to the previous field ^B - Move to the previous character (same as "left cursor") ^D - Delete the character at the cursor (shifting in any text at the right) ^K - Delete (and "cut" into paste-buffer) text to the right (emacs "Kill") ^U - Paste text in paste-buffer at the cursor (emacs "Yank") ^L - Refresh the screen Note that the "paste text" function is NOT the same control sequence used by emacs (which uses "^Y"). This will be confusing to emacs users, but currently the "^Y" function is processed as "terminal STOP". ---------------------------------------------------------- Handling Titles/Data-entry Errors - Template text overlays ---------------------------------------------------------- There may be times when you want special "standout rendition" titles or when you want to overlay special instructions for certain records. Data entry errors in fields may require a re-display of the current screen with a textual overlay of the template with a suitable error message. These actions are achieved with "template overlays". Template overlays are created with one or more calls to "menu_template_overlay", specifying text and the row and column location of where the text should start. You may specify any number of overlay areas at different locations on the screen. Overlays can be created in "standout rendition" and may be designated as "sticky" (meaning they normally will not clear with other overlays). A "sticky" overlay area is normally only used for "standout rendition" title areas (more or less "permanently attached" to the currently loaded template). Normal overlay areas are cleared by calling "menu_clear_overlay(0)". ALL overlay areas (including "sticky" ones) are cleared by calling "menu_clear_overlay(1)" (or by loading a new template with "menu_load_template"). Data entry errors can be corrected in two manners. The first (and simplest to code) involves multiple calls to "menu_display_template". When errors are detected upon return from "menu_display_template, the "defaults" array is loaded with the previously returned values in the "entered_data" array. Then, prior to calling "menu_display_template" again, "menu_load_overlay" is called to create an error message overlay on the screen. A subsequent call to "menu_display_template" re-displays the old data (with the error message on the screen) and allows the user to correct any values. While simpler to program, this technique means the entire screen is re-displayed each time errors are detected and new data is requested. A more complex (but screen I/O efficient) way to correct/detect errors is to use a "template exit routine" (described in the previous section). Template overlays can be created and cleared within a template exit routine. In this manner a single call to "menu_display_template" and a well designed exit routine can validate all fields and exit only when required values of the proper format are provided. The exit routine can also place error messages on the screen and position the cursor on specific fields, with only the changed areas of the screen refreshed as necessary. ---------- Routine: menu_overlay_template Syntax: &menu_overlay_template(row,col,"Overlay text",rendition, sticky); Input args: - Row, Column position to start the overlay. Required. Must fall within current screen boundaries. - Text to overlay the template with Required. Must be non-null. - Rendition (0=normal, 1=standout). Optional. Defaults to "normal". - Sticky flag (0=normal, 1=sticky) Optional. Defaults to "normal". Returns: 0=Success, 1=No template loaded or invalid data (row,col must be on screen and text must be non-null) This routine places the specified text on the screen for all subsequent calls until "menu_overlay_clear" is called (or a new template is loaded with "menu_load_template". The entire string is displayed in standout rendition if the rendition flag is non-zero. "Sticky" overlay areas are not cleared by "menu_overlay_clear" unless it is called with the "clear sticky areas" flag. Note that text overlayed on top of data input fields appears on the screen but will NOT be returned back as user-entered data on the "menu_display_template" call. Overlays are not a method for providing default data in data entry fields (you must use the "defaults" parameter on the "menu_display_template" call. ---------- Routine: menu_overlay_clear Syntax: &menu_overlay_clear($clear_sticky); Input args: Flag to indicate whether or not to clear the "sticky" overlay areas. Optional. Defaults to "don't clear sticky areas". Returns: Nothing By default, this routine clears all "non-sticky" loaded template overlay text. If the "clear sticky" flag is non-zero, the "sticky" overlay areas are cleared, too. For each field cleared the text which was placed on the screen is overwritten with blanks. ----------------------- Other template routines ----------------------- ---------- Routine: menu_template_prefs Syntax: &menu_template_prefs(left-mark-set,left-mark-clear,left-attr, right-mark-set,right-mark-clear,right-attr); Input args: Character strings denoting character strings to overlay on on the template to denote "required fields". Defaults are: left-mark-set "*" left-mark-clear " " (blank) left-attr 0 (normal rendition) right-mark-set "" (null-string, disabled) right-mark-clear "" (null-string, disabled) right-attr 0 (normal rendition) Returns: Nothing This call is used to provide alternate ways of denoting required fields during a call to "menu_display_template". By default only "left edge" required field markers are supplied and they are denoted with an asterisk ("*") in normal rendition. Any character string may be used to mark either (or both) edges of a required field, and separate strings may be inserted after a required field is supplied (and the marker "cleared"). The length of the string is accounted for in positioning it so the proper offset is maintained between the marker and the field. It is the Perl programmer's responsibility to make sure the marker offset values (provided in the "required" array) and the length of the strings used position the markers at the proper place on the template (and don't wrap at the edges). Only the rendition of the "marker set" string can be changed. The "marker clear" strings are always in "normal" rendition. For example, assume a required field "$FIELD[0]" is denoted on the template as: Name: [__________________] To change the left required field marker to "REQ->", activate the right required field marker (making it "<-REQ"), the following call would be used: &menu_template_prefs("REQ->"," ",0,"<-REQ"," ",0); $REQUIRED[0] = 2; # Offset two (so "[" and "]" are not overlayed) &menu_load_template(...); &menu_display_template(...,*REQUIRED); Produces the following when the template is displayed: Name: REQ->[ ]<-REQ ---------- Routine: menu_template_setexit Syntax: &menu_template_setexit(@exitseq); OR &menu_template_setexit("seq1","seq2",...); Input args: Array or list of character strings holding characters (or sequences of characters) which cause "menu_display_template" to exit. Optional. Defaults to "no additional sequences". Returns: Nothing This call is used to provide alternate ways of exiting from the call to "menu_display_template". By default only "Return" causes the termination of data input by the user. By using "menu_template_setexit", additional "escape sequences" or control keys can be defined to allow return. By using the "menu_getexit" call (see "Other Menu-Related PerlMenu Routines") the actual key(s) used can be interrogated and subsequent program action taken accordingly. For example, you could define "Control-X" as an additional exit sequence with "&menu_template_setexit("\cX");" to indicate "discard the data just entered" (to allow a user to abort the data entry process). After you return from menu_display_template you would use "if (&menu_get_exit eq "\cX") ..." to check if the exit sequence that cause you to return was "Control-X" and discontinue processing of the data. --------------------------- Template data entry example --------------------------- The following is an example of a full-screen data entry program using the name/addr/phone template used as an example above. This program includes all features available. Note especially the use of the "field default" array combined with the "field protection" to create a record number field with default data (the current record number) that cannot be modified by the user. Both types of error detection/correction are used. This program can be found in the PerlMenu distribution, as the file "demo_template". ---------- #!/usr/local/bin/perl5 BEGIN { $Curses::OldCurses = 1; } use Curses; use perlmenu; # Main menu package require "./menuutil.pl"; # For "pause" and "print_nl" routines @input_data = (); # Place to put data entered on screen @defaults = (); # Default data @protect = (); # Protected markers @required = (); # Required field markers $bell = "\007"; # Ascii bell character $row = $col = 0; # Storage for row/col used by menuutil.pl # # Since we are not using menus in this example, we need to call "menu_init" # to initialize the curses environment. Not necessary if you have at # least one menu display (which will include a menu_init) first. # &menu_init(); # # Activate left and right markers, both in standout rendition. # &menu_template_prefs("*"," ",1,"*"," ",1); # # Load the template from the data file (created with a text editor) # Data entry fields denoted by underscores ("_") or back-slashes ("\"); # &menu_load_template("./template_data"); &menu_overlay_template(0,28,"Perl Menu Version 4.0",1,1); &menu_overlay_template($LINES-5,10, "Fields between \"*\" are required.",1); # # Define "Control X" as "stop" # &menu_template_setexit("\cX"); # # Set defaults for all records the same in this example. # For record updating you would set the defaults to the existing values # from an old record. # $defaults[0] = 0; # Record number $defaults[1] = "Sample name"; # Name $defaults[2] = "Sample address"; # Addr $defaults[3] = "Sample city"; # City $defaults[4] = "IA"; # State $defaults[5] = ""; # Zip $defaults[6] = ""; # Phone - area code $defaults[7] = ""; # Phone - first three digits $defaults[8] = ""; # Phone - last four digits $defaults[9] = "Barney"; # Password # # Set protected fields for all records in this example. # This lets us supply a record number as a default in the first field but # not allow the user to change it. # $protect[0] = 1; # Record number (protected, filled in by call parm) $protect[1] = 0; # All remaining fields are unprotected $protect[2] = 0; $protect[3] = 0; $protect[4] = 0; $protect[5] = 0; $protect[6] = 0; $protect[7] = 0; $protect[8] = 0; $protect[9] = 0; # # Set required fields for records in this example. # Note that the offset value is "2" to prevent overlaying the "[" # on the template. # $required[0] = 0; $required[1] = 2; # Name $required[2] = 0; $required[3] = 0; $required[4] = 0; $required[5] = 0; $required[6] = 0; $required[7] = 0; $required[8] = 0; $required[9] = 2; # Password # # Input three records # for ($i = 1; $i <= 3; $i++) { $defaults[0] = $i; # Set the record number in the protected field # IMPORTANT: Note the use of pointers to arrays here &menu_display_template(*input_data,*defaults,*protect,"template_exit", *required); last if (&menu_getexit() eq "\cX"); # Demonstrate a template overlay the first time if ($i == 1) { @bad_data = @input_data; # Reload the data we just got &menu_overlay_template($LINES-5,10,"This is a template overlay.$bell"); &menu_overlay_template($LINES-4,10,"(It could be an error message)"); &menu_overlay_template($LINES-3,10, "Note that the data is from the previous screen."); # Let them reenter data &menu_display_template(*input_data,*bad_data,*protect,"template_exit", *required); &menu_overlay_clear(); last if (&menu_getexit() eq "\cX"); } # Display what we got the last time &clear(); $row = $col = 0; &print_nl("Record #$i",1); &print_nl("Here is what was returned in \@input_data:",2); for ($j = 0; $j <= $#input_data; $j++) { &print_nl("\$input_data[$j]: $input_data[$j]",1); } &pause(""); } &clear(); $row = $col = 0; &refresh(); exit(0); #********** # TEMPLATE_EXIT - Exit routine for "menu_display_template" #********** sub template_exit { local($direction,$last_index,$next_index,$still_required) = @_; # Return now if they are skipping between fields if ($direction) { return($next_index); } # They pressed "Return". &menu_overlay_clear(); # Clear any old overlays # Put out message if there are still required fields. if ($still_required) { &menu_overlay_template($LINES-5,10, "Fields preceded with a \"*\" are STILL required.",1); return(-1); # Still need required field(s) - auto-position } # Let them be done. return(-1); } ---------- This program inputs three records, displaying the result after each data entry panel is processed. An exit routine is used to make sure the "Name" field is supplied on all records. After entry of the first record, the data is re-displayed with an error message overlay with the previous screens data supplied as defaults. Of course a "real" program would process the entry-array into a database record and update it. When updating existing records the "defaults" would be the current record's field contents. -------------- For the record -------------- PerlMenu - Perl library module for curses-based menus & data-entry templates Copyright (C) 1992-97 Iowa State University Computation Center This Perl library module is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License (as published by the Free Software Foundation) or the Artistic License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. perlmenu-4.0.orig/README100660 1750 1750 15242 6301157745 15026 0ustar jgoerzenjgoerzen perlmenu.pm PerlMenu Package Version 4.0 February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa PerlMenu - Perl library module for curses-based menus & data-entry templates Copyright (C) 1992-97 Iowa State University Computation Center Ames, Iowa (USA) This Perl library module is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License (as published by the Free Software Foundation) or the Artistic License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -------- Overview -------- The "perlmenu.pm" package is a Perl5 package (built into your Perl program with a "use perlmenu.pm" command) that automates curses-based full screen menus and data entry. It also functions under Perl4/curseperl. Using three simple calls, any number of items may be selected from a single or multiple-page menu by moving an arrow to the desired item (or directly entering the selection number displayed on the screen). In addition to simple "single one-shot selection menus", "radio button" style menus and "multiple-item-selection" menus are provided. Paging through multiple-page menus is handled automatically. Menu titles, sub-titles, prompts, "single column", and "multiple column" menus are supported. Using two simple calls a full-screen data entry template may be loaded and a fully-titled data entry input screen may be created. Defaults, maximum field lengths, and numeric-only data are supported. The "perlmenu.pm" package uses curses interface routine calls supplied by the Curses extension for Perl5 (you should be running AT LEAST Perl 5.001). A "menu.pl" package can be created which uses curses interface routine calls supplied by the "curseperl" package for Perl4. All functions and features are identical whether you are using Perl4 or Perl5. ------------------------------------ The Official PerlMenu WWW home page: ------------------------------------ The official PerlMenu WWW home page (maintained by the author) is at: http://www.cc.iastate.edu/perlmenu/ ---------------------------- Official Distribution Points ---------------------------- The PerlMenu package is distributed via "CPAN" (the "Comprehensive Perl Archive Network"). Pick a CPAN site near you with a WWW browser pointed at "http://www.perl.com/perl/CPAN/CPAN.html" and go into the "authors/Steven L Kunz" folder. You should find "perlmenu.v4.0.tar.Z" in there. The author's official distribution is alos available via anonymous FTP from: ftp://ftp.iastate.edu/pub/perl/perlmenu.v4.0.tar.Z New releases are announced in the Usenet newsgroups "comp.lang.perl.announce" and "comp.lang.perl.modules". ---------------------- Distribution Contents ---------------------- This is "perlmenu.pm" - a set of perl routines that will perform full screen menu functions using Perl5+Curses. What you should have after unpacking this package is the following: ARTISTIC Artistic License COPYING Library GNU Public License FAQ Frequently Asked Questions INSTALLATION Guide to installing PerlMenus MENU_DOC A user's guide to the perlmenu.pm routines. MENU_DOC A user's guide to the menuutil.pl routines. README (this file) RELEASE_NOTES Differences between this version and previous versions. TO_DO List of things on my "to do" sheet. create_menu.pl Create a Perl4-style "menu.pl" module from the Perl5-style "perlmenu.pm" module. Used for legacy applications under Perl4 or Perl5. demo A simple menu demo showing all several types of menu selection capabilities (simple single-page, simple multiple-page, radio-button, and multiple-selection). demo_getstr A simple menu demo using the "menu_getstr" routine. demo_template A demo using the "menu_load_template" and "menu_display_template" routines. demo_top A simple menu demo with "top" menus. demo_util A simple demo of the routines in "menuutil.pl". ezpasswd A more involved demo showing how menu_getstr, menuutil.pl, and templates can be used to display full-screen formatted entries from a BSD-style /etc/password file. ezreg A more involved demo showing how menu template routines can be used in a full-screen user registration panel that a multiple required fields. ezview A more involved demo showing how menus can be used to call routines, select files, etc. install_hints.pl A small Perl5 program that helps you decide how to tweek "perlmenu.pm" for use on your system (with your flavor of termcap or terminfo). perlmenu.pm The PerlMenu subroutines in a Perl5-style package (usually placed somewhere like /usr/local/lib/perl/perlmenu.pm). See also "create_menu.pl". menuutil.pl Some curses subroutines useful in constructing curseperl transactions which use "perlmenu.pm". These are purely optional and are not needed for using PerlMenus ("perlmenu.pm"). Shows some examples of "curses" programming techniques. paint_text A sample file used by "demo" to display bottom-titles loaded from a file. template_data A sample full-screen input template used by "demo_template" to input name/address/phone data records. template_ezp The display template used by ezpasswd. template_reg The display template used by ezreg. --- Steven L. Kunz Networked Applications Iowa State University Computation Center, Iowa State University, Ames IA INET: skunz@iastate.edu perlmenu-4.0.orig/RELEASE_NOTES100660 1750 1750 41234 6301157753 16120 0ustar jgoerzenjgoerzen perlmenu.pm Perl Menus Version 4.0 Release Notes February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa Copyright (C) 1992-97 Iowa State University Computation Center Ames, Iowa (USA) Changes between perlmenu.pm version 4.0 and menu.pl version 3.3: - Converted to Perl5-style "perlmenu.pm" module. A program (create_menu.pl) is included to convert this module to the old Perl4-style "menu.pl" module for legacy applications and Perl4+curseperl users. All old PerlMenu programs should run without changes using this new "menu.pl" module. Conversion to use "perlmenu.pm" under Perl5 should only require changing "require" to a "use". - Added multiple-column menu support (requested by many people). Single call to "menu_prefs" converts all menus to "multiple column" selections. No changes to existing menu construction routines in old code required. Automatically scales and computes proper number of columns based on length of longest selection text. - Added a "highlighted" selection cursor preference. Previous versions only displayed the selection cursor with a "->" in front of the item. A new preference setting removes the "->" and highlights the selection text (in reverse video on most systems). Single call to "menu_prefs" converts all menus to "highlighted" selections. - Expanded the main "demo" program to enable switching between single and multiple column menus, arrowed or highlighted selection cursor, numbered and unnumbered menus. - Split out (and rewrote) the installation instructions into a new file called "INSTALLATION". Included a new "install_hints.pl" program (for Perl5+Curses users) which tries to figure out what tweeks you may need to make it work on your system. - Made appropriate changes to all other documentation as appropriate for the new features. - Added a new "FAQ" document. - Fixed a bug in that relates to typing an item selection number that is greater than the last item in the menu. Previously it dropped the selection arrow to the last item but crashed when you pressed "return". Now it "beeps" (to indicate an invalid selection). Thanks to Jay Fowler (CSU-Fresno, USA) for pointing this out. - Fixed bug in demo scripts. Previous versions were missing some calls to "endwin" prior to every "exit", which meant the original terminal environment was not restored (leaving the terminal in "raw" mode, etc.). Thanks to Warren Jones (Fluke Corporation, Everett, WA, USA) for the bug report and patches. - Added comment for HP-UX 9.05 terminfo/tput users in perlmenu.pm ("tput kent" does not work on these systems, use "tput cr"). Thanks to Stuart Poulin (Applied Microsystems Corporation, Redmond, WA, USA) for supplying this info. Changes between menu.pl version 3.3 and version 3.2: - Added a new call ("menu_load_template_array") to allow loading templates from an array (loaded within your Perl program) in addition to loading it from a file (as with the current "menu_load_template"). This means you can build your template applications as "one file", as opposed to having to distribute template files as companion required pieces. Changes "demo_template" to actually use this feature (with comments indicating how to use the file method, too). Thanks to Bjarne Steinsbo for all the patches required to install this feature. - Added a new (optional) operand to the "menu_init" call to support help on specific items within a menu. With an appropriate routine supplied, pressing "?" on a selected item will call the routine with the selection- text and action-text for the items as calling parms, providing a means of providing textual help for the item. The "demo" sample program is modified to provide help on individual items on the main menu to demonstrate this feature. Thanks to Trey Harris (University of North Carolina at Chapel Hill) for suggesting this idea. - Added a new call ("menu_help_routine") to allow overridding the default generic help screen (seen by pressing "h") so you can supply your own. - Added new operands to the "menu_prefs" call to allow overriding the "Do you really want to quit?" prompt and the default response. - Added additional "emacs-similar" field movement control sequences to menu_getstr and menu_display_template. Control-N and Control-P now move to next and previous fields. Thanks to Charles F. Randall of the Des Moines Area Community College. - Added new return code support to template exit routines to allow aborting data input when using "required fields" support. Thanks to Christopher Candreva (WestNet Internet Services of Westchester). - Updated "demo_template" and "ezreg" programs to reflect new "abort input using required fields" support. - Added a "clear_screen" call to "menuutil.pl" utility routines. The clears the screen and resets the $row and $col variables for you. - Added block of commented code to "menu.pl" for systems that do not have "getcap" but do have "terminfo" files and "tput" commands to get terminal sequences (such as SGI and other System V platforms). Expanded the installation instructions in the README file to better explain the "termcap" vs "terminfo" ramifications on various systems. - Improved documentation on use of the "menuutil.pl" utility routines. - Changed the demo scripts to favor working "out of the box" on Perl5 instead of Perl4 (package still works with both Perl4 and Perl5). - Changed GNU licensing to distribute under the "Library GNU Public License" (or the Artistic License) rather than the regular GPL (as in the past). Changes between menu.pl version 3.2 and version 3.1: - Added support for required fields to the "template" facility. This new support greatly simplifies coding data-entry routines with required fields. New parameters to "menu_display_template" allow automatic insertion of required field markers at one end (or each end) of required fields. New parameter supplied to your "template exit" routine indicates how many required fields remain to be filled in by the user. The required field markers can be changed via a new "menu_template_prefs" call. - Rewrote the "ezreg" demo to take advantage of the new "required field" template support. - Added Control-L screen refresh control key for template input. - Added "current cursor location latch" to input fields in a template. Now when you tab between fields on a template it returns to the cursor location you left (from within each window) when you return to it. - Fixed a bug in the menu subtitle support. When a subtitle routine was returning "null" (no titles), the titles already in the title array were not cleared. The first line of the old menu subtitle would not go away. Changes between menu.pl version 3.1 and version 3.0: - Added ability to set additional exit-key sequences for templates (via a new "menu_template_setexit" routine). Thanks to Christopher Candreva (WestNet Internet Services of Westchester). - Added ability to specify a routine address (instead of a raw string) for top/bottom subtitles on the "menu_init" call. The called routine must return the string to be used as the subtitle(s). Thanks to Christopher Candreva (WestNet Internet Services of Westchester). - Added a new "menu_pref" item to disable the "quit" ("Q") hot-key. Suggested by a couple people - the latest being Karsten Thygesen (Aalborg University, Denmark, Institute for Electronic Systems). - Fixed a return-code bug in "menu_load_template" (was not returning zero upon success as advertised). Thanks to Karsten Thygesen (Aalborg University, Denmark, Institute for Electronic Systems). - Fixed a bug in "menu_getstr" which cleared the default if it was not specified with a "maximum length" value. Thanks to Karsten Thygesen (Aalborg University, Denmark, Institute for Electronic Systems). - Changed demos to not use poor curses programming practices (like using stdio calls such as "print" and ""). - Added patch for Perl 5.000 and Perl 5.001 compatibility using the Curses extension. Thanks to William Setzer (author of the Perl5 Curses extension). Changes between menu.pl version 3.0 and version 2.3: - Added full-screen data entry support. New calls of "menu_load_template" and "menu_display_template" are used to load an easy-to-define data entry template. Alpha-numeric, numeric, hidden fields are supported. Multiple fields allowed per screen (and per line). Preliminary work done by Christopher Candreva (WestNet Internet Services of Westchester) provided a base for this development (Chris provided the menu_setexit and menu_getexit code to which I added the template routines). Alan Cunningham (NASA Spacelink Project) provided most of the design requirements for the exit routine support. - Added support for bottom titles (augmenting the existing top "sub-titles"). You can now have text above and below the menu. - Added a new "menu_paint_file" routine to load top sub-title and bottom titles from a file. Provides the ability to place large blocks of text associated with a menu in an "off-board" file where it can be easily edited and changed. This technique is optional - titles can still be loaded in the "menu_init" call. - Added a new "menu_prefs" call to allow setting certain global prefs for all menus. Currently you can indicate that you want all menus centered on the screen (instead of left-justified), and you can indicate you want more "gopher-like" action for the arrow keys. Thanks (again) to Chris Candreva for the centering code and idea for the arrow-action. - Added new optional parm to the "menu_item" call to allow specifying an item as "pre-selected" (changeable or non-changeable). - Added lots of optional parameters to menu_getstr to allow default values, maximum lengths, "noshow" values (for passwords), and numeric-only entry. Thanks (again) to Chris Candreva. - Added a "menuutil.pl" module with some useful curseperl routines to be used in PerlMenu programs. Includes a User's Guide. - Fixed a bug in the menu page display that caused an extraneous "bump up" of the menu when a down-arrow was pressed on the last page of a multiple page menu (and the last item was on the last line). Whew! - Fixed a bug in the return value from "menu_init". It previously returned one too few for the number of items currently in the menu. Thanks to Ian Phillipps. - Fixed a bug causing tight loops when the calling process went away (i.e. a terminal user hung up). If a menu prompt was active the null return value was not detected. Should also be handled by user signal trapping (within their code) for complete control. - Fixed a bug that caused an unnecessary screen repaint when pressing "U" ("up") at the top menu. Thanks (again) to Chris Candreva. - Fixed problems relating to Perl5 (subroutine calls with no parms called as "&rtn;" instead of "&rtn();"). Also added commented code for systems that use "tigetstr" (terminfo data) instead of "getcap" (termcap). Thanks to Jim Sumrall (Intel Corporation) and William Setzer (author of the Curses extension for Perl5). - Made arrow-movement much more CPU efficient. - Spiffed up the "ezview" demo to show how multiple file selection in a directory would work. - Added an "ezpasswd" demo as an example of full-screen template display of a BSD-style "/etc/passwd" file. - Changed "menu_getstr" to default to "overstrike" mode on single character data entry fields. - Added "emacs-similar" cursor movement/cut-paste control sequences to menu_getstr and menu_display_template. Thanks to Charles F. Randall of Iowa State University. Compatibility Note: There is ONE old call that has a new required operand. The "menu_curses_application" routine previously had no operands. With this version, you must pass in the value of the base window you got from the "initscr" call. So, if you called "menu_curses_application" in the past after you called "initscr" yourself, you should make your code look like: $window = &initscr(); &menu_curses_application($window); Changes between menu.pl version 2.3 and version 2.2: - Fixed a bug in the order of calls to "menu_return_prep" and "menu_exit_routine" when "quit" was being processed. The "menu_return_prep" routine is now called FIRST, so that it's processing can be done before a possible call to "endwin" in the user's "menu_exit_routine". This change also means that the processing in "menu_exit_routine" is truly the last code executed prior to exit. Thanks to Tim Goodwin. - Fixed a bug in "normal" applications (ones that do not call "menu_curses_application"). The "initscr" routine was previously called on each "menu_init" (in direct violation of the curses documentation). This caused no obvious problems on some systems (such as DEC ULTRIX) but many problems on others (such as Sun and other System V systems). Thanks to Steve Mitchell at CSU/Fresno. Changes between menu.pl version 2.2 and version 2.1: - Add menu subtitle capability. Changes between menu.pl version 2.1 and version 2.0: - Several bugfixes provided by Greg Kresko (National Research Council Canada). Greg found some problems with "endwin" statement placement (or lack thereof). Also suggested some minor changes to the demo programs. Changes between menu.pl version 2.0 and version 1.4: - Added multiple selection capability (new "menu_display_mult" call). Includes new menu options "a" (select "all"), "m" (select based on a string "match") and "c" ("clear" all selections). - Added "radio button" selection capability (new "menu_display_radio" call). - Removed "f" and "b" ("forward" and "backward") as page movement. Replaced by existing (but unadvertised) "n" and "p" ("next" and "previous" page). - Added "b" and "e" ("begin" and "end") as fast page movement to the items at the beginning and end of a menu. - Added "h" to provide a help screen explaining all available menu actions. - Changed default menu prompt formats. - Added ability to let users spawn off a sub-shell (and get a command prompt) from any menu (using the "!" hot-key) and later continue (upon shell exit). This feature is normally disabled. - Added "menu_getstr" utility routine call (lets you get a string from std input with C-shell-like editing) - Documentation changes (new features, some typos) Changes between menu.pl version 1.4 and version 1.3: - Added "r=refresh" to bottom menu line (when it fits). - A few (minor) documentation changes Changes between menu.pl version 1.1 and version 1.3: - Fixed bug in the "numeric direct entry code". Once a number was entered it was not cleared if an arrow key was used to move the pointer off the selection. - Added the "top menu" feature. Allows for a "t" ("top") menu hot-key to move to the top (first displayed) menu. - Added the "latched" menu feature. Allows calls to "menu_display" to have two additional parameters that remember the screen/arrow location upon return from the call. When recalling "menu_display" (with the same parameters) the menu will be restored to the original location/selection. Changes between menu.pl version .9 (beta) and version 1.1: - Declaration of "curses_application" fixed ("main`" prepended). - Cleanup of "cbreak" and "echo" handling. Calls to "menu_display" always return with "echo" and "cbreak" set. - Return key now functions on systems that do not have termcap entries for either a "newline" or "return" key. - "menu_display" will return "%EMPTY%" if no calls to "menu_item" were done between a "menu_init" call and a "menu_display" call. - Hitting the "space bar" is now the same as "f" or "n" for forward movement within a multi-page selection menu. - The title strings in "menu_init" calls can now begin with a "-" to suppress the "standout" attribute (normally a bold or reverse-video rendition). - menu_display will no longer return "%QUIT%" - returns "%UP" instead. The menu routines process a "q" (for "quit") locally and will exit from there (after the user responds to a "Do you really want to quit?" prompt). - Direct number entry for selecting entries "pops" the arrow to the "best fit" selection on the screen, indicating what selection will be made when return is hit. - The "ezview" demo now displays the correct modification date on its file display. --- Steven L. Kunz Networked Applications Iowa State University Computation Center, Iowa State University, Ames IA INET: skunz@iastate.edu perlmenu-4.0.orig/TO_DO100660 1750 1750 3303 6301157761 14746 0ustar jgoerzenjgoerzen perlmenu.pm Perl Menus Version 4.0 Release Notes February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa Copyright (C) 1992-97 Iowa State University Computation Center Ames, Iowa (USA) Things to do in future releases: - Allow integrated menus and templates (so you can have a multiple-selection menu overlayed on top a data-entry field template, for example). - Allow different rendition indications for various portions of the menus and templates. Things like "standout", or even colors (using standard ANSI or user-specified escape sequences for field rendition). This would allow (for example) template fields which had errors in the data to be presented in red reverse-video rendition. - Allow user specification of character-sequences used to perform certain generic functions (such as "cursor_up"). You could use a call such as the following: &menu_key_bind("",""); (I really thought I'd have this done for version 4.0, but I just couldn't get enough time. Maybe in version 4.1 ... SLK) - Allow a new "menu_pref" that places "(Done with ..."), etc at bottom of menus (instead of at the top). - Create support for headings within the menu selection items. These strings (really non-selectable items) would be "auto-skipped" during arrow movement/selection. perlmenu-4.0.orig/demo100770 1750 1750 30470 6276422451 15017 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #************************************************************************** # demo -- Simple PerlMenu demo # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Demonstrates "latched" (remembered) menu position technique # in "long" menu routine. # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout $window = &initscr(); &menu_curses_application($window); &menu_quit_routine("endwin"); # Uncomment this line to enable shell-escapes. # If your shell does not have a "SHELL" environment variable, replace the # call parameter with something like "/bin/sh". # &menu_shell_command($ENV{"SHELL"}); # Default prefs active at start $numbered_flag = 1; # Numbered menus $num_pref = "numbered"; $gopher_pref = "default"; # Non-gopherlike arrows/scrolling $gopher_flag = 0; $mult_pref = "single"; # Single column menus $mult_flag = 0; $arrow_pref = "arrow"; # Arrow selection indicator menus $arrow_flag = 0; $menu_default_top = 0; # Storage for mainline top item number. $menu_default_row = 0; # Storage for mainline arrow location. $menu_default_col = 0; # Storage for mainline arrow location. $row = $col = 0; # Storage for row/col for menuutil.pl $title_cnt = 0; # To trigger different subtitles/bottom titles while (1) { &menu_init($numbered_flag,"PerlMenu Version 4.0",0,"", "-Copyright 1992-97, Iowa State University, Ames, Iowa (USA)", "main_menu_help"); &menu_paint_file("./paint_text",0); &menu_item("Exit this demo","exit"); &menu_item("See a single-page menu demo","test_short_menu"); &menu_item("See a multiple-page menu demo","test_long_menu"); &menu_item("See a radio-button menu demo","test_radio_menu"); &menu_item("See a multiple-selection menu demo","test_mult_menu"); &menu_item("See a menu demo with sub-titles","test_subtitle_menu"); &menu_item("Change arrow-wrap/scrolling menu preferences","gopher_prefs"); &menu_item("Change multiple-column menu preferences","mult_col_prefs"); &menu_item("Change arrow/highlight selection line menu preferences","arrow_prefs"); &menu_item("Change numbering on all menus","numbered_prefs"); $sel = &menu_display("",$menu_default_row,$menu_default_top,$menu_default_col); if ($sel eq "exit") { last; } if ($sel eq "%EMPTY%") { die "Not enough screen lines to display demo menu\n"; } if ($sel ne "%UP%") { &$sel(); # Note that this assumes the "action_text" is a subroutine name } } &endwin; exit; # # Help routine for items on main menu panel # sub main_menu_help { local($item_text,$item_tag) = @_; &top_title("PerlMenu -- Demo Help Screen for Specific Menu Items"); &print_nl("Selection \"$item_text\"",2); if ($item_tag eq "exit") { &print_nl("Selecting this item will immediately exit this demo.",1); } elsif ($item_tag eq "test_short_menu") { &print_nl("A single-page menu has a few items which fit on one screen.",1); &print_nl("No wrapping or scrolling of the menu occurs.",1); &print_nl("",1); } elsif ($item_tag eq "test_long_menu") { &print_nl("A long menu has items that span several pages.",1); &print_nl("Wrapping and scrolling of the menu occurs.",1); } elsif ($item_tag eq "test_radio_menu") { &print_nl("Radio-button menus have selection boxes in front of each item.",1); &print_nl("Only one item can be checked at a time.",1); } elsif ($item_tag eq "test_mult_menu") { &print_nl("A multiple-selection menu provides a list of several items.",1); &print_nl("One or more items and be selected.",1); &print_nl("In addition, some items can be pre-selected or locked out.",1); &print_nl("Selection can be based on string-matching.",1); } elsif ($item_tag eq "test_subtitle_menu") { &print_nl("Several sub-title and bottom title options are available.",1); &print_nl("This selection demonstates them.",1); } elsif ($item_tag eq "prefs") { &print_nl("The PerlMenu designer can provide actions based on overall preferences.",1); &print_nl("This demo shows some of the arrow-key wrapping modes available.",1); } &pause("(Press any key to exit help)"); } # # Build a short (one page) demo menu. # sub test_short_menu { local($sel); while (1) { # Init a numbered menu with a title &menu_init($numbered_flag,"Short Menu (fits on one page)"); # Add item to return to main menu. &menu_item("(Exit)","exit"); # Add several items &menu_item("Dog","animal"); &menu_item("Cat","animal"); &menu_item("Granite","mineral"); &menu_item("Mouse","animal"); &menu_item("Shale","mineral"); &menu_item("Onion","vegetable"); &menu_item("Carrot","vegetable"); # Display menu and process selection. # Note that the previous position is not remembered because parms 2 and 3 # are not supplied to store values used on subsequent call. $sel= &menu_display(""); if (($sel eq "%UP%") || ($sel eq "exit")) { return; } &clear_screen(); &pause("You picked a $sel."); } } # # Build demo long menu (several pages) # sub test_long_menu { local($sel_num); local($menu_default_top) = 0; # Storage for local top menu item number. local($menu_default_row,$menu_default_col) = 0; # Storage for local arrow location. while (1) { # Init a numbered menu with title &menu_init($numbered_flag,"Long Menu (fits on several pages)"); # Add item to return to main menu. &menu_item("(Exit)","exit"); # Build lots of entries in the menu if ($mult_flag) { $max = 200; } else { $max = 50; } for ($i = 1; $i < $max; $i++) { $sel_num = $i + 1; &menu_item("Item $sel_num","action-$sel_num"); } # Get user selection. # Note that local parms 2 and 3 are provided to provide storage of the # default arrow location and top menu item on the screen for subsequent call. $sel = &menu_display("",$menu_default_row,$menu_default_top,$menu_default_col); if (($sel eq "%UP%") || ($sel eq "exit")) { return; } &clear_screen(); &pause("You picked the item with selection-action $sel."); } } # # Build a radio-button demo menu. # sub test_radio_menu { local($sel); # Init a numbered menu with a title &menu_init($numbered_flag,"Radio-button Menu"); # Add a few items &menu_item("Setting A","a"); &menu_item("Setting B","b"); &menu_item("Setting C","c"); # Display menu and process selection. # Note that the second operand is the "current selection". $sel= &menu_display_radio("","a"); if ($sel eq "%UP%") { return; } &clear_screen(); &pause("You set it to $sel."); } # # Build a multiple-selection demo menu. # sub test_mult_menu { local($sel,$i,$sel_num); # Init a numbered menu with a title and subtitle &menu_init($numbered_flag,"Multiple Selection Menu",0,"-Pets"); # Add a few items &menu_item("Dog","dog"); &menu_item("Cat","cat"); &menu_item("Gerbil (pre-selected)","gerbil",1); &menu_item("Hamster (locked out)","hamster",-1); &menu_item("Goldfish","goldfish"); # Display menu and process selection. $sel = &menu_display_mult(""); if ($sel eq "%UP%") { return; } # Process user selection. # Note how "split" is used to split the multiple-selection string into # individual pieces. &clear_screen(); if ($sel eq "%NONE%") { &pause("(You didn't select anything)"); } else { &print_nl("You selected the following:",1); split(/[,]/,$sel); # Put return in @_ foreach (@_) { &print_nl(" $_",1); } &pause(""); } } # # Build demo short menu (with sub-titles generated by a routine) # sub test_subtitle_menu { local($sel_num); local($menu_default_top) = 0; # Storage for local top menu item number. local($menu_default_row,$menu_default_col) = 0; # Storage for local arrow location. while (1) { $title_cnt++; # Jog the count # Init a numbered menu with title, sub-titles, and bottom titles of all # varieties. &menu_init($numbered_flag,"Menu with dynamic sub-titles and bottom titles", 0,"&sub_title_builder","&bottom_title_builder"); # Add item to return to main menu. &menu_item("(Exit)","exit"); # Build 25 entries in the menu $i = 1; while ($i < 25) { $sel_num = $i + 1; &menu_item("Item $sel_num","action-$sel_num"); $i++; } # Get user selection. # Note that local parms 2 and 3 are provided to provide storage of the # default arrow location and top menu item on the screen for subsequent call. $sel = &menu_display("",$menu_default_row,$menu_default_top,$menu_default_col); if (($sel eq "%UP%") || ($sel eq "exit")) { return; } &clear_screen(); &pause("You picked the item with selection-action $sel."); } } # # Generate variable top menu # sub sub_title_builder { if ($title_cnt > 1) { return("-Dynamic Subtitle Number $title_cnt"); } else { return("-Top Centered\n-Top Right-justified"); } } # # Generate variable bottom menu # sub bottom_title_builder { if ($title_cnt > 1) { return("This could say YOU HAVE $title_cnt NEW PIECES OF MAIL"); } else { return("Bottom Centered\n-Bottom Right-justified"); } } # # Toggle arrow-action/scrolling preferences # sub gopher_prefs { # Init a numbered menu with a title &menu_init($numbered_flag,"Arrow-Wrap/Scrolling Preference Setting"); # Add secelection items &menu_item("Default arrow action (scrolls/nowrap)","default"); &menu_item("More \"gopher-like\" arrow action (pages/wraps)","gopher-like"); # Display menu and process selection. # Note that the second operand is the "current selection". $sel= &menu_display_radio("",$gopher_pref); if ($sel eq "%UP%") { return; } $gopher_pref = $sel; if ($sel eq "default") { $gopher_flag = 0; } else { $gopher_flag = 1; } &menu_prefs(0,$gopher_flag,0,"","",$mult_flag,$arrow_flag); } # # Toggle multiple-column preferences # sub mult_col_prefs { # Init a numbered menu with a title &menu_init($numbered_flag,"Multiple-column Preference Setting"); # Add secelection items &menu_item("Single column menus","single"); &menu_item("Multiple column menus","multiple"); # Display menu and process selection. # Note that the second operand is the "current selection". $sel= &menu_display_radio("",$mult_pref); if ($sel eq "%UP%") { return; } $mult_pref = $sel; if ($sel eq "single") { $mult_flag = 0; } else { $mult_flag = 1; } &menu_prefs(0,$gopher_flag,0,"","",$mult_flag,$arrow_flag); } # # Toggle arrow/highlight selection cursor preferences # sub arrow_prefs { # Init a menu with a title &menu_init($numbered_flag,"Arrow/Highlighted Selection Cursor Preference"); # Add secelection items &menu_item("Arrow in front of selection text","arrow"); &menu_item("Highlighted selection text","highlight"); # Display menu and process selection. # Note that the second operand is the "current selection". $sel= &menu_display_radio("",$arrow_pref); if ($sel eq "%UP%") { return; } $arrow_pref = $sel; if ($sel eq "arrow") { $arrow_flag = 0; } else { $arrow_flag = 1; } &menu_prefs(0,$gopher_flag,0,"","",$mult_flag,$arrow_flag); } # # Toggle numbered/unnumbered for this demo # NOTE THAT THIS IS NOT A "MENU_PREF" PREFERENCE SETTING # sub numbered_prefs { # Init a numbered menu with a title &menu_init($numbered_flag,"Numbered/Unnumbered Control"); # Add selection items &menu_item("Numbered menus","numbered"); &menu_item("Unnumbered menus","unnumbered"); # Display menu and process selection. # Note that the second operand is the "current selection". $sel = &menu_display_radio("",$num_pref); if ($sel eq "%UP%") { return; } $num_pref = $sel; if ($sel eq "numbered") { $numbered_flag = 1; } else { $numbered_flag = 0; } } perlmenu-4.0.orig/demo_getstr100770 1750 1750 7753 6276163000 16367 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #************************************************************************** # demo_getstr -- Simple perl menu_getstr call demo # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Demonstrates "menu_getstr" utility routine (useful in perl # curses programs). # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout $menu_default_arrow = $menu_default_top = 0; # # NOTE: This program uses a regular perl menu to activate menu_getstr. If # you do not use a perl menu prior to calling menu_getstr the first # time you must still call menu_init (only) ONCE before calling # menu_getstr to initialize the curses environment. # while (1) { &menu_init(1,"PerlMenu 4.0 - menu_getstr Demonstration"); &menu_item("(Exit this demo)","exit"); &menu_item("Regular (long) strings","regular"); &menu_item("Regular (long) strings with default","regdef"); &menu_item("Regular (max length 8) strings","max8"); &menu_item("Regular (max length 8) strings with default","max8def"); &menu_item("Hidden (max length 8) strings with default","max8inv"); $sel = &menu_display("",$menu_default_arrow,$menu_default_top); if ($sel eq "exit") { &endwin(); exit(0); } elsif ($sel eq "regular") { &do_getstr("",0,0); # No default, no max length, non-hidden } elsif ($sel eq "regdef") { &do_getstr("Barney",0,0); # No default, no max length, non-hidden } elsif ($sel eq "max8") { &do_getstr("",8,0); # No default, max length 8, non-hidden } elsif ($sel eq "max8def") { &do_getstr("Barney",8,0); # Default of "Barney", max length 8, non-hidden } elsif ($sel eq "max8inv") { &do_getstr("password",8,1); # Default of "password", max length 8, hidden } } #********** # DO_GETSTR # # Function: Call menu_getstr with various parameters # # Input: - Default string (may be null) # - Maximum length (may be zero) # - No-show (hidden) flag (0=show, 1=noshow) # # Returns: Nothing # #********** sub do_getstr { local($default,$maxlen,$hide) = @_; local($title); # Generate a title indicating what we are doing if ($default) { $title .= "Default=\"$default\" "; } else { $title .= "No-Default "; } if ($maxlen) { $title .= "Maxlen=$maxlen "; } else { $title .= "No-Maxlen "; } if ($hide) { $title .= "Hidden "; } else { $title .= "Visible "; } # Put out a title and instructions. &clear(); &move(0,25); &addstr($title); &move(2,5); &addstr("Enter strings, using left and right arrows to move insert/deletion"); &move(3,5); &addstr("point after you have entered some characters."); &move(4,5); &addstr("A null entry exits."); # Loop, getting/displaying strings until a null value is entered while (1) { if ($maxlen) { $string = &menu_getstr(10,5,"Enter value: ",0,$default,$maxlen,$hide); } else { $string = &menu_getstr(10,5,"Enter value: ",0,$default,0,$hide); } if ($string eq "") { # Exit if we get a null string &clear(); &refresh(); last; } &move(12,5); # Display last string entered &clrtobot(); &addstr("Last string entered: $string"); &refresh(); } } perlmenu-4.0.orig/demo_template100770 1750 1750 15013 6276163025 16705 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #************************************************************************** # demo_template -- Full-screen data entry template demo # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Demonstrates data entry using templates (template file is # "template_data" in the current directory) # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout @input_data = (); # Place to put data entered on screen @defaults = (); # Default data @protect = (); # Protected markers @required = (); # Required field markers $bell = "\007"; # Ascii bell character $row = $col = 0; # Storage for row/col used by menuutil.pl # # Since we are not using menus in this example, we need to call "menu_init" # to initialize the curses environment. Not necessary if you have at # least one menu display (which will include a menu_init) first. # &menu_init(); # # Activate left and right markers, both in standout rendition. # &menu_template_prefs("*"," ",1,"*"," ",1); # # Load the template from in-line code (ending at "END_OF_TEMPLATE" in this # source file). Data entry fields denoted by underscores ("_") or # back-slashes ("\"); # # To demonstate loading the template from the data file, comment out all # statements from "&menu_load_template_array(...)" to (and including) the # "END_OF_TEMPLATE" statement and ADD the following line instead: # # &menu_load_template("./template_data"); # # This will load the template from the datafile "./template_data" instead # of from the in-line source. # &menu_load_template_array(split("\n", <<'END_OF_TEMPLATE')); Template Entry Demonstration Address Data Example Record # ___ Name: [_____________________________________________] Addr: [_____________________________________________] City: [__________________] State: [__] Zip: [\\\\\] Phone: (\\\) \\\-\\\\ Password: [^^^^^^^^] Enter all information available. Edit fields with left/right arrow keys or "delete". Switch fields with "Tab" or up/down arrow keys. Indicate completion by pressing "Return". Refresh screen with "Control-L". Abort this demo here with "Control-X". END_OF_TEMPLATE &menu_overlay_template(0,28,"Perl Menu Version 4.0",1,1); &menu_overlay_template($LINES-5,10, "Fields marked with a \"*\" are required.",1); # # Define "Control X" as "abort data input" # &menu_template_setexit("\cX"); # # Set defaults for all records the same in this example. # For record updating you would set the defaults to the existing values # from an old record. # $defaults[0] = 0; # Record number $defaults[1] = "Sample name"; # Name $defaults[2] = "Sample address"; # Addr $defaults[3] = "Sample city"; # City $defaults[4] = "IA"; # State $defaults[5] = ""; # Zip $defaults[6] = ""; # Phone - area code $defaults[7] = ""; # Phone - first three digits $defaults[8] = ""; # Phone - last four digits $defaults[9] = "Barney"; # Password # # Set protected fields for all records in this example. # This lets us supply a record number as a default in the first field but # not allow the user to change it. # $protect[0] = 1; # Record number (protected, filled in by call parm) $protect[1] = 0; # All remaining fields are unprotected $protect[2] = 0; $protect[3] = 0; $protect[4] = 0; $protect[5] = 0; $protect[6] = 0; $protect[7] = 0; $protect[8] = 0; $protect[9] = 0; # # Set required fields for records in this example. # Note that the offset value is "2" to prevent overlaying the "[" # on the template. # $required[0] = 0; $required[1] = 2; # Name $required[2] = 0; $required[3] = 0; $required[4] = 0; $required[5] = 0; $required[6] = 0; $required[7] = 0; $required[8] = 0; $required[9] = 2; # Password # # Input three records # for ($i = 1; $i <= 3; $i++) { $defaults[0] = $i; # Set the record number in the protected field # IMPORTANT: Note the use of pointers to arrays here &menu_display_template(*input_data,*defaults,*protect,"template_exit", *required); last if (&menu_getexit() eq "\cX"); # Demonstrate a template overlay the first time if ($i == 1) { @bad_data = @input_data; # Reload the data we just got &menu_overlay_template($LINES-5,10,"This is a template overlay.$bell"); &menu_overlay_template($LINES-4,10,"(It could be an error message)"); &menu_overlay_template($LINES-3,10, "Note that the data is from the previous screen."); # Let them reenter data &menu_display_template(*input_data,*bad_data,*protect,"template_exit", *required); &menu_overlay_clear(); last if (&menu_getexit() eq "\cX"); } # Display what we got the last time &clear_screen(); &print_nl("Record #$i",1); &print_nl("Here is what was returned in \@input_data:",2); for ($j = 0; $j <= $#input_data; $j++) { &print_nl("\$input_data[$j]: $input_data[$j]",1); } &pause(""); } &clear_screen(); &refresh(); &endwin; exit(0); #********** # TEMPLATE_EXIT - Exit routine for "menu_display_template" #********** sub template_exit { local($direction,$last_index,$next_index,$still_required) = @_; # Return now if they are skipping between fields if ($direction) { return($next_index); } # # Check for forced exit (aborted data entry). # Note that this routine uses a "-2" return code, which means "ignore # required fields checking". # if (&menu_getexit() eq "\cX") { return(-2); } # User says they are done (they pressed "Return"). &menu_overlay_clear(); # Clear any old overlays # Put out message if there are still required fields. if ($still_required) { &menu_overlay_template($LINES-5,10, "Fields marked with a \"*\" are STILL required.",1); return(-1); # Still need required field(s) - auto-position } # Let them be done. return(-1); } perlmenu-4.0.orig/demo_top100770 1750 1750 6113 6276163046 15660 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #********************************************************************* # demo_top -- PerlMenu demo - Usage of "top menu" functions. # # Note: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Demonstrates technique to use "top" menu feature. # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #******************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout # Prepare and display the main (top) menu while (1) { &menu_init(1,"PerlMenu Version 4.0",1,"-Top Menu Demonstration"); &menu_item("Exit this demo","exit"); &menu_item("Animal","animal"); &menu_item("Mineral","mineral"); &menu_item("Vegetable","vegetable"); # Get selection $sel= &menu_display(""); # Process selection (ignore "up" at top level) if ($sel ne "%UP%") { if ($sel eq "exit") { exit; } if ($sel eq "animal") { &animal(); } # Call lower level elsif ($sel eq "mineral") { &mineral(); } # Call lower level elsif ($sel eq "vegetable") { &vegetable(); } # Call lower level } } # One level down - can call lower levels sub animal { while (1) { &menu_init(1,"Lower animal menu"); &menu_item("Dog","dog"); &menu_item("Cat","cat"); $sel = &menu_display(""); if ($sel eq "%UP%") { return; } # "up" or "top" if ($sel eq "dog") { &dog(); } # Call lower level if ($sel eq "cat") { &cat(); } # Call lower level } } # Two levels down sub dog { while (1) { &menu_init(1,"Lower dog menu"); &menu_item("Lab",""); &menu_item("Collie",""); $sel = &menu_display(""); if ($sel eq "%UP%") { return; } # "up" or "top" } } # Two levels down sub cat { while (1) { &menu_init(1,"Lower cat menu"); &menu_item("Tabby",""); &menu_item("Siamese",""); $sel = &menu_display(""); if ($sel eq "%UP%") { return; } # "up" or "top" } } # One level down - (no lower levels) sub mineral { while (1) { &menu_init(1,"Lower mineral menu"); &menu_item("Shale",""); &menu_item("Limestone",""); $sel = &menu_display(""); if ($sel eq "%UP%") { return; } # "up" or "top" } } # One level down - (no lower levels) sub vegetable { while (1) { &menu_init(1,"Lower vegetable menu"); &menu_item("Carrot",""); &menu_item("Pea",""); $sel = &menu_display(""); if ($sel eq "%UP%") { return; } # "up" or "top" } } perlmenu-4.0.orig/demo_util100770 1750 1750 4505 6276163070 16033 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #************************************************************************** # demo_util -- Demonstate some utilities in menuutil.pl # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Demostrates some basic curses techniques via a set of # utility routines (which can also be snipped or built on). # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout # # Required global variables are $window, $row, and $col. # These variables are used by the menuutil.pl routines. # $window = $row = $col = 0; # Init the curses environment $window = &menu_init(); # Clear screen and center a top title. &top_title("PerlMenu Utility Routine Demo"); # Put out a couple lines. &print_nl("The first line (followed by two new-lines).",2); &print_nl("The second line.",1); # Pause (with the default prompt); &pause(""); # Put out a couple more lines. &print_nl("The third line",1); &print_nl("The fourth line",2); # See if they want to see the last line. if (&query("Do you want to see a pop-up \"ask\" box?","yn") eq "n") { &new_line(1); &print_nl("Sigh ... and it was the best demo!",1); if (&query("Are you SURE you don't want to see it?","yn") eq "y") { &endwin; exit(0); } } # Do the pop-up query. $name = &popup_ask("Please enter your first name: ",20); &pause("Goodbye, $name. Press any key to exit"); # All done - clean up and go home. &clear_screen(); &refresh(); &endwin; exit(0); perlmenu-4.0.orig/ezpasswd100770 1750 1750 7056 6276163147 15723 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #************************************************************************** # ezpasswd -- Full-screen data display template demo # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Demonstrates data display using templates (template file is # "ezp_template" in the current directory) # # With a little work this program could be converted to a # full-screen /etc/passwd updater (left as an excercise for the # user). # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout @input_data = (); # Not really used (but still needed) @display_data = (); # Display data @protect = (); # Protection $bell = "\007"; # Ascii bell character $default = ""; # Default login for main loop # # Since we are not using menus in this example, we need to call "menu_init" # to initialize the curses environment. Not necessary if you have at # least one menu display (which will include a menu_init) first. # &menu_init(); # # Load the template from the data file (created with a text editor) # Data entry fields denoted by underscores ("_") or back-slashes ("\"); # if (&menu_load_template("./template_ezp")) { die "Cannot find \"template_ezp\"template file.\n"; } # # Set protected fields in this "display only" example. # $protect[0] = $protect[1] = $protect[2] = $protect[3] = 1; $protect[4] = $protect[5] = $protect[6] = $protect[7] = 1; # # Main loop # while (1) { # Prompt for a /etc/passwd entry to display &top_title("PerlMenu 4.0"); &print_nl(" Enter login to display from /etc/passwd",1); &print_nl(" Supply a null value to exit.",2); $prow = $row; $pcol = $col+2; $string = &menu_getstr($prow,$pcol,"Login: ",0,$default,8,0); last if ($string eq ""); # Display entry (handle errors) if (!&display_entry($string)) { &new_line(1); &pause(" Login \"$string\" not found - Press any key to continue $bell"); $default = $string; } else { $default = ""; } } # # Clean up and go home. # &clear(); &refresh(); &endwin(); exit(0); #*********** # DISPLAY_ENTRY -- Display an entry from the password file # # Arguments: Login-id to display # # Returns: Boolean flag (0=not there, 1=found it) #*********** sub display_entry { local($seek) = @_; local($found_it) = 0; $i = 0; # Record count open(PASSWD,"/etc/passwd"); # Where the BSD-style "passwd" file is while() { $i++; # Count the record @display_data = split(":"); # Split fields next if ($display_data[0] ne $seek); $found_it = 1; unshift(display_data,$i); # Insert line number # IMPORTANT: Note the use of pointers to arrays here &menu_display_template(*input_data,*display_data,*protect); } close(PASSWD); return($found_it); } perlmenu-4.0.orig/ezreg100770 1750 1750 11627 6300355424 15203 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #*************************************************************************** # EasyReg -- PerlMenu Full-screen Registration Demo # (a "practical" demo for menu.pl) # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Thanks: # This is a "trimmed down" example of a registration program # developed by Alan Cunningham while we were working together on # template exits. Alan's code was clever enough (and useful enough) # for me to warrant including it in this distribution. # Thanks, Alan! # Steve Kunz # # Author: Alan Cunningham # NASA Spacelink Project # Marshall Space Flight Center # Huntsville, AL # # Date: February 1997 #**************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $| = 1; # Flush after every write to stdout # These three arrays are required for the menu routines...all three must # stay in the same order. [0] is first field on screen ... etc. @ENTERED=(); @DEFAULT=(); $DEFAULT[7] = "Y"; #Country=USA? @PROTECT=(); # # This array is NOT required for the menu routines, but is used by this code # to ensure we have answers for all the right fields. # $REQUIRED[0] = 2; #First Name $REQUIRED[1] = 0; #Middle Name $REQUIRED[2] = 2; #Last Name $REQUIRED[3] = 0; #Daytime Phone Number $REQUIRED[4] = 2; #Ed Inst Name $REQUIRED[5] = 2; #Add line 1 $REQUIRED[6] = 2; #Add line 2 $REQUIRED[7] = 2; #Country=USA? $req_field_cnt = $#REQUIRED; #number of fields to check for req data $basefieldline = 7; #Where do fields start $markcol = 34; #Where to mark missed fields $reqline = 16; #Where to put the required reminder text $reqtext = "These are STILL required--^"; # # Set up curses and the menu routines # $window = &initscr(); &menu_curses_application($window); &menu_init(); # # Load the template and add a standout "sticky" title # if (&menu_load_template("./template_reg")) { die "Cannot find \"template_reg\" template file.\n"; } &menu_overlay_template(0,28,"Perl Menu Version 4.0",1,1); # # Build some parts we couldn't put into the template file (because the # "caret" is a field marker) # &menu_overlay_template($reqline,$markcol,"^"); # # Define "Control X" as "abort data input". # &menu_template_setexit("\cX"); # # Display the form and get responses. # Use an exit routine to check to make sure all required fields are supplied. # &menu_display_template(*ENTERED,*DEFAULT,*PROTECT,"template_exit",*REQUIRED); # # Display what we got and exit. # You add the rest of the code to do something with it. # &top_title("Registration Demo"); if (&menu_getexit() eq "\cX") { # Check for aborted data entry &print_nl("(Data entry was aborted by Control-X)",2); } else { &print_nl("Here is what was returned in \@ENTERED:",2); for ($j = 0; $j <= $#ENTERED; $j++) { &print_nl("\$ENTERED[$j]: $ENTERED[$j]",1); } } &pause(""); &endwin(); exit(1); #********** # Exit routine for menu_display_template # # This routine gets control from within "menu_display_template" every time # the user tabs between fields or presses return. The basic action is # to allow the user to freely enter data and tab between fields until they # press "Return". At that point, a check is made for some entry in all # required fields. If some required fields are not filled in, all remaining # required fields are marked (using a template overlay) and the user is # positioned at the first required field not filled in. This process # continues until all required fields are supplied. #********** sub template_exit { local($direction,$last,$next,$still_required) = @_; # # Return now if they are skipping between fields # if ($direction) { return($next); } # # Check for forced exit (aborted data entry). # Note that this routine uses a "-2" return code, which means "ignore # required fields checking". # if (&menu_getexit() eq "\cX") { return(-2); } # # User says they are done (they hit "Return"). # &menu_overlay_clear(); if ($still_required) { &menu_overlay_template($reqline,($markcol+1)," " x 40); &menu_overlay_template($reqline,8,$reqtext,1); return(-1); # Let required field processing handle this. } return(-1); # No missing reqd fields - will really return. } perlmenu-4.0.orig/ezview100770 1750 1750 11411 6276163244 15400 0ustar jgoerzenjgoerzen#!/usr/local/bin/perl5 #*************************************************************************** # EasyView -- Unix File Viewer/Editor Interface # (a "practical" demo for menu.pl) # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # Email: skunz@iastate.edu # # Date: February 1997 #**************************************************************************** # Perl5+Curses ONLY! # Comment these lines for use with Perl4/curseperl BEGIN { $Curses::OldCurses = 1; } use Curses; # PerlMenu needs "Curses" use perlmenu; # Main menu package (Perl5 only) require "./menuutil.pl"; # For "pause" and "print_nl" routines. # Perl4/curseperl ONLY! # Uncomment these lines for use with Perl4/curseperl # (Did you remember to run "create_menu.pl"?) #require "./menu.pl"; # Main menu package (Perl4 only) #require "./menuutil.pl"; # For "pause" and "print_nl" routines. $SIG{'INT'} = 'cleanup'; # Set signal handler $| = 1; # Flush after every write to stdout $last_arrow = 0; # For arrow latching $last_top = 0; # For arrow latching # # MAIN_MENU -- Main (top level) menu # while (1) { &menu_init(1,"EasyView Version 4.0"); &menu_item("Exit","%UP%"); &menu_item("List files in current directory","dir_list"); &menu_item("Page through text files","page_file"); &menu_item("Edit text files","edit_file"); $subr = &menu_display("",$last_arrow,$last_top); if ($subr eq "%UP%") { &cleanup; } if ($subr ne "") { &$subr; } # Call subroutine selected } #********** # DIR_LIST -- Provide directory list #********** sub dir_list { &dir_select(0,".","Directory Contents"); } #*********** # PAGE_FILE -- Page through a file in the current directory # # Arguments: None # # Returns: Nothing # # Note: Uses file as an unnumbered menu #*********** sub page_file { local($filename,$last_arrow,$last_top); # Call utility function to select file $filename = &dir_select(1,".","Select one or more files to page through"); if (($filename eq "%UP%") || ($filename eq "%NONE%")) { return; } # Split up selections, page through each split(/[,]/,$filename); # Put return in @_ foreach (@_) { &menu_pager($_); } } #********** # MENU_PAGER -- A simple pager written in menu routines #********** sub menu_pager { local($filename) = @_; # Load file as an unnumbered menu - let menu_display do the paging # # Special thanks: The tab expansion used here was lifted from the # "pager" program distributed with perl.4.36 in the "usub" directory. # Don't know who wrote it but it fit the bill. SLK # &menu_init(0,"File: $filename"); open(TEMP,$filename); while () { s/^(\t+)/' ' x length($1)/e; &expand($_) if /\t/; &menu_item($_,""); } &menu_display("",$last_arrow,$last_top); close(TEMP); } # Expand tabs to blanks sub expand { while (($off = index($_[0],"\t")) >= 0) { substr($_[0], $off, 1) = ' ' x (8 - $off % 8); } } #*********** # EDIT_FILE -- Edit a file in the current directory #*********** sub edit_file { &clear; $filename = &dir_select(1,".","Select one or more files to edit"); if (($filename eq "%UP%") || ($filename eq "%NONE%")) { return; } # Split up selections, edit each split(/[,]/,$filename); # Put return in @_ foreach (@_) { system("vi $_"); } } #************ # DIR_SELECT -- Load a formatted directory list into a menu. # # Arguments: Boolean flag indicating numbered menu (1=yes), directory # name string and top-title string for menu # # Returns: File name (or "%UP%" or "%NONE%") #************ sub dir_select { local($numbered,$directory,$title) = @_; local($last_arrow,$last_top) = 0; opendir(DIR,$directory); &menu_init($numbered,$title); dir_entry: while ($filename = readdir(DIR)) { next dir_entry if ($filename eq "."); next dir_entry if ($filename eq ".."); next if (! -f $filename); ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, $blksize,$blocks) = stat($filename); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($mtime); $mon++; $sel_action = $filename; $filename=$filename.substr(" ",0,20-length($filename)); $sel_text = sprintf("%s%s%02d/%02d/%02d %02d:%02d %s\n", $filename,$filler,$mon,$mday,$year,$hour,$sec,getpwuid($uid)); &menu_item($sel_text,$sel_action); } if ($numbered) { $fn = &menu_display_mult("",""); } else { $fn = &menu_display(""); } $fn; } #********** # Cleanup routine (called upon exit) #********** sub cleanup { &clear; &refresh; &endwin; exit; } perlmenu-4.0.orig/INSTALLATION100660 1750 1750 36455 6301170051 15764 0ustar jgoerzenjgoerzen perlmenu.pm Perl Menus Version 4.0 February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa PerlMenu - Perl library module for curses-based menus & data-entry templates Copyright (C) 1992-97 Iowa State University Computation Center Ames, Iowa (USA) -------------------------------- A bit of history (and a warning) -------------------------------- The PerlMenu package was written originally for Perl 4.36 (with the "curseperl" extensions). When Perl5 came out PerlMenu was modified to include some "compatibility tweeks" so it worked with William Setzer's "Curses" extension, but was still distributed "Perl4-ready". The PerlMenu module was named "menu.pl" (in Perl4 fashion). Later versions of PerlMenu have been distributed to run on Perl5+Curses "out-of-the-box". Beginning with PerlMenu version 4.0, the package is distributed as a Perl5-style "perlmenu.pm" module. However, even this latest version can still be converted to run under Perl4 (by generating a Perl4-style "menu.pl" module). While I like to think that I can continue to bring new features to everybody, there will be a day coming when "menu.pl" is "iced" and new features only appear under the Perl5 version. See that "Wall" over there. No, not the one named "Larry" - the other one made of stone. It has writing on it ... ;-) ------------------------------- Installation for use with Perl5 ------------------------------- *** You must have at least Perl 5.001 *** 1) You need to have William Setzer's "Curses" extension built into Perl5. This package is available from any "CPAN" ("Comprehensive Perl Archive Network") site. Point your WWW browser to: http://www.perl.com/perl/CPAN/CPAN.html and look for "Curses" in the "User Interfaces" section. 2) You may have to modify the first line of the demo scripts ("demo", "demo_getstr", "demo_template", "demo_top", "demo_util", "ezview", "ezreg", and "ezpasswd") to point to where your "Perl5" is installed. They are distributed assuming "/usr/local/bin/perl5". 3) Beginning with PerlMenu version 4.0 the PerlMenu package is distributed as a "perlmenu.pm" file. The demos are written to "use perlmenu;" in Perl5 fashion. However, you may have "legacy" applications which require the old-style "menu.pl" module (which you have a "require" for in your code). Run the program "create_menu.pl" which will create "menu.pl" from "perlmenu.pm". Your old Perl5 applications should work fine using this module. Perl5 users should convert to use "perlmenu.pm" as soon as it is convenient. In general this conversion is simply finding your 'require "menu.pl";' statements and replacing them with 'use perlmenu.pm;' statements. You might also want to check out the new features in this release and tweek your code to use them. 4) If the "demo" script runs fine, skip this step. If not you probably have "terminfo" or "termcap" information retrieval problems. There are various ways different systems use to retrieve the escape sequences in use for the current terminal for generic functions (like "move the cursor up"). The two most common methods are "termcap" support (where there is a "termcap" file which you retrieve values from with a "getcap" subroutine call) and "terminfo" support (where there is a "terminfo" file which you retrieve values from with a "tput" command). Some systems (such as Solaris) may use "tigetstr" functions. This package is distributed with the assumption you have the older "termcap" support (and therefore have "getcap" incorporated into your Perl5+Curses support). If the demo script fails to run "out of the box" with the following (or similar) message: Curses function 'getcap' is not defined by your vendor ... or "seg faults" (DEC/OSF systems do this) you may have to comment/uncomment small portions of "perlmenu.pm" to reflect the terminal support on your system. A small Perl script called "install_hints.pl" is included to assist you in figuring out what to do at this point. Check the first line of "install_hints.pl" to make sure it is pointing to your "Perl5+Curses" location, then run it. It will try various things and (hopefully) suggest a method that will work on your system. It will indicate one (or more) "methods" that may work. Pick one and change things as indicated in one of the following sections: - Method 1 (getcap) You have "getcap" (or are told you can probably simulate it). Since the demo didn't work you probably have a "getcap" with bugs in it (there are some out there). Edit "perlmenu.pm" and scan for "# PERL5 ONLY (GETCAP PROBLEMS)". You will find a section of commented code below here that will simulate a correct "getcap" call (for Perl 5.001 and later). Locate and uncomment these statements so it looks like THIS and try again: # PERL5 ONLY (GETCAP PROBLEMS) # Uncomment these statements if you DON'T have "getcap()" OR # if the demo doesn't appear to work (there's a bug in some getcap's). # if ($] >= 5.001) { package Perl5::Menu_PL::Compat; # Don't pollute menu.pl namespace require Term::Cap; # Get Tgetent package $term = Tgetent Term::Cap { OSPEED => 9600 }; # Define entry sub perlmenu::getcap { $term->{"_" . shift()} }; # Define local subr } DO NOT comment out the code in "# Method 1 (getcap)" - since you are simulating getcap you need the "# Method 1 (getcap)" code, also. It should work now. Try the demo again. - Method 2 (tput) Edit the "perlmenu.pm" module and COMMENT OUT the statements in the "# Method 1 (getcap)" block. Locate the "# Method 3 (tput)" block of statements and UNCOMMENT those. Try the demo again. - Method 3 (tigetstr) Edit the "perlmenu.pm" module and COMMENT OUT the statements in the "# Method 1 (getcap)" block. Locate the "# Method 4 (tigetstr)" block of statements and UNCOMMENT those. Try the demo again. For any of these methods make sure ONLY ONE of the "Method 1", "Method 2", or "Method 3" sections is "live" (i.e not commented out). In addition, if you simulated getcap (under the "Method 1" section above) then "Method 1 (getcap)" must also NOT BE COMMENTED. As distributed, the first section (assuming you have "getcap") is live. A special note for HP-UX 9.05 users. If you are uncommenting the "tput" code, pay attention to the comment about "HP-UX 9.05 users" in the "Method 3 (tput)" area. If you don't have "tput", "tigetstr" or "getcap", you will have to hard-code the values needed (bad, because they are terminal specific) or find out how your system retrieves termcap or terminfo capabilities (and how you get that info via Perl). The general idea is to assign the proper string values to $ku, $kd, $kr, $kl, $cr, and $nl to indicate the "escape sequences" needed to perform the generic function. If you come up with a technique you think will benefit others be sure and send me email and I'll try to include it in a future release (email to "skunz@iastate.edu"). Note that if you have created a "menu.pl" module (with the "create_menu.pl" program in Step 3) you will have to make similar changes in the "menu.pl" source, too. 5) Put "perlmenu.pm" (and "menu.pl" if required) with the rest of your Perl packages (usually in something like "/usr/local/lib/perl5" or "/usr/local/lib/perl"). The demo programs will work by just leaving a copy of the modules in the same directory as the demo scripts. 6) Note that if you move the demo programs into a public area (and out of the distribution library), you should change the "use" and "require" statements as appropriate so they find the PerlMenu modules. ------------------------------- Installation for use with Perl4 ------------------------------- 1) If you don't have curseperl working and installed somewhere, go into your Perl 4.36 distribution (in the "usub" directory) and construct it following the instructions there. Install your "curseperl" in the same location as your normal "perl" binary. 2) Run the Perl program "create_menu.pl" (distributed with PerlMenus). This will convert the Perl5-style module "perlmenu.pm" to the Perl4-style module "menu.pl". You 'require "menu.pl";' under Perl4/curseperl (instead of the 'use perlmenu;' that you do under Perl5). Save the "perlmenu.pm" module for whenever you convert to Perl5. 3) You will have to modify the first line of the demo scripts ("demo", "demo_getstr", "demo_template", "demo_top", "demo_util", "ezview", "ezreg", and "ezpasswd") to point to where your "curseperl" is installed. They are distributed "Perl5-ready" (assuming your are using "/usr/local/bin/perl5" and have the Curses extension installed). You will also need to comment out the lines at the beginning of each demo script which set the "$Curses::OldCurses = 1;" flag and "use" the "Curses" and "perlmenu" packages (which you don't have on Perl4). You should un-comment the "require" statements for "menu.pl" and "menuutil.pl". Read the comments in the demos - they tell you what to do. 4) If the "demo" script runs fine, skip this step. If not you probably have "terminfo" or "termcap" information retrieval problems. There are various ways different systems use to retrieve the escape sequences in use for the current terminal for generic functions (like "move the cursor up"). The two most common methods are "termcap" support (where there is a "termcap" file which you retrieve values from with a "getcap" subroutine call) and "terminfo" support (where there is a "terminfo" file which you retrieve values from with a "tput" command). Some systems (such as Solaris) may use "tigetstr" functions. This package is distributed with the assumption you have the older "termcap" support (and therefore have "getcap" incorporated into your Perl4/curseperl support). If the demo script fails with the following (or similar) message: Undefined subroutine "main'getcap" called at line ... or "seg faults" (DEC/OSF systems do this) you may have to comment/uncomment small portions of "menu.pl" to reflect the terminal support on your system. Proceed as follows. - You may be able to simulate "getcap". Edit "menu.pl" and scan for "# PERL4 ONLY (GETCAP PROBLEMS)". You will find a section of commented code below here that will simulate a correct "getcap" call (for Perl4). Locate and uncomment these statements so it looks like THIS and try again: # PERL4 ONLY (GETCAP PROBLEMS) # Uncomment these statements if you DON'T have "getcap()" OR # if the demo doesn't appear to work (there's a bug in some getcap's). # if (($] >= 4.0) && ($] < 5.0)) { # Perl4 ONLY! package simgetcap; # Don't pollute menu.pl namespace $ispeed = $ospeed = 13; # Set old-style "9600"; require "termcap.pl"; # Get Tgetent package &Tgetent($ENV{'TERM'}); # Load $TC array sub main'simgetcap { $TC{shift}; }; # Define local subroutine } DO NOT comment out the code in "# Method 1 (getcap)" - since you are simulating getcap you need the "# Method 1 (getcap)" code, also. However, you will need to change the code at "# Method 1 (getcap)" to look like the following (since the simulated "getcap" is not called "getcap" but "simgetcap"): # Method 1 (getcap) # Uncomment if you have "getcap" $ku = &main'simgetcap('ku'); # Cursor-up $kd = &main'simgetcap('kd'); # Cursor-down $kr = &main'simgetcap('kr'); # Cursor-right $kl = &main'simgetcap('kl'); # Cursor-left $cr = &main'simgetcap('cr'); # Carriage-return $nl = &main'simgetcap('nl'); # New-line It should work now. Try the demo again. - It simulating "getcap" doesn't work, try the following command at a command prompt on your system: tput kcuu1 If the command is valid, you have "terminfo" (instead of "termcap") terminal control. If you don't have a "tput" command, your system may use "tigetstr" instead. The best way to proceed is to edit the "menu.pl" file, find the "menu_init" subroutine, and look for three blocks of code, each starting with the following comments: # Method 1 (getcap) # Uncomment if you have "getcap" [...] # Method 2 (tigetstr) # Uncomment if you have tigetstr (Solaris) instead of "getcap" [...] # Method 3 (tput) # Uncomment if you have terminfo (and tput) instead of "getcap" [...] Make sure ONLY ONE of these sections is "live" (i.e not commented out) and try each, one at a time. As distributed, the first section (assuming you have "getcap") is live. Hopefully one of the others will work. Since you probably already tried the "getcap" and "simulated getcap" methods, you need to commend out the code in the "Method 1 (getcap)" area and try the other two (one at a time). A special note for HP-UX 9.05 users. If you are uncommenting the "tput" code, pay attention to the comment about "HP-UX 9.05 users" in the "Method 3 (tput)" area. - If you don't have "tput", "tigetstr" or "getcap", you will have to hard-code the values needed (bad, because they are terminal specific) or find out how your system retrieves termcap or terminfo capabilities (and how you get that info via Perl). The general idea is to assign the proper string values to $ku, $kd, $kr, $kl, $cr, and $nl to indicate the "escape sequences" needed to perform the generic function. If you come up with a technique you think will benefit others be sure and send me email and I'll try to include it in a future release (email to "skunz@iastate.edu"). 5) Put "menu.pl" with the rest of your Perl packages (usually in something like "/usr/local/lib/perl"). The demo programs will work by just leaving a copy of the modules in the same directory as the demo scripts. 6) Note that if you move the demo programs into a public area (and out of the distribution library), you should change the "require" statements as appropriate so they find the PerlMenu modules. --- Steven L. Kunz Networked Applications Iowa State University Computation Center, Iowa State University, Ames IA INET: skunz@iastate.edu perlmenu-4.0.orig/menuutil.pl100660 1750 1750 16116 6273702655 16352 0ustar jgoerzenjgoerzen#**************************************************************************** # menuutil.pl -- Curses Utility Functions # # Version: 1.1 # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # # Official PerlMenu WWW home page: # http://www.cc.iastate.edu/perlmenu/ # # Official Package Distributions: # ftp://ftp.iastate.edu/pub/perl # # Bugs: skunz@iastate.edu # Cheers: skunz@iastate.edu # # Date: Version 1.0 -- January, 1995 -- Original version # Version 1.1 -- February, 1996 -- Added "clear_screen" # # Notes: Perl4 - Requires curseperl # Perl5 - Requires William Setzer's "Curses" extension # # Routines: &top_title -- Clear screen, center title # &print_nl -- Print text on screen # &new_line -- Skip to new line on screen # &query -- Ask question, validate response key # &pause -- Pause (with prompt) # &popup_ask -- Ask question in pop-up overlay box # &clear_screen -- Clear the screen # # PerlMenu - Perl library module for curses-based menus & data-entry templates # Copyright (C) 1992-97 Iowa State University Computation Center # Ames, Iowa (USA) # # This Perl library module is free software; you can redistribute it # and/or modify it under the terms of the GNU Library General Public # License (as published by the Free Software Foundation) or the # Artistic License. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free # Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #**************************************************************************** #*********** # CLEAR_SCREEN -- Clear screen (and row, col values) # # Arguments: Boolean flag (0=don't do refresh, 1=do refresh) # # Notes: #*********** sub clear_screen { local($do_refresh) = @_; &clear(); $row = $col = 0; if ($do_refresh) { &refresh(); } } #*********** # TOP_TITLE -- Center title at top of screen # # Arguments: Title string # # Notes: Title string is normally placed on screen centered in # "standout" rendition. If you do NOT want standout # rendition start the string with a "-" (it will not appear # in the title). #*********** sub top_title { local($title) = @_; local($title_col) = 0; local($title_standout) = 1; # Check for title format character. if (substr($title,0,1) eq '-') { $title = substr($title,1); $title_standout = 0; } # Truncate or center title as necessary if (length($title) > $COLS) { $title = substr($_[1],0,$COLS); } else { $title_col = int($COLS/2) - int(length($title)/2); } # Clear screen and put title at the top. &clear(); $row = $col = 0; &move(0,$title_col); if ($title_standout) { &standout(); } &addstr($title); $col += length($title); if ($title_standout) { &standend(); } # Setup row,col for those that follow. $row = 2; $col = 0; &move($row,$col); &refresh(); } #********** # PRINT_NL -- Print text followed by optional new-line(s) on screen. # # Arguments: - Text string # - New-line count. Optional #********** sub print_nl { local($text,$skip) = @_; # Check for end-of-line wrap while ($col+length($text) > $COLS) { &addstr(substr($text,0,$COLS)); $row++; $col = 0; &move($row,$col); $text = substr($text,$COLS); } # Put last (or only) chunk on the screen &addstr($text); $col += length($text); # Add any new-lines specified if ($skip) { &new_line($skip); } } #********** # NEW_LINE -- Skip to new line (with end-of-page clear) # # Arguments: New-line count #********** sub new_line { local($skip) = @_; $row += $skip; $col = 0; if ($row > $LINES - 1) { print "\007"; &refresh(); &clear(); $row = 0; $col = 0; &refresh(); } &move($row,$col); &refresh(); } #********** # QUERY -- Perform query of user # # Arguments: - Prompt text # - List of single-char values allowed ("ynq") # # Returns: One of the single characters from the "allowed" list. #********** sub query { local($prompt,$allowed) = @_; local($ch,$sel_prompt); local($nsl,$i) = 0; # Construct "allowed selections" part of the prompt. $nsl = length($allowed); if ($nsl < 1) { return; } $sel_prompt = "("; while ($i < $nsl) { $sel_prompt .= substr($allowed,$i,1)."|"; $i++; } chop($sel_prompt); $sel_prompt .= ")"; # Prompt until we get a good answer. while (1) { &getyx($window,$row,$col); $ch = &menu_getstr($row,$col,"$prompt $sel_prompt ",0); &new_line(1); if ($ch ne "") { $ch = substr($ch,0,1); $ch =~ tr/A-Z/a-z/; if (index($allowed,$ch) >= 0) { return($ch); } } print "\007"; &new_line(1); &print_nl("Invalid answer - must be one of $sel_prompt.",1); } } #********** # PAUSE -- Pause until key is pressed # # Arguments: Optional message text string. # Defaults to "[Press any key to continue]" # # Returns: Nothing. # # Note: This routine always skips to a new line first. #********** sub pause { local($msg) = @_; # Skip a row and put our message. $row += 1; $col=0; &move($row,$col); if ($msg eq "") { $msg = "[Press any key to continue]"; } &addstr($msg); # Leave cursor on a fresh line. $row++; &move($row,$col); # Refresh screen and wait for a keypress. &refresh(); $ch = &getch(); } #********** # POPUP_ASK -- Pop-up box to ask a question # # Function: Provides an outlined box, centered on the screen, to allow # edited data-entry by the user. # # Arguments: Note: All parms optional # - Prompt string # - Maximum data input length # - Default value string # - Boolean flag (0=show, 1=hidden) # - Boolean flag (0=alpha-numeric, 1=numeric) # # Returns: Value supplied by the user (may be null). #********** sub popup_ask { local($prompt,$maxlen,$default,$noshow,$numeric) = @_; local($box_row,$box_col,$box_win,$data_win,$val); # Compute some key values if (!$maxlen) { $maxlen = $COLS - length($prompt) - 2; } $box_row = int($LINES/2) - 2; $box_col = int($COLS/2) - int((length($prompt)+$maxlen)/2) - 1; if ($box_col < 0) { $box_col = 0; } # Create the main pop-up box (with the prompt in it) $box_win = &newwin(3,length($prompt)+$maxlen+2,$box_row,$box_col); &wmove($box_win,1,1); &waddstr($box_win,$prompt); &box($box_win,ord('|'),ord('-')); &wrefresh($box_win); # Create a second window for data entry within the main pop-up box $data_win = &newwin(1,$maxlen,$box_row+1,$box_col+length($prompt)+1); $val = &main'menu_getstr(0,0,"",0,$default,$maxlen, $noshow,$numeric,$data_win); # Clean up the data-entry window &wclear($data_win); &wrefresh($data_win); &delwin($data_win); # Clean up the pop-up window &wclear($box_win); &wrefresh($box_win); &delwin($box_win); # Clean up the main window and return value &touchwin($window); &refresh(); $val; } 1; perlmenu-4.0.orig/paint_text100660 1750 1750 272 6273422055 16202 0ustar jgoerzenjgoerzen -Welcome to Perl Menus! -This is version 4.0 of the PerlMenu system. -This text came from a text file processed into sub-titles. -The copyright notice at the bottom is a bottom-title. perlmenu-4.0.orig/FAQ100660 1750 1750 11370 6301157713 14471 0ustar jgoerzenjgoerzen perlmenu.pm Perl Menus Version 4.0 February 17, 1997 Steven L. Kunz Networked Applications Iowa State University Computation Center Iowa State University Ames, Iowa -------------------------- Frequently Asked Questions -------------------------- --------------------------- Where do I get "PerlMenus"? --------------------------- The PerlMenu package is distributed via "CPAN" (the "Comprehensive Perl Archive Network"). Pick a CPAN site near you with a WWW browser pointed at "http://www.perl.com/perl/CPAN/CPAN.html" and go into the "authors/Steven L Kunz" folder. You should find the latest release there. The author's official distribution is alos available via anonymous FTP from: ftp://ftp.iastate.edu/pub/perl/perlmenu.v..tar.Z New releases are announced in the Usenet newsgroups "comp.lang.perl.announce" and "comp.lang.perl.modules". ---------- The terminal state ("echo" and other settings) are not restored when exiting a PerlMenu application. ---------- This is usually due to either an obscure coding problem (outlined here) or a problem with your curses library (which you probably can do nothing about but can circumvent). Both situations are discussed here. The most common coding problem occurs when you write an application using curses calls yourself (and not letting PerlMenu do ALL the work). It may be the case you are using "menu_curses_application" and NOT calling "endwin" before exiting your application. Refer to the "menu_curses_application" routine documentation (in the "Other Menu-Related PerlMenu Routines" section of this document). You will find a sentence that indicates "You should make sure you issue an "endwin" call prior to exiting." when using the "menu_curses_application" routine. This "endwin" call is what restores the terminal environment on most systems. It is a subtle mistake (indeed, until version 4.0 of PerlMenu it was present in many of the demo programs included with PerlMenu!). Double-check your code for an "endwin" at every exit point if you use "menu_curses_application" in your code. If you have code that looks like this at the top of your program: $window = &initscr(); &menu_curses_application($window); then you will need this at every exit point: &endwin; Sometimes you can code the "endwin" routine as your "menu_quit_routine". For example: &menu_quit_routine( "endwin" ); If you have other code to do in a "menu_quit_routine", include "&endwin" near the end. Make sure you are covered by a call to "endwin" at any other exit points within your code. If you continue to have problems with terminal settings after checking for the above conditions, you may have a problem in your curses library (built into your version of Perl) that prevents proper restoration of the "tty" settings. A circumvention that works is restore the terminal settings yourself before you exit your code (again, the same place your "endwin" calls are located - probably AFTER them). Include a Perl command like the following: [...] &endwin; system("stty sane"); [...] This UNIX command restores a general default environment to your tty terminal on many UNIX systems. You can check on your particular "stty" options and only turn back on the ones that you know are bad ('system("stty echo");' or whatever). Experiment with the "stty" command AFTER exiting your application to see what restores the terminal on your system, then code that into your application in all the appropriate exit points. ---------- The demos don't work right. It looks like everything I type is "buffered up" and not acted upon right away, then a whole bunch happens at once! ---------- Try placing the following line at the beginning of your main code (before the first call to "menu_init": $| = 1; # Flush after every write to stdout This forces STDOUT to flush after every "write" or "print". Many systems default to "line buffering" by default for output to the terminal. ---------- I want to mix menus and templates. For example, I want to put a three item "radio" button menu on my input template to simplify setting something. ---------- Sorry, you can't do this (yet). It is on the list of "things to do". perlmenu-4.0.orig/template_data100660 1750 1750 1140 6122026572 16637 0ustar jgoerzenjgoerzen Template Entry Demonstration Address Data Example Record # ___ Name: [_____________________________________________] Addr: [_____________________________________________] City: [__________________] State: [__] Zip: [\\\\\] Phone: (\\\) \\\-\\\\ Password: [^^^^^^^^] Enter all information available. Edit fields with left/right arrow keys or "delete". Switch fields with "Tab" or up/down arrow keys. Indicate completion by pressing "Return". Refresh screen with "Control-L". Abort this demo here with "Control-X". perlmenu-4.0.orig/template_ezp100770 1750 1750 606 6273422217 16517 0ustar jgoerzenjgoerzen Perl Menu Version 4.0 BSD Password File Display /etc/passwd line number ____ login: ________ password: ^^^^^^^^ UID: ____ GID: ____ Comment: _____________________________________________ Home dir: _____________________________________________ Shell: _____________________________________________perlmenu-4.0.orig/template_reg100660 1750 1750 1704 6122026572 16511 0ustar jgoerzenjgoerzen Template Demonstration Personal Account Information Move between fields with the TAB, Up and Down arrow keys. ONLY when you have completed all of the fields, press the RETURN key. Use Control-L to refresh the screen. Use Control-X to abort. First Name [________________________________________] Middle Name [________________________________________] Last Name [________________________________________] Daytime Area Code & Phone Number [____________________] Institution Name [________________________________________] Institution Street Address [________________________________________] Institution City, State, ZIP [________________________________________] Is this address in the U.S.A.? [_] Y or N ---Fields marked with "*" are required! perlmenu-4.0.orig/perlmenu.pm100660 1750 1750 217343 6301150513 16343 0ustar jgoerzenjgoerzen#**************************************************************************** # perlmenu.pm -- Perl Menu Support Facility # # Version: 4.0 # # Author: Steven L. Kunz # Networked Applications # Iowa State University Computation Center # Ames, IA 50011 # # Major Contributors (Version 3.0, 3.1): # Chris Candreva (chris@westnet.com) # WestNet Internet Services of Westchester # # Alan Cunningham # NASA Spacelink Project # # Official PerlMenu WWW home page: # http://www.cc.iastate.edu/perlmenu/ # # Official Package Distributions: # ftp://ftp.iastate.edu/pub/perl # # Bugs: skunz@iastate.edu # Cheers: skunz@iastate.edu # # Date: Version 1.0 -- May, 1992 -- Original version # Version 1.1 -- Aug, 1992 -- Minor enhancements, bugfixes # Version 1.2 -- Nov, 1992 -- Selection bugfix # Version 1.3 -- Dec, 1992 -- "top" and "latch" functions added # Version 1.4 -- Apr, 1993 -- "r=refresh" added to bottom line # Version 2.0 -- Sep, 1993 -- Radio-button, Multiple-selection, # shell-escape, new "hot-keys", and # "menu_getstr" routine. # Version 2.1 -- Oct, 1993 -- Bug fixes # Version 2.2 -- Mar, 1994 -- Menu sub-titles # Version 2.3 -- Jun, 1994 -- Bug fixes # Version 3.0 -- Jan, 1995 -- Templates, lots of new options on # many calls, Perl5 interfacing. # Version 3.1 -- Mar, 1995 -- Bug fixes, new "menu_template_setexit" # call, new menu_pref. # Version 3.2 -- Jun, 1995 -- Bug fixes, template "required field" # support, template Control-L refresh. # Version 3.3 -- Feb, 1996 -- Bug fixes, help routines, templates # from arrays ("menu_load_template_array") # Version 4.0 -- Feb, 1997 -- Converted to "pm" module, highlighted # selection cursor pref, Multiple-column # menus pref, bug fixes # # Notes: Perl4 - Requires "curseperl" # (distributed with perl 4.36 in the usub directory) # Perl5 - Requires "Curses" extension available from any CPAN # site (http://www.perl.com/CPAN/CPAN.html). # # Put the following at top of your code: # # BEGIN { $Curses::OldCurses = 1; } # use Curses; # # Use: # &menu_init(1,"title"); # &menu_item("Topic 1","got_1"); # &menu_item("Topic 2","got_2"); # ... # &menu_item("Topic n","got_n"); # $sel_text = &menu_display("Select using arrow keys"); # # PerlMenu - Perl library module for curses-based menus & data-entry templates # Copyright (C) 1992-97 Iowa State University Computation Center # Ames, Iowa (USA) # # This Perl library module is free software; you can redistribute it # and/or modify it under the terms of the GNU Library General Public # License (as published by the Free Software Foundation) or the # Artistic License. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free # Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # #**************************************************************************** package perlmenu; #%PERL5ONLY% DO NOT REMOVE OR CHANGE THIS LINE BEGIN { $Curses::OldCurses = 1; } use Curses; require Exporter; @ISA = qw(Exporter); @EXPORT = qw( menu_curses_application menu_prefs menu_template_prefs menu_shell_command menu_quit_routine menu_init menu_paint_file menu_setexit menu_getexit menu_item menu_display menu_display_radio menu_display_mult menu_getstr menu_template_setexit menu_load_template menu_load_template_array menu_overlay_clear menu_overlay_template menu_display_template ); #%PERL5ONLY% DO NOT REMOVE OR CHANGE THIS LINE # PERL5 ONLY (GETCAP PROBLEMS) # Uncomment these statements if you DON'T have "getcap()" OR # if the demo doesn't appear to work (there's a bug in some getcap's). # #if ($] >= 5.001) { # Perl5 ONLY! #package Perl5::Menu_PL::Compat; # Don't pollute perlmenu.pm namespace #require Term::Cap; # Get Tgetent package #$term = Tgetent Term::Cap { OSPEED => 9600 }; # Define entry #sub perlmenu::getcap { $term->{"_" . shift()} }; # Define local subroutine #} # PERL4 ONLY (GETCAP PROBLEMS) # Uncomment these statements if you DON'T have "getcap()" OR # if the demo doesn't appear to work (there's a bug in some getcap's). # #if (($] >= 4.0) && ($] < 5.0)) { # Perl4 ONLY! #package simgetcap; # Don't pollute menu.pl namespace #$ispeed = $ospeed = 13; # Set old-style "9600"; #require "termcap.pl"; # Get Tgetent package #&Tgetent($ENV{'TERM'}); # Load $TC array #sub main'simgetcap { $TC{shift}; }; # Define local subroutine #} # Preferences (set by "menu_pref") $curses_application = 0; # Application will do initscr, endwin $center_menus = 0; # Center menus $gopher_like = 0; # More gopher-like arrow keys $disable_quit = 0; # Disable "Quit" hot-key $quit_prompt = ""; # Override Quit prompt $quit_default = "y"; # Quit default response $multiple_column = 0; # Multiple column menus $highlight = 0; # Highlight selection points $menu_exit_routine = "main'clear"; $menu_generic_help_routine = "menu_default_show_help"; $menu_item_help_routine = ""; $menu_shell_text = ""; $menu_is_first_one = 1; $menu_is_top_one = 0; $menu_top_activated = 0; $finding_top = 0; @menu_sel_text = (); # Menu item selection text @menu_sel_action = (); # Menu item actions @selected_action = (); # Menu item selected flags (multiple-selection menus) @menu_sub_title = (); # Top Sub-title strings $menu_sub_titler = ""; # Top Sub-title builder routine @menu_bot_title = (); # Bottom title strings $menu_bot_titler = ""; # Bottom title builder routine $did_initterm = 0; # We already got escape sequences for arrows, etc. $window = 0; # Base window $xrow = $xcol = 0; $first_line = $last_line = $item_lines_per_screen = 0; $items_per_screen = $items_per_line = 0; $arrow_col = $arrow_line = 0; $max_sel_line = $max_sel_col = 0; $menu_top_item = 0; $arrow_spec_row = $arrow_spec_col = 0; @menu_exitkeys = (); # Exit-key strings $menu_lastexit = ""; # Exit-key string that caused the last exit $show_mail = ""; $max_item_len = 0; # Length of longest selection text $left_margin = 0; # Leftmost column of menu (for centering) $prepend_len = 0; # Length of text we prepend to each selection $column_width = 0; # Width of each item in column $ku = $ansi_ku = $kd = $ansi_kd = ""; $field = 0; # Count of loaded template fields $template_exit_active = 0; # Currently processing a template user exit @template_exitkeys = (); # Exit-key strings @menu_template_line = (); # Template text line @menu_template_row = (); # Data entry rows @menu_template_col = (); # Data entry cols @menu_template_len = (); # Data entry lengths @menu_template_type = (); # Data entry type # (0=alpha-numeric, 1=numeric, 2=no-show) $last_window_cpos = 0; # Storage to last windows cursor position. @menu_overlay_row = (); # Template overlay row @menu_overlay_col = (); # Template overlay col @menu_overlay_text = (); # Template overlay text @menu_overlay_rend = (); # Template overlay rendition @menu_overlay_stick = (); # Template overlay "sticky" flags $req_lmark_set = "*"; # Marker for required fields - left (set) $req_lmark_clear = " "; # Marker for required fields - left (clear) $req_lmark_attr = 0; # Marker attribute - left (0=normal,1=standout) $req_rmark_set = ""; # Marker for required fields - right (set) $req_rmark_clear = ""; # Marker for required fields - right (clear) $req_rmark_attr = 0; # Marker attribute - right (0=normal,1=standout) @req_mark_row = (); # Required field markers - rows @req_lmark_col = (); # Required field markers - left cols @req_rmark_col = (); # Required field markers - right cols # Simple emacs-style editing key definitions $begin_of_line = "\cA"; $end_of_line = "\cE"; $next_char = "\cF"; $prev_char = "\cB"; $next_field = "\cN"; $prev_field = "\cP"; $redraw_screen = "\cL"; $delete_right = "\cD"; $kill_line = "\cK"; # Normally yank_line would be "\cY" (C-y), unfortunately both C-z and C-y are # are used to send the suspend signal in our environment. Bind it to # C-u for a lack of anything better. $yank_line = "\cU"; # buffer $kill_buffer = ""; #********** # MENU_CURSES_APPLICATION # # Function: Indicate application is using curses calls. If called, # the menu routines will not do initscr and endwin calls # (the application must do them). # # Call format: &menu_curses_application(window); # # Arguments: The main window (gotten from an initscr call) # # Returns: Main window (either passed in or gotten here) #********** sub menu_curses_application { ($window) = @_; $curses_application = 1; # Sanity check. If no window, get one. if (!$window) { $window = &initscr(); } $window; } #********** # MENU_PREFS # # Function: Establish general default preferences for menu style. # # Call format: &menu_pref(center_menus,gopher_like,quit_flag,quit_prompt, # quit_def_resp,mult_col_menu,highlight_sel_text); # # Arguments: - Boolean flag (0=left justified menus, 1=centered menus) # - Boolean flag (0=normal, 1=more gopher-like) # - Boolean flag (0=allow quit, 1=disable quit) # - String with default "Quit" prompt # - String with "Quit" default response character # - Boolean flag (0=single column menus, 1=multiple column menus # - Boolean flag (0=arrow in front of selection text, # 1=highlight selection text (no arrow) # # Returns: Nothing #********** sub menu_prefs { ($center_menus,$gopher_like,$disable_quit,$quit_prompt,$quit_default, $multiple_column,$highlight) = @_; # Don't allow bad default characters. if (($quit_default ne "Y") && ($quit_default ne "y") && ($quit_default ne "N") && ($quit_default ne "n")) { $quit_default = "y"; } } #********** # MENU_TEMPLATE_PREFS # # Function: Establish general default preferences for templates. # # Call format: &menu_template_pref(mark-set-left,mark-clear-left,left-attr, # mark-set-right,mark-clear-right,right-attr); # # Arguments: - Required field marker flag string (for left of field) # - Required field marker flag clear string (for left of field) # - Attribute for left marker (0=normal,1=standout) # - Required field marker flag string (for right of field) # - Required field marker flag clear string (for right of field) # - Attribute for right marker (0=normal,1=standout) # # Returns: Nothing #********** sub menu_template_prefs { ($req_lmark_set,$req_lmark_clear,$req_lmark_attr, $req_rmark_set,$req_rmark_clear,$req_rmark_attr) = @_; } #********** # MENU_SHELL_COMMAND # # Function: Enable "!" as shell escape from a menu and indicate the # command that should be issued. # # Call format: &menu_shell_command("shell-path command"); # # Arguments: Shell path (such as "/bin/csh") to start shell spawn-off. # If null value is supplied, shell escape is disabled. # # Returns: Nothing #********** sub menu_shell_command { ($menu_shell_text) = @_; } #********** # MENU_QUIT_ROUTINE # # Function: Specify a "cleanup" routine to be called before a "quit" # from the application is processed. # # Call format: &menu_quit_routine("string"); # # Arguments: String containing name of exit routine to call. # # Returns: Nothing. # #********** sub menu_quit_routine { $menu_exit_routine = "main'@_"; } #********** # MENU_HELP_ROUTINE # # Function: Specify a "help" routine to be called when "h" or "H" # is pressed during menu display. # # Call format: &menu_help_routine("string"); # # Arguments: String containing name of help routine to call. # If a null string is provided, the default routine is used. # # Returns: Nothing. # #********** sub menu_help_routine { local($rtn) = @_; if ($rtn eq "") { $menu_generic_help_routine = "menu_default_show_help"; } else { $menu_generic_help_routine = "main'$rtn"; } } #********** # MENU_INIT # # Function: Initialize menu type (numbered or unnumbered), arrays, # title, and "top" flags. # # Call format: &menu_init([0|1],"Top Title",[0|1],"Sub Titles"); # # Arguments: Boolean flag indicating whether or not a arrows and numbers # are desired (0=no, 1=yes) and title text (for the top line # of menu), an optional boolean top-menu indicator, and an # optional sub-title. # # Returns: Window value from "initscr" call. # # Notes: 1) If the title string begins with a "-" the title is not # presented in reverse-video ("standout") representation. # 2) Optional sub-titles have two controls characters (which # are order dependant. A "-" functions as in the title. # A "<" or ">" as the next character (or first, if "-" # is not used) performs left or right justification. # 3) If this is the FIRST menu_init call and the optional # third opernd is "1", it is the "top" menu. #********** sub menu_init { ($menu_numbered,$menu_top_title,$menu_is_top_one,$sub_titles,$bot_titles, $item_help) = @_; local($i,$justify); # Perform initscr if not a curses application if (!$curses_application && !$window) { $window = &initscr(); } # Load "magic sequence" array based on terminal type if (!$did_initterm) { # Get terminal info (if we don't have it). &defbell() unless defined &bell; # Method 1 (getcap) # Uncomment if you have "getcap" $ku = &getcap('ku'); # Cursor-up $kd = &getcap('kd'); # Cursor-down $kr = &getcap('kr'); # Cursor-right $kl = &getcap('kl'); # Cursor-left $cr = &getcap('cr'); # Carriage-return $nl = &getcap('nl'); # New-line # Method 2 (tigetstr) # Uncomment if you have tigetstr (Solaris) instead of "getcap" # $ku = &tigetstr('kcuu1'); # Cursor-up # $kd = &tigetstr('dcud1'); # Cursor-down # $kr = &tigetstr('kcuf1'); # Cursor-right # $kl = &tigetstr('kcub1'); # Cursor-left # $cr = &tigetstr('cr'); # Carriage-return # $nl = &tigetstr('nl'); # New-line # Method 3 (tput) # Uncomment if you have terminfo (and tput) instead of "getcap" # $ku = `tput kcuu1`; # Cursor-up # $kd = `tput kcud1`; # Cursor-down # $kr = `tput kcuf1`; # Cursor-right # $kl = `tput kcub1`; # Cursor-left # $cr = `tput kent`; # Carriage-return # # HP-UX 9.05 users: try $cr = `tput cr` if # # "tput kent" gives errors # $nl = `tput nel`; # New-line $ansi_ku = "\033[A"; # Ansi cursor-up (for DEC xterm) $ansi_kd = "\033[B"; # Ansi cursor-down (for DEC xterm) $ansi_kr = "\033[C"; # Ansi cursor-right (for DEC xterm) $ansi_kl = "\033[D"; # Ansi cursor-left (for DEC xterm) @magic_seq = ($ku,$ansi_ku,$kd,$ansi_kd,$kl,$ansi_kl,$kr,$ansi_kr, $cr,$nl,"\n", "n","N"," ","p","P","b","B","e","E", $begin_of_line, $end_of_line, $next_char, $prev_char, $next_field, $prev_field, $redraw_screen, $delete_right, $kill_line, $yank_line, "a","A","c","C","m","M","=","/","h","H","?","!"); $did_initterm = 1; } # Check for title format character. $menu_top_title_attr = 0; if (substr($menu_top_title,0,1) eq '-') { $menu_top_title = substr($menu_top_title,1); $menu_top_title_attr = 1; } # Center top title if (length($menu_top_title) >= $main'COLS) { $menu_top_title = substr($menu_top_title,0,$main'COLS-1); $menu_top_title_col = 0; } else { $menu_top_title_col = int($main'COLS/2) - int(length($menu_top_title)/2); } # Process any sub-titles like the title. @menu_sub_title = (); $menu_sub_titler = ""; @menu_bot_title = (); $menu_bot_titler = ""; $first_line = 2; # Assume no sub-titles for now $last_line = $main'LINES - 3; # Assume no bottom-titles for now if ($sub_titles ne "") { if ($sub_titles =~ /^&/) { $menu_sub_titler = "main'".substr($sub_titles,1); # Run-time routine } else { $first_line += &proc_titles($sub_titles,*menu_sub_title, *menu_sub_title_attr,*menu_sub_title_col); } } if ($bot_titles ne "") { if ($bot_titles =~ /^&/) { $menu_bot_titler = "main'".substr($bot_titles,1); # Run-time routine } else { $last_line -= &proc_titles($bot_titles,*menu_bot_title, *menu_bot_title_attr,*menu_bot_title_col); $last_line--; # Blank line between menu and bottom titles } } $item_lines_per_screen = $last_line - $first_line + 1; $arrow_line = $first_line; # Arrow on top item by default $arrow_col = 0; # Arrow on leftmost item by default # Process item help routine. $menu_item_help_routine = ""; if ($item_help) { $menu_item_help_routine = "main'$item_help"; } # Enable "top menu" functions if first menu is a top menu. if ($menu_is_first_one && $menu_is_top_one) { $menu_top_activated = 1; } $menu_is_first_one = 0; # Init selection array @menu_sel_text = (); # Selection text for each item @menu_sel_action = (); # Action text for each item @selected_action = (); # Selected items (multiple selection menus) $menu_index = 0; # Reset flags # Init some other key variables $menu_top_item = 0; # First item is the top item by default $last_menu_top_item = -1; # Force drawing of menu items $max_item_len = 0; # Reset max length # Return window value from "initscr" call. $window; } #*********** # MENU_PAINT_FILE # # Function: Define a text file to display with a menu # # Call format: &menu_paint_file("name_of_file",top_bottom_flag); # # Arguemnts: - File name to display # - Location (0=sub-title area, 1=bottom-title area # # Returns: 0=Success, 1=Cannot open file #*********** sub menu_paint_file { ($paint_file,$top_bot) = @_; local($concat_string,$i); open(INFILE,$paint_file) || return(1); # Reset appropriate array and first or last line if ($top_bot == 0) { @menu_sub_title = (); $menu_sub_titler = ""; $first_line = 2; # Changing first menu line } else { @menu_bot_title = (); $menu_bot_titler = ""; $last_line = $main'LINES - 3; # Changing last menu line } # Suck up file into a title string $i = 0; $concat_string = ""; while () { $concat_string .= $_; } close(INFILE); # Process title string as normal into top/bottom titles if ($top_bot == 0) { $first_line += &proc_titles($concat_string,*menu_sub_title, *menu_sub_title_attr,*menu_sub_title_col); } else { $last_line -= &proc_titles($concat_string,*menu_bot_title, *menu_bot_title_attr,*menu_bot_title_col); $last_line--; # Blank line between menu and bottom titles } # Re-calculate some key variables $arrow_line = $first_line; # Arrow on top item by default $arrow_col = 0; 0; } #********* # MENU_SETEXIT # # Function: Set the keys for exiting MENU_GETSTR # # Call format: &menu_setexit(@exit_key_array); # OR # &menu_setexit("exit_seq1","exit_seq2",...); # # Arguments: exit_key_array - the keys to end menu_getstr on #********** sub menu_setexit { @menu_exitkeys = @_; } #********** # MENU_GETEXIT # # Function: Returns the key last used to exit menu_getstr # #********** sub menu_getexit { return($menu_lastexit); } #*********** # PROC_TITLES # # Function: Process title string into sub-title/bottom title arrays. # # Call format: &proc_titles("String",*string_array,*attr_array,*col_array); # # Arguments: String presented in menu, array to load. # # Returns: Number of items loaded into the array. #*********** sub proc_titles { local($title_strings,*temp_title,*temp_title_attr,*temp_title_col) = @_; local($i); # If the title is a function, we will process it at display time. if ($title_strings =~ /^&/) { $temp_title[0] = substr($title_strings,1); $temp_title_col[0] = -1; $temp_title_attr[0] = -1; return(1); } @temp_title = split('\n',$title_strings); if ($#temp_title < 0) { return(0); } for ($i = 0; $i <= $#temp_title; $i++) { # Figure out rendition. $temp_title_attr[$i] = 0; if (substr($temp_title[$i],0,1) eq '-') { $temp_title[$i] = substr($temp_title[$i],1); $temp_title_attr[$i] = 1; } # Figure out justification. $justify = substr($temp_title[$i],0,1); if (($justify eq "<") || ($justify eq ">")) { $temp_title[$i] = substr($temp_title[$i],1); } else { $justify = ""; } if (length($temp_title[$i]) >= $main'COLS-1) { $temp_title[$i] = substr($temp_title[$i],0,$main'COLS-1); $temp_title_col[$i] = 0; } else { if ($justify eq "<") { $temp_title_col[$i] = 0; } elsif ($justify eq ">") { $temp_title_col[$i] = $main'COLS - length($temp_title[$i]) - 1; } else { $temp_title_col[$i] = int($main'COLS/2) - int(length($temp_title[$i])/2); } } } $i; # Return number of items processed } #*********** # MENU_ITEM # # Function: Add an item to the active menu. # # Call format: &menu_item("What you see","test_rtn",pre_set_flag); # # Arguments: - String presented in menu. Required. # - String returned if selected. Optional. # - Value to pre-set multiple selection menu. Optional. # (neg=lockout selection,0=allow selection,1=preset selection) # # Returns: Number of items currently in the menu. #*********** sub menu_item { local($item_text,$item_sel,$item_set) = @_; # Sanity check if ($item_lines_per_screen <= 0) { return(0); } if (!$item_text) { return($menu_index); } if (!$item_set) { $item_set = 0; } # Adjust max length value (for centering menu) $_ = length($item_text); if ($_ > $max_item_len) { $max_item_len = $_; } # Load into arrays and adjust index $menu_sel_text[$menu_index] = $item_text; $menu_sel_action[$menu_index] = $item_sel; $selected_action[$menu_index] = $item_set; ++$menu_index; } #********** # MENU_DISPLAY # # Function: Display items in menu_sel_text array, allow selection, and # return appropriate selection-string. # # Call format: $sel = &menu_display("Prompt text",$arrow_line,$top_item); # # Arguments: - Prompt text (for the bottom line of menu). # - Line number offset for the arrow (defaults to zero). # - Index of top item on screen (defaults to zero). # - Column number offset for the arrow (multiple-column mode # only, defaults to zero). # # Returns: Selected action string (from second param on &menu_item) # %UP% -- "u"|"U" pressed (or "t"|"T" and looking for top) # %EMPTY% -- Nothing in menu to display # # Notes: 1) This routine ALWAYS sets "nocbreak" and "echo" terminal # modes before returning. # 2) This routine exits directly (after calling the optional # "quit" routine) if "q"|"Q" is pressed. #********** sub menu_display { ($menu_prompt,$arrow_spec_row,$menu_top_item,$arrow_spec_col) = @_; local($ret); # Check for no "menu_item" calls. $total_items = $#menu_sel_text + 1; if ($total_items <= 0) { &nocbreak(); # ALWAYS turn off "cbreak" mode &echo(); # ALWAYS turn on "echo" return("%EMPTY%"); } &clear(); $xrow = $xcol = 0; $last_menu_top_item = -1; # Force drawing of menu items $ret = &menu_display_internal(0,$menu_prompt,0); if ($#_ > 0) { $_[1] = $arrow_spec_row; } if ($#_ > 1) { $_[2] = $menu_top_item; } if ($#_ > 2) { $_[3] = $arrow_spec_col; } &menu_return_prep(); $ret; } #********** # MENU_DISPLAY_RADIO # # Function: Display items in "radio-button" style. # # Call format: $sel = &menu_display_radio("Prompt text","current","Done"); # # Arguments: - Prompt text (for the bottom line of menu). # - Current setting (one of the "action-texts" that is the # current setting. # - Text for "done with setting" top menu item # Optional - defaults to "(Accept this setting)" # # Returns: Selected action string (from second param on &menu_item) # %UP% -- "u"|"U" pressed (or "t"|"T" and looking for top) # %EMPTY% -- Nothing in menu to display # # Notes: 1) This routine ALWAYS sets "nocbreak" and "echo" terminal # modes before returning. # 2) This routine exits directly (after calling the optional # "quit" routine) if "q"|"Q" is pressed. #********** sub menu_display_radio { ($menu_prompt,$current,$done_text) = @_; # Check for no "menu_item" calls. $total_items = $#menu_sel_text + 1; if ($total_items <= 0) { &nocbreak(); # ALWAYS turn off "cbreak" mode &echo(); # ALWAYS turn on "echo" return("%EMPTY%"); } &clear(); $xrow = $xcol = 0; $last_menu_top_item = -1; # Force drawing of menu items $arrow_spec_row = $arrow_spec_col = $menu_top_item = 0; # Reset # Insert our top selection item (and adjust max length value) if ($done_text eq "") { $done_text = "(Accept this setting)"; } $_ = length($done_text); if ($_ > $max_item_len) { $max_item_len = $_; } unshift(@menu_sel_text,$done_text); unshift(@menu_sel_action,"%DONE%"); $menu_index++; while (1) { $ret = &menu_display_internal(1,$menu_prompt,$current); last if $ret eq "%DONE%"; if ($ret eq "%UP%") { &menu_return_prep(); return($ret); } $current = $ret; } &menu_return_prep(); $current; } #********** # MENU_DISPLAY_MULT # # Function: Display items in "multiple selection" format. # # Call format: $sel = &menu_display_mult("Prompt text","Done"); # # Arguments: - Prompt text (for the bottom line of menu) # - Text for "done with selections" top menu item # Optional - defaults to "(Done with selections)" # # Returns: Selected action string (from second param on &menu_item) # %UP% -- "u"|"U" pressed (or "t"|"T" and looking for top) # %NONE% -- No items selected # %EMPTY% -- Nothing in menu to display # # Notes: 1) This routine ALWAYS sets "nocbreak" and "echo" terminal # modes before returning. # 2) This routine exits directly (after calling the optional # "quit" routine) if "q"|"Q" is pressed. #********** sub menu_display_mult { ($menu_prompt,$done_text) = @_; local($i,$ret) = 0; # Check for no "menu_item" calls. $total_items = $#menu_sel_text + 1; if ($total_items <= 0) { &nocbreak(); # ALWAYS turn off "cbreak" mode &echo(); # ALWAYS turn on "echo" return("%EMPTY%"); } &clear(); $xrow = $xcol = 0; $last_menu_top_item = -1; # Force drawing of menu items $arrow_spec_row = $arrow_spec_col = $menu_top_item = 0; # Reset # Insert our top selection item (and adjust max length value) if ($done_text eq "") { $done_text = "(Done with selections)"; } $_ = length($done_text); if ($_ > $max_item_len) { $max_item_len = $_; } unshift(@menu_sel_text,$done_text); unshift(@menu_sel_action,"%DONE%"); unshift(@selected_action,0); $menu_index++; # Loop, allowing toggle of selections, until done. while (1) { $ret = &menu_display_internal(2,$menu_prompt,0); last if $ret eq "%DONE%"; if (($ret eq "%UP%") || ($ret eq "%EMPTY%")) { @selected_action = (); &menu_return_prep(); return($ret); } if ($selected_action[$item] >= 0) { if ($selected_action[$item]) { $selected_action[$item] = 0; } #Toggle off else { $selected_action[$item] = 1; } # Toggle on } else { &bell(); } } # Format the return string based on selections. $ret = ""; $i = 1; while ($i < $menu_index) { if ($selected_action[$i] > 0) { $ret .= "$menu_sel_action[$i],"; } $i++; } chop($ret); # Remove final comma @selected_action = (); if ($ret eq "") { $ret = "%NONE%"; } &menu_return_prep(); $ret; } #********** # MENU_GETSTR # # Function: Prompt for a string (allowing editing) from one row of the # screen. # # Call format: $string = &menu_getstr(row,col,"Prompt text",clr_flag, # "Initial value",maxlen,noshow, # data-type,window); # # Arguments: - Row,Col for prompt and data-input. Required. # - Prompt text. Optional. Default=""; # - Boolean flag (0=leave line on exit, 1=clear line on exit) # Optional. Default=0. # - Initial value. Optional. Default="". # - Max length of input field. Optional. # - Boolean flag (0=show,1=hidden) (use "hidden" for passwords) # Optional. Default=0. # - Data-type (0=alphanumeric,1=numeric). Optional. Default=0. # - Window value. Optional. Default=main window. # - Cursor position (not offset). Optional. # Default=end of "Initial value". # # Returns: String (can be null) # # Notes: 1) This routine ALWAYS sets "nocbreak" and "echo" terminal # modes before returning. # 2) This routine checks for the right edge of the screen. #********** sub menu_getstr { local($row,$col,$prompt,$cleanup,$default,$maxlen,$noshow,$dtype,$win,$cpos) = @_; local($prompt_col,$left_col,$action,$string,$i,$overstrike); local ($stars); if (!$win) { $win = $window; } # Use main window by default # Set cbreak, noecho. &cbreak(); &noecho(); # Make sure the default is not longer than the maximum lengths if (($maxlen > 0) && (length($default) > $maxlen)) { $default = substr($default,0,$maxlen); } # Clear our area. Place prompt and any default on the screen &wmove($win,$row,$col); &wclrtoeol($win); if ($prompt ne "") { &waddstr($win,$prompt); } if ($default ne "") { if ($noshow) { for ($i = 0; $i < length($default); $i++) { &waddstr($win,"*"); } } else { &waddstr($win,$default); } } # Position cursor for data input $prompt_col = $col; $left_col = $prompt_col + length($prompt); if (!$cpos) { $col = $left_col + length($default); } else { $col = $cpos - 1; } &wmove($win,$row,$col); &wrefresh($win); # Set max col to right edge of screen if maxlen passed. # If single character field, allow "overstrike" mode. if ($maxlen == 0) { $maxcol = $main'COLS; } else { $maxcol = $prompt_col + length($prompt) + $maxlen; } if ($maxcol - $left_col == 1) { $overstrike = 1; } else { $overstrike = 0; } $string = $default; if (!$cpos) { $i = length($string); } else { $i = $cpos - 1; } $menu_lastexit = "\n"; # Perform editing until "Return" pressed. while (1) { $action = &collect_seq($win); if ($#menu_exitkeys >= 0) { &check_exit_keys(); } # Check any exit keys if (($action eq $kr) || ($action eq $ansi_kr) || ($action eq $next_char) ) { # Right-arrow if ($i+1 > length($string)) { &bell(); } else { $col++; $i++; &wmove($win,$row,$col); } } elsif (($action eq $kl) || ($action eq $ansi_kl) || ($action eq $prev_char) ) { # Left-arrow if ($i-1 < 0) { &bell(); } else { $col--; $i--; &wmove($win,$row,$col); } } elsif (($action eq "\177") || ($action eq "\010")) { # Delete/BS if ($i-1 < 0) { &bell(); } else { $col--; $i--; &wmove($win,$row,$col); &wdelch($win); $string = substr($string,0,$i).substr($string,$i+1); } } elsif ($action eq $delete_right) { # Delete right if ($i < length($string)) { &wdelch($win); $string = substr($string,0,$i).substr($string,$i+1); } else { &bell(); } } elsif (($action eq $cr) || ($action eq $nl) || ($action eq "\n")) { # Terminate $last_window_cpos = $col + 1; # Save current column (not offset) if ($cleanup) { &wmove($win,$row,$prompt_col); # Clear our stuff &wclrtoeol($win); &wrefresh($win); } &nocbreak(); # ALWAYS turn off "cbreak" mode &echo(); # ALWAYS turn on "echo" return($string); } elsif (($action eq $ku) || ($action eq $ansi_ku) || ($action eq $next_field) || ( $action eq $prev_field ) || ($action eq $kd) || ($action eq $ansi_kd)) { ; # Ignore } elsif ($action eq $begin_of_line) { # Go to begin-of-line $col = $prompt_col + length($prompt); $i=0; &wmove($win,$row,$col); } elsif ($action eq $end_of_line) { # Go to end-of-line $col = $prompt_col + length($prompt) + length($string); $i = length($string); &wmove($win,$row,$col); } elsif ($action eq $kill_line) { # Delete to end-of-line if ($i != length($string)) { # Not at end of line &wclrtoeol($win); $kill_buffer = substr($string,$i); $string = substr($string,0,$i) } else { &bell(); } } elsif ($action eq $yank_line) { # Paste killed text # Now it "does the right thing" in numeric-only # and hidden fields if (length($kill_buffer) != 0) { # Check for non-numeric kill_buffer in numeric-only field if ($dtype == 1 && $kill_buffer !~ m/^\d+$/ ) { &bell(); } elsif ($overstrike) { # If single-character field cannot yank a multi-character field if (length($kill_buffer) != 1) { &bell(); } else { # Delete single-character field &wmove($win,$row,$col); &wdelch($win); # Yank single-character kill_buffer &winsch($win,ord($kill_buffer)); $string = $kill_buffer; } } elsif ($left_col + length($string) + length($kill_buffer) > $maxcol) { # Yanking kill_buffer will make field too long &bell(); } else { if ($noshow) { $stars = '*' x length($kill_buffer); # Draw yanked text &waddstr($win,$stars."\0"); # Draw rest of string $stars = '*' x length(substr($string,$i)); &waddstr($win,$stars."\0"); } else { # Draw yanked text &waddstr($win,$kill_buffer."\0"); # Draw rest of string &waddstr($win,substr($string,$i)."\0"); } $string = substr($string,0,$i) . $kill_buffer . substr($string,$i); $col += length($kill_buffer); $i += length($kill_buffer); &wmove($win,$row,$col); } } } else { # Any other character if ($overstrike) { # Delete only char on single-char field &wmove($win,$row,$col); &wdelch($win); $string = ""; } if ($left_col + length($string) + 1 > $maxcol) { &bell(); } else { if (($dtype == 1) && (index("0123456789",$action) < 0)) { &bell(); } else { &wmove($win,$row,$col); # Insert the character on the screen if ($noshow) { &winsch($win,ord("*")); } else { &winsch($win,ord($action)); } $string = substr($string,0,$i).$action.substr($string,$i); if (!$overstrike) { $col++; $i++; &wmove($win,$row,$col); } } } } &wrefresh($win); } } #********** # MENU_DISPLAY_INTERNAL # # Function: Display items in menu_sel_text array, allow selection, and # return appropriate selection-string. # # Call format: $sel = &menu_display_internal([0|1|2],"Prompt text", # $arrow_pos,$top_item,"current"); # # Arguments: - Menu type (0=simple, 1=radio, 2=multiple-select). # - Prompt text (for the bottom line of menu). # - Current selection (radio only). # # Returns: Selected action string (from second param on &menu_item) # %UP% -- "u"|"U" pressed (or "t"|"T" and looking for top) # %EMPTY% -- Nothing in menu to display # %DONE% -- Done with selections (radio and mult only) #********** sub menu_display_internal { ($menu_type,$menu_prompt,$radio_sel) = @_; local($i,$search,$low_sel,$do_scroll,$move_amt); # If looking for top menu, return with "%UP%". if ($finding_top) { if ($menu_is_top_one) { $finding_top = 0; } else { return("%UP%"); } } # Check for no "menu_item" calls. $total_items = $#menu_sel_text + 1; if ($total_items <= 0) { &nocbreak(); # ALWAYS turn off "cbreak" mode &echo(); # ALWAYS turn on "echo" return("%EMPTY%"); } &cbreak(); # cbreak mode (each character available) &noecho(); # Menus are always "noecho" # Compute prepend length (for stuff we prepend to each selection text) $prepend_len = 0; # Assume nothing if (!$highlight && $menu_numbered) { $prepend_len += 2; } # Adjust for "->" if ($menu_numbered) { $prepend_len += 6; } # Adjust for "nnnn) " if ($menu_type) { $prepend_len += 4; } # Adjust for "[X] " # Calculate items per line and items per screen (based on mult-column pref) if ($multiple_column) { $column_width = $prepend_len + $max_item_len + 1; # Always pad one blank $items_per_line = int(($main'COLS-1)/$column_width); if ($items_per_line <= 0) { $items_per_line = 1; } } else { $column_width = $prepend_len + $max_item_len; $items_per_line = 1; } $items_per_screen = ($last_line - $first_line + 1) * $items_per_line; if ($total_items <= $items_per_screen) { $menu_single_page = 1; } else { $menu_single_page = 0; } if ($menu_prompt eq "") { $menu_prompt = "h)elp"; if ($menu_item_help_routine ne "") { $menu_prompt .= " ?)item-help"; } if (!$disable_quit) { $menu_prompt .= " q)uit"; } $menu_prompt .= " u)p"; if ($menu_top_activated) { if (! $menu_is_top_one) { $menu_prompt .= " t)op"; } } if ($menu_type == 2) { $menu_prompt .= " a)ll m)atch c)lear"; } if (! $menu_single_page) { $menu_prompt .= " n)ext-pg p)rev-pg"; } $menu_prompt .= " b)egin e)nd"; if (length($menu_prompt)+9 < $main'COLS - 7) { $menu_prompt .= " r)efresh"; } } if (length($menu_prompt) > $main'COLS - 7) { $menu_prompt = substr($menu_prompt,0,$main'COLS - 7); } # Validate/adjust paramaters. $arrow_line = $arrow_spec_row + $first_line; if ($menu_top_item + 1 > $total_items) { $menu_top_item = $total_items - 1; } if ($arrow_line < $first_line) { $arrow_line = $first_line; } if ($arrow_line > $last_line) { $arrow_line = $last_line; } $arrow_col = $arrow_spec_col; if ($arrow_col < 0) { $arrow_col = 0; } elsif ($arrow_col > $items_per_screen - 1) { $arrow_col = $items_per_screen - 1; } # Compute leftmost column (for left-justified or centered menus) $left_margin = 0; # Assume left-justified menu (no centering) if ($center_menus) { $left_margin = int($main'COLS/2) - int($column_width/2) * items_per_line; } # Clear screen and add top title and bottom prompt &menu_top_bot(); $move_amt = 0; $number = 0; $menu_lastexit = "\n"; while (1) { $number_shown = $menu_top_item + $items_per_screen; if ($number_shown > $total_items) { $number_shown = $total_items; } $percent = int($number_shown * 100 /$total_items); &menu_page(); # Display current page # Collect key sequences until something we recoginize # (or we know we don't care) $action = &collect_seq($window); if ($#menu_exitkeys) { &check_exit_keys(); } # Check any exit keys # If trying to be more "gopher-like", translate now. if ($gopher_like && ($items_per_line == 1)) { if (($action eq $kr) || ($action eq $ansi_kr)) { $action = "\n"; } if (($action eq $kl) || ($action eq $ansi_kl)) { $action = "u"; } } # Perform action based on keystroke(s) received $move_amt = 0; if ($action ne "") { $last_arrow_line = $arrow_line; $last_arrow_col = $arrow_col; if (($action eq $kd) || ($action eq $ansi_kd)) { # Down-arrow $number = 0; $do_scroll = 1; if ($items_per_line > 1) { if (($arrow_line+1 >= $max_sel_line) && ($arrow_col > $max_sel_col)) { $do_scroll = 0; } } if ($do_scroll) { if ($arrow_line < $max_sel_line) { $arrow_line++; } else { if ($gopher_like) { $move_amt = $items_per_screen; $arrow_line = $first_line; } else { if ($arrow_line == $last_line) { $move_amt = $items_per_line; } } } } } if (($action eq $next_field) || ($action eq $kr) || ($action eq $ansi_kr)) { # Right-arrow $number = 0; $do_scroll = 1; if ($items_per_line > 1) { if (($arrow_line == $max_sel_line) && ($arrow_col == $max_sel_col)) { $item = $menu_top_item+($arrow_line-$first_line)*$items_per_line+$arrow_col; if (($item == $menu_index-1) && !$gopher_like) { $do_scroll = 0; } } else { if ($arrow_col + 1 < $items_per_line) { $arrow_col++; $do_scroll = 0; } } } if ($do_scroll) { $arrow_col = 0; if ($arrow_line < $max_sel_line) { $arrow_line++; } else { if ($gopher_like) { $move_amt = $items_per_screen; $arrow_line = $first_line; } else { if ($arrow_line == $last_line) { $move_amt = $items_per_line; } } } } } elsif (($action eq $ku) || ($action eq $ansi_ku)) { # Up-arrow $number = 0; if ($arrow_line > $first_line) { $arrow_line--; } else { if ($gopher_like) { $move_amt = -$items_per_screen; if ($menu_top_item + $move_amt < 0) { # Moving before 1st item if ($menu_top_item > 0) { # Not currently on 1st page $arrow_line = $menu_top_item + $arrow_line - 1; # Adjust arrow } else { $arrow_line = $last_line; } } else { $arrow_line = $last_line; } } else { $move_amt = -$items_per_line; } } } elsif (($action eq $prev_field) || ($action eq $kl) || ($action eq $ansi_kl)) { # Left-arrow $number = 0; $do_scroll = 1; if ($items_per_line > 1) { if ($arrow_col > 0) { $arrow_col--; $do_scroll = 0; } else { if (($arrow_line > $first_line) || ($menu_top_item > 0)) { $arrow_col = $items_per_line - 1; } else { if ($gopher_like) { $arrow_col = $max_sel_col; } else { $do_scroll = 0; } } } } if ($do_scroll) { if ($arrow_line > $first_line) { $arrow_line--; } else { if ($gopher_like) { $move_amt = -$items_per_screen; if ($menu_top_item + $move_amt < 0) { # Moving before 1st item if ($menu_top_item > 0) { # Not currently on 1st page $arrow_line = $menu_top_item + $arrow_line - 1; # Adjust arrow } else { $arrow_line = $last_line; } } else { $arrow_line = $last_line; } } else { $move_amt = -$items_per_line; } } } } elsif (($action eq "n") || ($action eq "N") || # Next ($action eq " ")) { $number = 0; $move_amt = $items_per_screen; } elsif (($action eq "b") || ($action eq "B")) { # Begin $menu_top_item = 0; $arrow_line = $first_line; $arrow_col = 0; $number = 0; } elsif (($action eq "e") || ($action eq "E")) { # End $number = 0; if (! $menu_single_page) { $menu_top_item = $menu_index - $items_per_screen; } $arrow_line = $last_line; $arrow_col = $max_sel_col; } elsif (($action eq "p") || ($action eq "P")) { # Previous $number = 0; $move_amt = -$items_per_screen; } elsif (($action eq "a") || ($action eq "A")) { # Select all if ($menu_type == 2) { $i = 1; while ($i < $menu_index) { if ($selected_action[$i] >= 0) { $selected_action[$i] = 1; } $i++; } } } elsif (($action eq "c") || ($action eq "C")) { # Clear all if ($menu_type == 2) { $i = 1; while ($i < $menu_index) { if ($selected_action[$i] >= 0) { $selected_action[$i] = 0; } $i++; } } } elsif (($action eq "m") || ($action eq "M") || # Match string ($action eq "=") || ($action eq "/")) { if ($menu_type == 2) { $search = &menu_getstr($last_line+1,0,"Search string: ",1); &cbreak(); # menu_getstr turned this off &noecho(); # menu_getstr turned this on if ($search) { # Toggle selections $search =~ tr/A-Z/a-z/; $i = 1; while ($i < $menu_index) { if ($selected_action[$i] >= 0) { $low_sel = $menu_sel_text[$i]; $low_sel =~ tr/A-Z/a-z/; if (index($low_sel,$search) >=0) { $selected_action[$i] = 1; } } $i++; } } } } elsif (($action eq "r") || ($action eq "R") || ($action eq $redraw_screen)) { # Refresh &clear(); &menu_top_bot(); $last_menu_top_item = -1; &menu_page(); } elsif (($action eq "\177") || ($action eq "\010")) { # Delete/BS num-reset $number = 0; $arrow_line = $first_line; &menu_page(); } elsif ((($action eq "Q")||($action eq "q")) && !$disable_quit) { # Quit &clear(); $xrow = $xcol = 0; &move(0,0); if ($quit_prompt eq "") { $ch = "Do you really want to quit?"; } else { $ch = $quit_prompt; } $ch .= " $quit_default"; &addstr($ch); &move(0,length($ch) - 1); &refresh(); $ch = &getch(); if ($ch eq "") { &menu_hangup_proc(); } if (($ch eq $cr) || ($ch eq $nl) || ($ch eq "\n")) { $ch = $quit_default; } $ch =~ tr/A-Z/a-z/; if ($ch eq "y") { &menu_return_prep(); if ($menu_exit_routine ne "") { &$menu_exit_routine(); } exit(0); } &clear(); $xrow = $xcol = 0; &menu_top_bot(); # Re-display current page $last_menu_top_item = -1; &menu_page(); } elsif (($action eq "U") || ($action eq "u")) { # Up unless ($menu_is_top_one) { $finding_top = 0; return("%UP%"); } } elsif (($action eq "T") || ($action eq "t")) { # Top if ($menu_top_activated && !$menu_is_top_one) { $finding_top = 1; return("%UP%"); } } elsif (($action eq "h") || ($action eq "H") || # Help ($action eq "?")) { if (($action eq "?") && ($menu_item_help_routine ne "")) { if ($number) { $item = $number - 1; } else { $item = $menu_top_item+($arrow_line-$first_line)*$items_per_line+$arrow_col; } if (($item < $menu_top_item) || ($item > $menu_bot_item)) { &bell(); $number = 0; } else { &$menu_item_help_routine($menu_sel_text[$item],$menu_sel_action[$item]); &clear(); &refresh(); } } else { &$menu_generic_help_routine(); # Show generic help page &clear(); $xrow = $xcol = 0; &refresh(); } &menu_top_bot(); # Clear and re-display the current page $last_menu_top_item = -1; &menu_page(); } elsif ($action eq "!") { # Shell escape if ($menu_shell_text ne "") { &clear(); $xrow = $xcol = 0; # Clear screen &refresh(); &nocbreak(); # ALWAYS turn off "cbreak" mode &echo(); # ALWAYS turn on "echo" $xrow = $xcol = 0; &print_nl("Entering command shell via \"$menu_shell_text\".",1); &print_nl("Return here via shell exit (normally Control-D).",1); &refresh(); &endwin(); system($menu_shell_text); &cbreak(); # cbreak mode (each character available) &noecho(); # Menus are always "noecho" &clear(); $xrow = $xcol = 0; # Clear screen &menu_top_bot(); # Re-display the current page $last_menu_top_item = -1; &menu_page(); } } elsif (($action eq $cr) || ($action eq $nl) || ($action eq "\n")) { # RETURN if ($number) { $item = $number - 1; } else { $item = $menu_top_item+($arrow_line-$first_line)*$items_per_line+$arrow_col; } if (($item < $menu_top_item) || ($item > $menu_bot_item)) { &bell(); $number = 0; } else { $arrow_spec_row = $arrow_line - $first_line; $arrow_spec_col = $arrow_col; return($menu_sel_action[$item]); } } else { $digit_val = index("0123456789",$action); # Number if ($digit_val >= 0) { $number = $number * 10 + $digit_val; if ($number >= $menu_top_item + 1) { if (($number <= $menu_bot_item + 1) && ($number <= $total_items)) { if ($items_per_line > 1) { $i = $number - $menu_top_item - 1; $arrow_line = int($i/$items_per_line) + $first_line; $arrow_col = $i % $items_per_line; } else { $arrow_line = $number - $menu_top_item + $first_line - 1; } } else { &bell(); $number = 0; $arrow_line = $first_line; $arrow_col = 0; } &menu_page(); } } } # Check for paging/scrolling of the menu text. # Key variable to set is "menu_top_item". if ($move_amt != 0) { if ($move_amt < 0) { # Move backward if ($menu_top_item + $move_amt < 0) { # Moving before 1st item if ($gopher_like) { if ($menu_top_item > 0) { # Not currently on 1st page $menu_top_item = $menu_top_item + $move_amt; } else { # Currently on 1st page $menu_top_item = $total_items - $items_per_screen; } if ($menu_top_item < 0) { $menu_top_item = 0; } } else { $menu_top_item = 0; } } else { $menu_top_item = $menu_top_item + $move_amt; } } else { # Move forward if (($menu_top_item + $move_amt < $total_items) && ($menu_bot_item + 1 < $total_items)) { $menu_top_item = $menu_top_item + $move_amt; } else { if ($gopher_like) { $menu_top_item = 0; } } } } # Reset last selection to normal rendition or clear last arrow if ($highlight) { $item = $menu_top_item+($last_arrow_line-$first_line)*$items_per_line+$last_arrow_col; $i = $left_margin+$prepend_len+$last_arrow_col*($column_width); if ($menu_type && !$item) { $i -= 4; } # No "[X] " on first item &move($last_arrow_line,$i); &addstr($menu_sel_text[$item]); &move($last_arrow_line,$i); } else { if ($menu_numbered) { &move($last_arrow_line,$left_margin+$last_arrow_col*($column_width)); &addstr(" "); } } } } } #********* # CHECK_EXIT_KEYS # # Function: Check for user-define exit keys on menu and getstr. # # Input: Nothing # # Returns: Nothing (action and lastexit set) # #********* sub check_exit_keys { local($j); for ($j = 0; $j <= $#menu_exitkeys; $j++) { if ($action eq $menu_exitkeys[$j]) { $menu_lastexit = $action; $action = "\n"; last; } } } #********** # COLLECT_SEQ -- Collect characters until a sequence we recognize (or we # know it cannot possibly fit any "magic" sequences. #********** sub collect_seq { local($cwin) = @_; local($i,$possible); local($collect,$action) = ""; $possible = $#magic_seq; # Set number of possible matches seq_seek: while ($possible > 0) { $ch = &wgetch($cwin); if ($ch eq "") { &menu_hangup_proc(); } $collect = $collect.$ch; $i = 0; $possible = 0; $action = $ch; try: while ($i <= $#magic_seq) { if (length($collect) > length($magic_seq[$i])) { $i++; next try; } if (substr($magic_seq[$i],0,length($collect)) eq $collect) { $possible++; if ($collect eq $magic_seq[$i]) { $action = $magic_seq[$i]; last seq_seek; } } $i++; } # end while } $action; } #********** # MENU_TOP_BOT -- Display top and bottom lines of current menu #********** sub menu_top_bot { local($i,$j,$temp); # Main top title &move(0,$menu_top_title_col); if ($menu_top_title_attr == 0) { &standout(); } &addstr($menu_top_title); if ($menu_top_title_attr == 0) { &standend(); } # Top sub-titles if ($menu_sub_titler ne "") { $temp = &$menu_sub_titler; # Expand title string $first_line = 2; # Assume no sub-titles for now $last_line = $main'LINES - 3; # Assume no bottom-titles for now if ($temp ne "") { $first_line += &proc_titles($temp,*menu_sub_title, *menu_sub_title_attr,*menu_sub_title_col); } else { @menu_sub_title = (); } } if ($#menu_sub_title >= 0) { for ($i = 0; $i <= $#menu_sub_title; $i++) { &move($i+1,$menu_sub_title_col[$i]); if ($menu_sub_title_attr[$i] == 0) { &standout(); } &addstr($menu_sub_title[$i]); if ($menu_sub_title_attr[$i] == 0) { &standend(); } } } # Bottom sub-titles if ($menu_bot_titler ne "") { $temp = &$menu_bot_titler; if ($temp ne "") { $last_line = $main'LINES - 3; $last_line -= &proc_titles($temp,*menu_bot_title, *menu_bot_title_attr,*menu_bot_title_col); $last_line--; # Blank line between menu and bottom titles } else { @menu_bot_title = (); } } if ($#menu_bot_title >= 0) { $j = $main'LINES - $#menu_bot_title - 3; for ($i = 0; $i <= $#menu_bot_title; $i++) { &move($j+$i,$menu_bot_title_col[$i]); if ($menu_bot_title_attr[$i] == 0) { &standout(); } &addstr($menu_bot_title[$i]); if ($menu_bot_title_attr[$i] == 0) { &standend(); } } } $items_per_screen = ($last_line - $first_line + 1) * $items_per_line; &move($main'LINES - 1,7); &addstr($menu_prompt); } #********** # MENU_PAGE -- Display one page of menu selection items. #********** sub menu_page { local($i,$j) = 0; local($curr_line,$line,$fx,$iw); local($refresh_items) = 0; # Check for top item change (scrolling/paging of menu text). if ($menu_top_item != $last_menu_top_item) { $last_menu_top_item = $menu_top_item; $refresh_items = 1; } # Refresh all items on screen if ($refresh_items) { # Update percentage on bottom line &move($main'LINES-1,0); &standout(); if ($menu_single_page) { &addstr("(All) "); } else { &addstr(sprintf("\(%3d%%\)",$percent)); } &standend(); # Display current page of menu $item = $menu_top_item; $menu_bot_item = $menu_top_item; $curr_line = $first_line; $max_sel_line = $first_line; $max_sel_col = 0; while ($curr_line <= $last_line) { # Process lines on screen &move($curr_line,$left_margin); &clrtoeol(); $line = ""; if ($item < $total_items) { # If any items left to show ... $curr_col = 1; while ($curr_col <= $items_per_line) { # Add items to line if ($item < $total_items) { if ($menu_numbered) { $line .= &menu_add_number($item + 1); } if ($menu_type) { # Add selection boxes on mult/radio if ($item != 0) { if ($menu_type == 1) { if ($menu_sel_action[$item] eq $radio_sel) { $line .= "[X] "; } else { $line .= "[ ] "; } } else { # menu_type is 2 if ($selected_action[$item] > 0) { $line .= "[X] "; } elsif ($selected_action[$item] < 0) { $line .= "[-] "; } else { $line .= "[ ] "; } } } } $line .= $menu_sel_text[$item]; # Add the selection text if ($items_per_line > 1) { # Pad out if multiple columns $i = 1; # Always pad one if ($menu_type && !$item) { $i += 4; } # Missing "[ ] " $line .= ' ' x ($max_item_len-length($menu_sel_text[$item])+$i); } $max_sel_col = $curr_col - 1; $item++; } $curr_col++; } if (length($line) > $main'COLS - 1) { # Truncate lines that would wrap $line = substr($line,0,$main'COLS - 1); } &addstr($line); $max_sel_line = $curr_line; } $curr_line++; } $menu_bot_item = $item - 1; } # Refresh only selection tags on radio/multi-select menus elsif ($menu_type) { $item = $menu_top_item; $curr_line = $first_line; while ($curr_line <= $last_line) { $i = $left_margin + $prepend_len - 3; # First "X" on line if ($item < $total_items) { for ($j = 0; $j < $items_per_line; $j++) { if ($item) { &move($curr_line,$i); if ($menu_type == 1) { if ($menu_sel_action[$item] eq $radio_sel) { &addstr("X"); } else { &addstr(" "); } } else { # menu_type is 2 if ($selected_action[$item] > 0) { &addstr("X"); } elsif ($selected_action[$item] < 0) { &addstr("-"); } else { &addstr(" "); } } } $i += $column_width; # Next "X" on line $item++; # Next item } } $curr_line++; # Next line } } # Sanity checks for arrow if ($arrow_line < $first_line) { $arrow_line = $first_line; } if ($arrow_line > $max_sel_line) { $arrow_line = $max_sel_line; } # Highlight selection text or add selection arrow (based on prefs). # Position the cursor properly on the screen. if ($highlight) { $item = $menu_top_item+($arrow_line-$first_line)*$items_per_line+$arrow_col; $i = $left_margin+$prepend_len+$arrow_col*($column_width); if ($menu_type && $item == 0) { $i -= 4; } # No "[X] " on first item &move($arrow_line,$i); &standout(); &addstr($menu_sel_text[$item]); &standend(); &move($arrow_line,$i); } else { &move($arrow_line,$left_margin+$arrow_col*$column_width); if ($menu_numbered) { &addstr("->"); } } # Write out current menu page &refresh(); } #********** # MENU_ADD_NUMBER -- Format selection number. #********** sub menu_add_number { local($sel_num) = @_; local($sel_str) = ""; if (!$highlight) { $sel_str = " "; } # Place for "->" if ($sel_num < 1000) { $sel_str .= " "; } if ($sel_num < 100) { $sel_str .= " "; } if ($sel_num < 10) { $sel_str .= " "; } $sel_str .= "$sel_num) "; $sel_str; } #********** # MENU_RETURN_PREP -- Common return functions. #********** sub menu_return_prep { &nocbreak(); &echo(); &clear(); $xrow = $xcol = 0; &refresh(); if (!$curses_application) { &endwin(); } } #********** # MENU_HANGUP_PROC -- Hangup return functions #********** sub menu_hangup_proc { if ($menu_exit_routine ne "") { &$menu_exit_routine(); } exit(1); } #********** # MENU_DEFAULT_SHOW_HELP #********* sub menu_default_show_help { local($arrow_txt); &clear(); $xrow = $xcol = 0; &print_nl("--------------------------------",1); &print_nl("Menu Help (PerlMenu version 4.0)",1); &print_nl("--------------------------------",2); if ($items_per_line > 1) { $arrow_txt = "up/down/left/right"; } else { $arrow_txt = "up/down"; } if ($highlight) { &print_nl("- Use $arrow_txt arrow keys to highlight your selection.",1); } else { &print_nl("- Use $arrow_txt arrows to place \"->\" in front of your selection.",1); } if ($menu_type == 1) { &print_nl("- Press Return (or Enter) to choose that selection.",1); &print_nl("- Select the first item when ready to continue.",2); } elsif ($menu_type == 2) { &print_nl("- Press Return (or Enter) to toggle the selection on/off.",1); &print_nl("- Select the first item when ready to continue.",2); } else { &print_nl("- Press Return (or Enter) when ready to continue.",2); } &print_nl("Available action-keys:",1); &print_nl("h - Show this help screen.",1); if ($menu_item_help_routine ne "") { if ($highlight) { &print_nl("? - Show help on the item with the \"->\" in front.",1); } else { &print_nl("? - Show help on the highlighted item.",1); } } if (!$disable_quit) { &print_nl("q - Quit entirely.",1); } &print_nl("u - Return to the previous menu or function.",1); if ($menu_top_activated && !$menu_is_top_one) { &print_nl("t - Return to the top menu.",1); } if ($menu_type == 2) { &print_nl("a - Select all items.",1); &print_nl("m - Select based on a case-insensitive string match.",1); &print_nl("c - Clear all selections.",1); } if (! $menu_single_page) { &print_nl("n - Move forward to next page.",1); &print_nl("p - Move backward previous page.",1); } &print_nl("b - Move to the item at the beginning of the menu.",1); &print_nl("e - Move to the item at the end of the menu.",1); &print_nl("r - Refresh the screen.",1); if ($menu_shell_text ne "") { &print_nl("! = Enter command shell via \"$menu_shell_text\".",1); } &print_nl(" ",1); &addstr("[Press any key to continue]"); &refresh(); $ch = &getch(); if ($ch eq "") { &menu_hangup_proc(); } &clear(); $xrow = $xcol = 0; &refresh(); } sub print_nl { local($text,$skip) = @_; &addstr($text); if ($skip) { &nl($skip); } &refresh(); } sub nl { local($skip) = @_; $xrow += $skip; $xcol = 0; if ($xrow > $main'LINES - 1) { &clear(); $xrow = 0; $xcol = 0; &refresh(); } &move($xrow,$xcol); } sub defbell { eval q# sub bell { print "\007"; } #; } #********** # MENU_TEMPLATE_SETEXIT # # Function: Set alternative exit keys that may be used to exit a template # # Call format: &menu_template_setexit(@exit_key_array); # OR # &menu_template_setexit("exit_seq1","exit_seq2",...); # # Arguments: exit_key_array - the keys to end menu_display_template on # # Returns: Nothing #********* sub menu_template_setexit { @template_exitkeys = @_; } #********** # MENU_LOAD_TEMPLATE # # Function: Load screen-input template from a file for later processing. # # Input: Filename # # Returns: 0=Success, 1=Cannot open file #********** sub menu_load_template { local($filename) = @_; &menu_load_template_init_internal; # Load the template open(TEMPLATE,$filename) || return(1); while(