The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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

2000/02/29 -- Original functional version
2002/10/10 -- Rewritten in OO form

AUTHOR/COPYRIGHT

(c) 2001 Arthur Corliss (corliss@digitalmages.com)