In Chapter 22, "Perl/Tk and the Web", we discussed the Netscape PerlPlus Plugin and used several PPL programs in our examples. We include two PPL programs in this appendix. The first is the clock-bezier.ppl program, shown in Figure C-3.

#!/usr/local/bin/perl -w
#
# This most entertaining program was written in Tcl/Tk by Scott Hess
# (shess@winternet.com). It's a clock that uses a bezier curve anchored
# at four points—the hour position, the minute position, the second
# position and the center of the clock—to show the time.
#
# <Button-1> switches between display modes, and <Button-2> switches
# between line thicknesses.
#
# Perl/Tk version by Stephen.O.Lidie@Lehigh.EDU, 2000/02/05.
use POSIX qw/asin/;
use Tk;
use subs qw/buildclock hands setclock/;
use vars qw/$clock %hand $mw $pi180 $resize/;
use strict;
%hand = (
hour => 0.40,
minute => 0.75,
second => 0.85,
0 => 0.00,
intick => 0.95,
outtick => 1.00,
width => 0.05,
scale => 100,
type => 'bezier',
types => [qw/normal curve angle bezier/],
tindx => 3,
normal => [qw/minute 0 0 second 0 0 hour 0 0 minute/],
curve => [qw/minute 0 second 0 hour 0 minute/],
angle => [qw/minute second second hour/],
bezier => [qw/minute second 0 hour/],
tick => [qw/intick outtick/],
);
$pi180 = asin(1) / 90.0;
$resize = 0;
$mw = MainWindow->new;
$clock = $mw->Canvas(qw/-width 200 -height 200/);
$clock->pack(qw/-expand 1 -fill both/);
$mw->bind('<Configure>' => \&buildclock);
$mw->bind('<Button-1>' => \&incrtype);
$mw->bind('<Button-2>' => \&incrwidth);
buildclock;
$mw->repeat(1000 => sub {my(@t) = localtime; setclock @t[0 .. 2]});
MainLoop;
sub buildclock {
# Build the clock. Puts tickmarks every 30 degrees, tagged
# "ticks", and prefills the "hands" line.
my $pi180 = asin(1)/90.0;
Tk::catch {$clock->delete('marks')};
$clock->update;
my $w = $clock->width;
$mw->geometry("${w}x${w}") if $resize; # ensure clock is square
$resize++;
$hand{scale} = $w / 2.0;
# This is a horrid hack. Use the hands( ) procedure to
# calculate the tickmark positions by temporarily changing
# the clock type.
my $type = $hand{type};
$hand{type} = 'tick';
my %angles;
for (my $ii = 0; $ii < 12; $ii++) {
$angles{intick} = $angles{outtick} = $ii * 30 * $pi180;
$clock->createLine(hands(\%angles), -tags => [qw/ticks marks/]);
}
$hand{type} = $type;
$clock->createLine(qw/0 0 0 0 -smooth 1 -tags/ => [qw/hands marks/]);
$clock->itemconfigure(qw/marks -capstyle round -width/ =>
$hand{width} * $hand{scale});
}
sub hands {
# Calculate the set of points for the current hand type and
# the angles in the passed array.
my($aa) = @_;
my $ss = $hand{scale};
my @points;
foreach my $desc ( @{ $hand{$hand{type}} } ) {
push @points, sin($aa->{$desc}) * $hand{$desc} * $ss + $ss;
push @points, $ss - cos($aa->{$desc}) * $hand{$desc} * $ss;
}
#print join(', ', @points), "\n";
return @points;
}
sub incrtype {
$hand{type} = $hand{types}->[ ++$hand{tindx} % @{$hand{types}} ];
}
sub incrwidth {
my $w = $hand{width} + .05;
$hand{width} = $w > .25 ? 0 : $w;
$clock->itemconfigure('marks', -width => $hand{width} * $hand{scale});
}
sub setclock {
# Calculate the angles for the second, minute, and hour hands,
# and then update the clock hands to match.
my($second, $minute, $hour) = @_;
my %angles;
$angles{0} = 0;
$angles{second} = $second * 6 * $pi180;
$angles{minute} = $minute * 6 * $pi180;
$angles{hour} = $hour * 30 * $pi180 + $angles{minute} / 12;
my $sector = int( $angles{second} + 0.5 );
my(@colors) = qw/cyan green blue purple red yellow orange/;
$clock->itemconfigure(qw/hands -fill/ => $colors[$sector]);
$clock->coords('hands', hands \%angles);
}
Copyright © 2002 O'Reilly & Associates. All rights reserved.