Search
Documents
PV (PerlVision - Text-mode User Interface Widgets.) (Displayed)
|
PV (PerlVision - Text-mode User Interface Widgets.)
PerlVision - Text-mode User Interface Widgets.
use PV;
init PV;
my $foo = new PV::Static ("Text", $x1, $y1, $x2, $y2);
$foo->display;
Once upon a time I needed a basic text-mode GUI framework to implement
some nice-looking interfaces for the Linux console. Didn't find any
around, so necessity became the mother of PerlVision, which kept
growing as I kept adding more goodies, so now it's far from basic...
PV provides 90% of the features you'd want for a user interface,
including checkboxes, radiobuttons, three different styles (!) of
pushbuttons, single and multiple selection listboxes, an extensible
editbox, a scrollable viewbox, single line text entry fields, a
menubar with pulldown menus, and full popup dialog boxes with multiple
controls.
The following object classes are defined within PV:
- PV::Static
-
A static text region, trivial class.
- PV::Checkbox
-
A single 2-state checkbox.
- PV::Radio
-
A single 2-state radiobutton.
- PV::RadioG
-
A group of connected radiobuttons.
- PV::Listbox
-
A single selection list box.
- PV::Mlistbox
-
A multiple selection list box.
- PV::Entryfield
-
A single line text entry field.
- PV::Password
-
A single line text entry field that *'s out what's typed.
- PV::Menubar
-
A top line menu bar with single-level pulldown submenus.
- PV::Combobox
-
A combo box.
- PV::Editbox
-
A multi line edit box.
- PV::Viewbox
-
A readonly viewer/pager for text files.
- PV::Pushbutton
-
A push button that takes 3 lines of screen real estate.
- PV::Cutebutton
-
A push button that takes 2 lines of screen real estate.
- PV::Plainbutton
-
A no-frills button that fits on a single line.
- PV::Dialog
-
A full dialog box with as many controls as you like.
Other classes are defined for internal use by PerlVision and should
not be used from outside. Also, see below why use of the PV::Radio
control is limited from outside.
Constructors for all the classes are called new().
All classes expect that you will not fiddle with the object's data
yourself.
All nontrivial controls (except PV::RadioG, see below) have an
activate() method. It makes the control active, and returns when any
traditional shift focus key is pressed - see the section on PV::Dialog
for more details.
All nontrivial controls have a stat() method, which returns the status
of the control (checked, unchecked, text, whatever).
my $foo = new PV::Static ("Text", $x1, $y1, $x2, $y2);
This is the trivial text region control. It's there mainly so you can
put static text in dialog boxes. It doesn't have an activate() or
stat() method.
$foo->display; # Displays the widget.
If your text doesn't fit in the space you allocate, it'll be
truncated. It's also your responsibility to provide line breaks if you
don't want all the text to be thought of as a single line.
my $foo = new PV::Checkbox ("Label", $x, $y, $stat);
Arguments $x and $y are the X and Y co-ordinates to place the control.
$stat is 1 if the Checkbox is checked, 0 if not. ``Label'' is printed on
the left of the checkbox.
$foo->display; # Displays checkbox.
$foo->activate; # Gives it focus. Exits on 1,2,3,4,5,6,7 codes.
$foo->select; # Toggles status.
$foo->stat; # Returns status. (1 checked, 0 unchecked)
my $foo = new PV::Radio ("Label", $x, $y, $stat);
PV::Radio is a direct descendant of PV::Checkbox that just looks a bit
different. All the methods defined for PV::Checkbox are defined for
PV::Radio as well, But don't try to use PV::Radio as a different
looking PV::Checkbox.
Because radio buttons are generally meant to be grouped and to affect
the state of all other buttons in the group. So unless you include a
radio button in a group with PV::RadioG (see below), you're liable to
hurt something. Once it's in a group you can use all the methods
outlined above for PV::Checkbox.
my $foo = new PV::RadioG ($radio_1, $radio_2, $radio_3...);
Where $radio_* are PV::Radio objects. See? You take your PV::Radio
objects, and feed them to the constructor for PV::RadioG, and out pops
a radio button group.
$foo->display; # Displays all radio buttons in group.
$foo->stat; # To figure out which button is the one that's
# selected. This returns the Label of the selected
# button.
PV::RadioG has no 'activate' method. You activate the PV::Radio
objects directly. This is much more flexible for use in dialog boxes.
my $foo = new PV::Listbox ("Head", $x1, $y1, $x2, $y2,
"Label1", 0, "Label2", 0...);
Yes, the element following each ``Labeln'' should be 0 for this to work
right.
``Label*'' are the strings that will be shown in the listbox. ``Head''
will be printed across above the top of the listbox.
$foo->activate; # Gives it focus. Exits on 5,6,7,8 exit codes.
$foo->stat; # Returns the label of the selected entry.
my $foo = new PV::Mlistbox ("Head", $x1, $y1, $x2, $y2,
"Label1", 0, "Label2", 0...);
Yes, the element following each ``Labeln'' should be 0 for this to work
right.
``Label*'' are the strings that will be shown in the listbox. ``Head''
will be printed across above the top of the listbox.
$foo->activate; # Gives it focus. Exits on 5,6,7,8 exit codes.
$foo->stat; # Returns a list of all selected labels.
my $foo = new PV::Entryfield ($x, $y, $length, $max,
"Label", "Initial Value");
$length is the length of the text entry area. $max is the maximum
length of the input. actually this is ignored. ;-) ``Label'' is printed
to the left of the entry field. Can be ``''. The entryfield is
pre-initialized to ``Initial Value''. Can be ``''.
$foo->activate; # Gives it focus. Exits on 1,2,5,6,7,8 exit codes.
# Changed text is always saved, regardless of
# how the loop exited.
$foo->stat; # Returns the text value of the entryfield.
Identical to PV::Entryfield except that it displays '*'s instead of
what the user types.
The menu bar is a bit odd. The way you do it is set it up with just
one pulldown, then add pulldowns to it till you have enough. Don't add
too many (i.e. that there's not enough space for their heads on the
menubar) or things will definitely get broken.
my $foo = new PV::Menubar ("Head", $width, $depth,
"label1", 0, "label2", 0...);
Just like with the listboxes, each list element is followed by a
0. This list becomes your first pulldown. Now to add more pulldowns,
do:
$foo->add("Head", $width, $depth, "label1", 0, "label2", 0...);
That's the second pulldown, and so on. Because of this step by step
method of building up the menubar, you need to display it once you're
finished adding pulldowns, it doesn't automatically display itself. Do
a:
$foo->display();
To activate:
$foo->activate();
It'll exit on 5, 7, and 8. On 8, it'll give you a second element in
the return list of the form ``Pulldown:Selection''. The ``Pulldown'' is
the head of the pulldown menu, the ``Selection'' is the label of the
selection.
Help context does not come through on the 5 exit code. i.e. you can't
tell which pulldown was active when help was requested, or which
selection in which pulldown. C'est la vie.
Not implemented yet. I'll get around to it when I need it I guess.
Actually it's a pretty trivial offspring of a listbox and an
entryfield.
my $foo = new PV::Editbox ($x1, $y1, $x2, $y2, $margin,
"Text", $index, $start);
$margin is the word-wrap boundary. If it's bigger than the size of the
box, that's your headache.
$text is a text string to be dumped into the editbox. it will be
stripped of CRs (not LFs), TABs, and nulls, and justified the way the
editbox does it (see below).
$index is the start position within the text to initially place the
cursor at. First char is 0.
$start is the line number to position at the top of the editbox, if
possible. First line is 0.
$foo->activate; # Gives it focus. Exits on 5,6,7 exit codes.
# Changed text is always saved, regardless of
# how the loop exited.
$foo->stat; # Returns the text value of the editbox.
There are some hooks in there to let you subclass it and do
things. One is an empty 'sub statusbar' that's called every-time the
display is refreshed. Another is an empty 'sub process_key' which is
used extensively in rap to build a full editor out of the editbox
control.
The editbox does automatic word-wrapping and reverse word-wrapping and
other fancy stuff. The style of auto-wrapping I chose is what
personally irritates me the least (all auto-wraps irritate me). Trying
to change the wrap style is likely to be very hairy, and will probably
break the editbox. It took a lot of tweaking of plenty of regexps to
get it to work the way it does.
my $foo = new PV::Viewbox ($x1, $y1, $x2, $y2, $text, $start);
Much like PV::Editbox but it's readonly and the arrow keys have
different bindings. I will eventually implement hardware scrolling in
viewboxes that extend the length of the display so that it's a fast
browser.
my $foo = new PV::Pushbutton ("Label", $x1, $y1);
Makes a simple push button.
$foo->display(); # Displays it.
$foo->activate(); # Activates it.
Exits on codes 1,2,3,4,5,6,7,8. On 8, it 'depresses' and it's up to
you to 'undepress' it by calling the display method.
PV::Pushbutton is BIG. It takes 3 lines on the screen. PV::Cutebutton is
my favorite - it takes only two lines, and actually pushes and pops
around so it's fun to watch ;) PV::Plainbutton is a basic one-line
button which does absolutely nothing fancy but is very useful in some
situations (e.g. for hyper-text).
This is the guy that puts it all together and does all the work of
managing how focus switches between multiple controls in a dialog
box. Once you've created all the controls you need, you can feed them
to PV::Dialog and out pops an object that you can trust to handle
everything. Above you would have noticed that the activate loops for
all controls return en exit code when focus is released. This is what
these codes mean:
When an activate loop exits, it returns a code telling you the reason
for exiting:
1 = Up Arrow (Traditional shift-focus key)
2 = Down Arrow (Traditional shift-focus key)
3 = Right Arrow (Traditional shift-focus key)
4 = Left Arrow (Traditional shift-focus key)
5 = M-h (For help)
6 = M-x (For menu)
7 = Tab (Traditional shift-focus key)
8 = Enter (Traditional 'Done here' key)
These codes are used by the PV::Dialog control to figure out how to
switch focus between controls, and when to exit. Here's how to create
a PV::Dialog object:
$foo = new PV::Dialog ("Title", $x1, $y1, $x2, $y2, $style, $color,
$control1, 1, 2, 2, 1, 1, 1, 2, 0,
$control2, 1, 3, 3, 1, 2, 2, 3, 0,
...);
``Title'' is currently ignored.
$style: if 1, creates a popup that is 'raised'.
if 0, creates a popup that is 'depressed'
$color is the background color for the dialog. I'd recommend 6 (cyan)
because of the overall hardcoded buddha-nature of colors at present.
$control* are PV::* objects that you created beforehand (I think they
can even be PV::Dialog types, though I haven't tested it. They can't
be PV::Menubar types). Note that the controls must be positioned
relative to the origin of the dialog box, not relative to the screen
origin (dialog boxes are actually curses windows, and that's how
curses likes it).
How the dialog box works is that the control+exitcode matrix tells
PV::Dialog which control to switch focus to on each of the 8 exit
codes listed above. So when you do a:
$foo->activate;
PV::Dialog starts off by displaying itself and giving focus to
$control1. When $control1 exits, $foo looks in the list that follows
$control1 in the constructor syntax above to figure out which control
to give focus to next. The list is simply numbers that say which
control. So 1 represents $control1, 2 represents $control2, and so on,
strictly based on the order in which the controls appear in the
constructor invocation.
The special value 0 is reserved to tell PV::Dialog that it's time to
exit and hide the dialog box. I also use it as a place-holder for
those exit-codes that a certain control never returns, for example of
$control1 above was a PV::Editbox, I'd put 0's in the list following
$control1 at positions 1,2,3 and 4 because the edit box object never
exits on those codes (those keys have meaning within the editbox)
If you don't want focus to switch off a control when a certain
exitcode is returned, simply put that control's own number in the
corresponding position in the list.
Look in the rap code for an example of PV::Dialog use, the $options
object. It's generally very easy and powerful.
When PV::Dialog's activate exits, it returns a two-element list. First
element tells you which was the last control to be active (again
numbered as they appear in the constructor invocation), and the second
element tells you what exitcode that control returned.
After the dialog box has exited, you can call 'stat' on each control
to find out what's up. Remember, don't put PV::RadioG controls in a
dialog box, they don't have an activate method. Put the corresponding
PV::Radio controls in. When you 'stat', you'll be 'stat'ing the
PV::RadioG.
Also, don't ever put a PV::Static as the first control in a
PV::Dialog. It doesn't have an activate method. If you just want a
pop-up box with text and no other controls, either consider using a
PV::Viewbox control, or write the text onto the popup box yourself with
pv::pvprint.
PerlVision also defines two often needed dialog box styles:
PV::PVD::message (A simple message box with OK button)
PV::PVD::yesno (An option box with Yes/No buttons)
Both self-center, and make sure the box is big enough to hold the
buttons. They don't bother to check if the screen will hold the dialog
box, or the dialog box will hold your text. Both use the following
syntax:
$foo = new PV::PVD::message ("Text", $width, $depth);
PV::PVD::yesno returns 1 for yes and 0 for no.
Width and depth are how big you want the text part of the box to be
(the buttons are separate).
$max in PV::Entryfield is a misnomer. It's actually used internally
and should be set to 0 when you create a new entryfield object.
Colors are still more-or-less hardcoded.
Some vestigal crufts from v0.1 remain, as the rewrite to use curses
was accomplished by blatant abuse of emacs's M-x replace-regexp. In
particular, all controls still expect X co-ordinates before Y
co-ordinates, which is the reverse of how curses likes it. In a future
version I'll do away with positional arguments and use hash arguments.
PV.pm should check if the terminal can support the minimum
capabilities required, as well as eval uncertain curses calls.
Error checking needs work.
PV languished for many (4) years without any updates but I am hoping
to get a chance to clean it up soon. A lot needs to be worked on - too
much to list here.
- v0.1
-
March 1995. First release. Didn't use curses, did its own screen
optimization, which was in Perl and very slow.
- v0.2
-
April 1995. Found Will Setzer's Curses interface for Perl and did a
rewrite using curses/ncurses. Tremendously speeded up and much more
portable. Turned into a real Perl 5 module. Many thanx to Tim Bunce
for helping clear up my confusion about modules.
- v1.x
-
July 2000. Moved docs to pod format and put PV in CVS. Brought PV
packaging up to date with a 2 digit version number and a
Makefile.PL. Hopefully this means I am going to finally do some work
on PV soon!
Curses(3), perl(1).
PerlVision is Copyright (c) 2000 Ashish Gulhati
<hash@netropolis.org>. All Rights Reserved.
Nick Cabatoff <ncc@cs.mcgill.ca>
Thanks to Barkha for inspiration and lots of good times; to Raj for
the good old days when we hacked Unix and consumed insane quantities
of alcohol; to Emily Saliers, Eddie Van Halen and Neil Peart for
fantastic music; to William Setzer for Perl Curses, Larry Wall for
Perl, and RMS for Emacs.
This code is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
It would be nice if you would mail your patches to me, and I would
love to hear about projects that make use of this module.
This is free software. If it breaks, you own both parts.
Information
|
This site is currently in testing, it is not yet operating using the full database. Until it is officially launched you may wish to visit Help-Site Computer Manuals. After launch, this site (HelpSpy) will replace Help-Site. Information about the spider which is currently trawling the Internet looking for links to add to this directory can be found here. |
|