#! /usr//bin/perl
##
use strict;
use warnings;
use English;
use ExtUtils::testlib;
use Curses;
sub fatal {
clrtobot(0, 0);
addstr(0, 0, "@_\n");
refresh();
sleep 2;
die("Fatal error");
}
sub driveForm($$) {
my ($fwinR, $formR) = @_;
while (1) {
my $ch = getch($fwinR);
if ($ch eq KEY_UP) {
form_driver($formR, REQ_PREV_FIELD);
} elsif ($ch eq KEY_DOWN or $ch eq "\t" or
$ch eq "\r" or $ch eq "\n") {
form_driver($formR, REQ_NEXT_FIELD);
} elsif ($ch eq KEY_LEFT) {
form_driver($formR, REQ_LEFT_CHAR);
} elsif ($ch eq KEY_RIGHT) {
form_driver($formR, REQ_RIGHT_CHAR);
} elsif ($ch eq KEY_NPAGE) {
form_driver($formR, REQ_NEXT_PAGE);
} elsif ($ch eq KEY_PPAGE) {
form_driver($formR, REQ_PREV_PAGE);
} elsif ($ch eq KEY_DC or ord($ch) == 8 or ord($ch) == 127) {
form_driver($formR, REQ_DEL_PREV);
} elsif ($ch eq KEY_F(1)) {
last;
} elsif ($ch =~ /^\S$/) {
form_driver($formR, ord($ch));
} else {
beep();
}
}
}
sub makeFields() {
my $fieldListR = [
[ 'L', 0, 0, 0, 8, "Form" ],
[ 'L', 0, 0, 2, 0, "First Name" ],
[ 'F', 1, 15, 2, 12, "F Name" ],
[ 'L', 0, 0, 3, 0, "Last Name" ],
[ 'F', 1, 15, 3, 12, "L Name" ],
[ 'L', 0, 0, 5, 8, "Form (pt 2)" ],
[ 'L', 0, 0, 7, 0, "# Tuits" ],
[ 'F', 1, 5, 7, 12, "Tuits" ],
[ 'L', 0, 0, 8, 0, "# Bleems" ],
[ 'F', 1, 5, 8, 12, "Bleems" ]
];
my @fieldRList;
foreach my $F (@{$fieldListR}) {
my $fieldR;
# This is a Perl reference to a scalar number variable. The
# number is the numerical equivalent (cast) of the C pointer to the
# executable-Curses FIELD object. The reference is blessed into
# package "Curses::Field", but don't confuse it with a Perl
# object.
if ($F->[0] eq 'L') {
$fieldR = new_field(1, length($F->[5]), $F->[3], $F->[4], 0, 0);
if ($$fieldR eq '') {
fatal("new_field $F->[5] failed");
}
set_field_buffer($fieldR, 0, $F->[5]);
field_opts_off($fieldR, O_ACTIVE);
field_opts_off($fieldR, O_EDIT);
} elsif ($F->[0] eq 'F') {
$fieldR = new_field($F->[1], $F->[2], $F->[3], $F->[4], 0, 0);
if ($$fieldR eq '') {
fatal("new_field $F->[5] failed");
}
if ($F->[5] eq "Tuits") {
set_field_buffer($fieldR, 0, $F->[5]);
}
set_field_back($fieldR, A_UNDERLINE);
}
push(@fieldRList, $fieldR);
}
return @fieldRList;
}
sub interpretForm($$$) {
my ($cFieldRListR, $firstNameR, $lastNameR) = @_;
$$firstNameR = field_buffer($cFieldRListR->[2], 0);
$$lastNameR = field_buffer($cFieldRListR->[4], 0);
}
sub demo($$) {
my ($firstNameR, $lastNameR) = @_;
noecho();
eval { new_form() };
if ($@ =~ m{not defined in your Curses library}) {
print STDERR "Curses was not compiled with form function.\n";
exit 1;
}
my @cFieldRList = makeFields();
# Believe it or not, we have to pass to new_form() a string whose
# representation in memory is a C array of pointers to C field objects.
# Don't try to understand it; just copy this magic pack code.
# The argument is a string whose ASCII encoding is an array of C
# pointers. Each pointer is to a FIELD object of the
# executable-Curses library, except the last is NULL to mark the
# end of the list. For example, assume there are two fields and
# the executable-Curses library represents them with FIELD objects
# whose addresses (pointers) are 0x11223344 and 0x0004080C. The
# argument to Curses::new_form() is a 12 character string whose
# ASCII encoding is 0x112233440004080C00000000 .
my @cFieldList;
foreach my $cFieldR (@cFieldRList) {
push(@cFieldList, ${$cFieldR});
}
push(@cFieldList, 0);
my $fieldListFormArg = pack('L!*', @cFieldList);
my $formR = new_form($fieldListFormArg);
if (${$formR} eq '') {
fatal("new_form failed");
}
# Don't under any circumstance destroy $itemListMenuArg while the menu
# object still exists, since the C menu object actually points to the
# memory that backs $itemListMenuArg.
# And don't destroy @cItemList or @cItemRList either while the menu object
# still exists, because they are backed by memory that the C menu object
# references as well.
my $rows;
my $cols;
scale_form($formR, $rows, $cols);
my $fwinR = newwin($rows + 2, $cols + 4, 4, 0);
my $fsubR = derwin($fwinR, $rows, $cols, 1, 2);
set_form_win($formR, $fwinR);
set_form_sub($formR, $fsubR);
box($fwinR, 0, 0);
keypad($fwinR, 1);
post_form($formR);
addstr(0, 0, "Use KEY_UP/KEY_DOWN/KEY_PPAGE/KEY_NPAGE to navigate");
addstr(1, 0, "Press 'ENTER' to select item, or 'F1' to exit");
addstr(2, 0, "Other alphanumeric characters will enter data");
refresh();
driveForm($fwinR, $formR);
interpretForm(\@cFieldRList, $firstNameR, $lastNameR);
unpost_form($formR);
delwin($fwinR);
free_form($formR);
map { free_field($_) } @cFieldRList;
}
##############################################################################
# MAINLINE
##############################################################################
initscr();
# The eval makes sure if it croaks, we have a chance to restore the
# terminal.
my ($firstName, $lastName);
eval { demo(\$firstName, \$lastName) };
endwin();
if ($@) {
print STDERR "Failed. $@\n";
exit(1);
}
print "You entered '$firstName' for First Name and "
. "'$lastName' for Last Name\n";
exit(0);