NAME
Curses::Forms - Curses Forms Framework
MODULE VERSION
$Id: Forms.pm,v 1.997 2002/11/14 18:22:59 corliss Exp corliss $
SYNOPSIS
use Curses::Forms;
$obj = Curses::Forms->new({
ALTBASE => 'MyCompany::Widgets',
ALTFBASE => 'MyCompany::Forms',
COLUMNS => 40,
LINES => 20,
BORDER => 1,
BORDERCOL => 'white',
CAPTION => 'New Record',
CAPTIONCOL => 'yellow',
FOREGROUND => 'black',
BACKGROUND => 'white',
Y => 1,
X => 1,
INPUTFUNC => \&scankey,
DERIVED => 0,
AUTOCENTER => 1,
TABORDER => [qw(btnOKCancel edtLogon edtPsswd)],
FOCUSED => 'edtLogon',
WIDGETS => {
btnOKCancel => {
TYPE => 'ButtonSet',
LABELS => [qw(OK Cancel)],
Y => 8,
X => 3,
FOREGROUND => 'white',
BACKGROUND => 'green',
OnExit => \&btns,
},
edtLogon => {
TYPE => 'TextField',
FOREGROUND => 'white',
BACKGROUND => 'blue',
CAPTION => 'Logon',
CAPTIONCOL => 'yellow',
LENGTH => 21,
Y => 2,
X => 8,
},
edtPsswd => {
TYPE => 'TextField',
FOREGROUND => 'white',
BACKGROUND => 'blue',
CAPTION => 'Password',
CAPTIONCOL => 'yellow',
LENGTH => 21,
Y => 5,
X => 8,
PASSWORD => 1,
},
});
$form->setField(BORDER => 1);
@taborder = @{$form->getField('TABORDER')};
$form->addWidget('btnClose', { %options });
$widget = $form->getWidget('btnClose');
$form->addSubform('MainSubFrm', { %options });
$subform = $form->getSubform('MainSubFrm');
$form->execute($mwh);
pushwh($mwh);
popwh();
refreshwh();
lowerwh($wh);
raisewh($wh);
REQUIREMENTS
Curses Curses::Widgets
DESCRIPTION
Curses::Forms provide a simple framework for OO forms. The Forms module itself provides a basic class from which extended forms can be derived, or, it can be used as-is to control forms populated with widgets. More specialised forms are also available under Curses::Forms::Dialog.
INTRODUCTION
This module is partially derived from the Curses::Widgets module, and so has much of the same syntax and APIs. One area of special note, however, is populating a form with widgets.
ADDING WIDGETS
There are two ways to add widgets to a form: interactively (i.e., one at a time, at any time), or predeclared (i.e., all at once during object instantiation). Both methods require passing hashes containing all the standard arguments normally used when creating the widgets directly via the Curses::Widgets::* modules. There are a few new keys to be aware of, though:
Key Description
====================================================
TYPE Type of widget, relative to Curses::Widgets
OnEnter Subroutine reference to be called when the
widget first gains focus
OnExit Subroutine reference to be called when the
widget loses focus
Only TYPE is mandatory. The value is a string relative to the Curses::Widgets hierarchy. In other words, if you want a TextField widget, that's all you need to put in, not the full Curses::Widgets::TextField module name. This allows you to use new widgets with no special modifications needed in this module, as long as it's found within the Curses::Widgets namespace.
If you want to use custom widgets not in the Curses::Widgets namespace you must set the ALTBASE key to whatever the base class is called (i.e., 'MyCompany::Widgets', if all the widgets are within that heirarchy). The TYPE will use ALTBASE first, then, and if that fails, try Curses::Widgets. You can set ALTBASE to an array ref with multiple namespaces to search, if desired.
OnEnter and OnExit can be considered rudimentary event handlers. These subroutines are called when the widget gains and/or loses focus. These subroutines are always called with two arguments: a reference to the Curses::Forms object, and the last key stroke:
@$sub($form, $key)
This allows you to use these handlers to update other widgets on the form, or take appropriate action as needed. For instance, suppose you had a database record form open, with two buttons: Commit, and Cancel. The former would save the database changes, while the latter would just close the form. You would accomplish this as so:
# During widget declaration
$form->new({
...
WIDGETS => {
...
btnCommitCancel => {
...
OnExit => \&CancelOrCommit,
},
},
});
# Subroutine somewhere else in your program code
sub CancelOrCommit {
my $form = shift;
my $key = shift;
my $btns = $form->getWidget('btnCommitCancel');
# Make sure they user pressed <ENTER> to push a button
return unless $key eq "\n";
# The user pressed 'Commit'
if ($btn->getField('VALUE') == 0) {
# Save your record updates
...
# The user pressed 'Cancel'
} else {
$form->setField(EXIT => 1);
}
}
As you can see, this example also explains a special field used by the Curses::Forms object: EXIT. Whenever you want the form to be closed due to some condition or user input just set EXIT to some true value. Once your subroutine exits this field will be checked, and if true, will cause the form to break out of the execute loop.
Another special field is the DONTSWITCH field, which tells the form to keep the focus where it is.
A point of clarification: if you use the getField/setField operations to retrieve and modify the WIDGETS key, this will have no affect on the current set of widgets in the form. This key is only used during object instantiation, with all object references to the widgets stored internally, but outside of the configuration hash. Therefore, you can modify widget parameters only by retrieving the object reference via the getWidget method. Also, you can add widgets via the addWidget but there is no method to delete them.
The form content area is always a derived window, so widgets should always place themselves relative to (0, 0), regardless of whether or not the form has a border.
ADDING SUBFORMS
Adding subforms within a form is done in the same manner as widgets, either by passing the subform options via the SUBFORMS field, or by calling the addSubform method. Like the widgets implementation, subforms can be custom derivatives of Curses::Forms, all you need to do is declare the alternate Forms namespace(s) to search via the ALTFBASE key.
The only change in subform behaviour versus form behaviour is that once the focus leaves the last widget in the tab order, focus switches back to the parent form tab order, instead of looping within that subform.
MANAGING OVERLAPPING FORMS
Every time a non-derived form is displayed Curses::Forms pushes the active window handle onto an internal ordinal array. This array is used each time a window is released to refresh each window from the bottom up to make sure all the regions overlapped by the now-deleted form are redrawn. This is done by calling touchwin and noutrefresh on each window handle, and then a single doupdate at the end. The deleted form's window handle is popped off the array just prior to this refresh.
From time to time you may create windows that need to be redrawn with the other overlapping windows. Two functions are provided to handle this: pushwh and popwh. As you create the window you should use pushwh to put it in the array, and use popwh as soon as you delete it. If you'd like to manually refresh the screen, you may do so via the refreshwh subroutine.
To other functions are provided for lowering or raising the windows in the array: lowerwh and raisewh.
FUNCTIONS
Using this module will import the same set of functions provided by Curses::Widgets. Please consult the Curses::Widgets pod for a complete reference of these functions.
New functions provided by this module are documented below.
pushwh
pushwh($mwh);
Pushes an external window handle onto the Curses::Forms-managed refresh array.
popwh
popwh();
Pops a window handle off the Curses::Forms-managed refresh array.
refreshwh
refreshwh();
Refreshes each window in order of the ordinal array.
raisewh
raisewh($wh);
Raises the passed window in the array.
lowerwh
lowerwh($wh);
Lowers the passed window in the array.
METHODS
new
$obj = Curses::Forms->new({
ALTBASE => 'MyCompany::Widgets',
ALTFBASE => 'MyCompany::Forms',
COLUMNS => 40,
LINES => 20,
BORDER => 1,
BORDERCOL => 'white',
CAPTION => 'New Record',
CAPTIONCOL => 'yellow',
FOREGROUND => 'black',
BACKGROUND => 'white',
Y => 1,
X => 1,
INPUTFUNC => \&scankey,
DERIVED => 0,
AUTOCENTER => 1,
TABORDER => [qw(btnOKCancel edtLogon edtPsswd)],
FOCUSED => 'edtLogon',
WIDGETS => {
btnOKCancel => {
TYPE => 'ButtonSet',
LABELS => [qw(OK Cancel)],
Y => 8,
X => 3,
FOREGROUND => 'white',
BACKGROUND => 'green',
OnExit => \&btns,
},
edtLogon => {
TYPE => 'TextField',
FOREGROUND => 'white',
BACKGROUND => 'blue',
CAPTION => 'Logon',
CAPTIONCOL => 'yellow',
LENGTH => 21,
Y => 2,
X => 8,
},
edtPsswd => {
TYPE => 'TextField',
FOREGROUND => 'white',
BACKGROUND => 'blue',
CAPTION => 'Password',
CAPTIONCOL => 'yellow',
LENGTH => 21,
Y => 5,
X => 8,
PASSWORD => 1,
},
});
This method instantiates a new instance of a Curses::Form object. All configuration directives, with the exception of COLUMNS and LINES are optional. The defaults for the rest are described below:
Key Default Description
==============================================================
BORDER 0 Display a border around the form
BORDERCOL undef Foreground colour for border
CAPTION undef Caption superimposed on border
CAPTIONCOL undef Foreground colour for caption text
FOREGROUND undef Foreground colour for form
BACKGROUND undef Background colour for form
Y 0 Y coordinate for upper left corner
X 0 X coordinate for upper left corner
INPUTFUNC \&scankey Function to use to scan for keystrokes
DERIVED 1 Whether to create the form as a derived
or new window
TABORDER [] Order in which widgets will get the
focus
FOCUSED undef Currently focused widget
WIDGETS {} Widgets used on the form
ALTBASE undef Alternate namespace to search for
loadable widgets
ALTFBASE undef Alternate namespace to search for
loadable forms
AUTOCENTER 0 Whether or not to center the form in the
display (only for non-derived windows)
The CAPTION is only valid when the BORDER is enabled. INPUTFUNC will be passed to each widget explicitly. FOREGROUND, BACKGROUND, and CAPTIONCOL will be passed to each widget if that widget's declaration doesn't specify it directly.
Please see the Introduction section on special handling of the declaration of widgets.
draw
$form->draw($mwh);
This methods renders and displays the form in its current state. An optional second argument designates whether or not the focused widget should be drawn in active mode or not.
setField/getField
$form->setField(BORDER => 1);
@taborder = @{$form->getField('TABORDER')};
These methods are inherited from the Curses::Widgets module, and hence are syntactically the same. For more specifics please see that module.
addWidget
$form->addWidget('btnClose', { %options });
This method allows you to add a widget to the form. Please see the INTRODUCTION for a more indepth explanation of this call. Returns a true if successful, or a false if not (if, for instance, you're trying to use a widget that module can be found for, or a widget by that name already exists).
getWidget
$widget = $form->getWidget('btnClose');
Retrieves a reference to a widget object. Returns an undef if the widget does not exist under the passed name.
addSubform
$form->addSubform('MainSubFrm', { %options });
This method allows you to add a subform to the form. Please see the INTRODUCTION for a more indepth explanation of this call. Returns a true if successful, or a false if not (if, for instance, you're trying to use a form that module can't be found for, or a widget by that name already exists).
getSubform
$subform = $form->getSubform('MainSubFrm');
Retrieves a reference to a subform object. Returns an undef if the form does not exist under the passed name.
execute
$form->execute($mwh);
This method starts the form loop to scan input and cycle through the widgets that can get focus. A valid window handle must be passed for any form using DERIVED mode.
HISTORY
AUTHOR/COPYRIGHT
(c) 2001 Arthur Corliss (corliss@digitalmages.com)