#!/usr/bin/perl -w =head1 NAME timer - A Perl Tk Timer Reminiscent of an old Gralab darkroom timer. =head1 USAGE ./timer.pl duration [-n bells -s size -h height -w width -u update_rate -t title] ./timer.pl 600 -t"10 minute break" -n20 -fred -bgrey =head1 AUTHOR Copyright 2001 Tom Anderson <t@tomacorp.com> http://tomacorp.com Perlmonks: toma Thanks to predecessor codebase from Internet-time clock code, which is Copyright 1999 Walter C. Mankowski =head1 COPYING You may copy and distribute this program under the same terms as Perl iteself. =head1 SEE ALSO Tk, Getopt::Std =cut use vars qw( $VERSION ); $VERSION = '1.0'; use Tk; use Getopt::Std; my $duration= shift; my %opts; getopt('b:f:h:n:s:t:u:w:', \%opts); my $pi = 4.0 * atan2(1,1); # Option handling my $maxbell; if (exists $opts{n}) { $maxbell= $opts{n}} else {$maxbell=3} my ($canvas_height, $canvas_width); if (exists $opts{s} and $opts{s} >= 40 ) { $canvas_height= $opts{s}; $canvas_width= $opts{s}; } else { $canvas_height= 210; $canvas_width= 210; } if (exists $opts{h} and $opts{h} >= 40 ) { $canvas_height= $opts{h}} else {$canvas_height=210} if (exists $opts{w} and $opts{w} >= 40 ) { $canvas_width= $opts{w}} else {$canvas_width=210} my $update_rate; if (exists $opts{u}) { $update_rate= $opts{u}} else {$update_rate=200} my $title; if (exists $opts{t}) { $title= $opts{t}} else {$title='PerlLab'} my $foreground; if (exists $opts{f}) { $foreground= $opts{f}} else {$foreground='green'} my $background; if (exists $opts{b}) { $background= $opts{b}} else {$background='black'} my $canvas_margin = 5; my $numbell=0; my $tstop; if ($duration =~ /([0-9]+):([0-9]+)/) { $tstop= 60*$1+$2 } elsif ($duration =~ /([0-9]+)/) { $tstop= $1 } elsif ($duration eq "") { usage(); exit; } else { print "Error: Time `$duration' not in format seconds or minutes:seconds\n\n" ; usage(); exit; } my $timestart= time + $tstop; # Computed Tk parameters my $clock_center_y; my $clock_center_x; my $face_y_radius; my $face_x_radius; my $canvas_max; my $hand_len; my $sec_width; my $min_width; my $center_circle_r; my $tick_width; my $mw = MainWindow->new; my $canvas; $mw->title($title); $mw->client("labtimer"); drawclock(); &MainLoop; sub drawclock { # Draws the timer $clock_center_y= $canvas_height/2; $clock_center_x= $canvas_width/2; $face_y_radius= $canvas_height/2 - $canvas_margin; $face_x_radius = $canvas_width/2 - $canvas_margin; $canvas_max= ($canvas_height < $canvas_width) ? $canvas_height:$canvas_width; $hand_len= $canvas_max/2 - $canvas_margin; $sec_width = $hand_len/50+1; $min_width = $hand_len/30+1; $center_circle_r= int($min_width/sqrt(2))+1; $tick_width=$canvas_max/200+1; # $canvas is where the analog clock goes $canvas = $mw->Canvas(-height => $canvas_height, -background => $background, -width => $canvas_width) ->pack (-side => 'top', -expand => 1); # the outer circle $canvas->createOval($canvas_margin, $canvas_margin, $canvas_width-$canvas_margin, $canvas_height-$canvas_margin, -width => 5, -fill => $background, -outline => $foreground ); # the inner circle where the hands meet $canvas->createOval($clock_center_x-$center_circle_r,$clock_center_y-$center_circle_r, $clock_center_x+$center_circle_r,$clock_center_y+$center_circle_r, -fill => $foreground, -outline => $foreground ); # ticks around the outside hands &DrawTicks; &DrawHands ($canvas, $timestart-time, 1); # periodically move the hands $canvas->repeat( $update_rate, \&RedrawHands, $canvas); } sub DrawHands { my ($canvas, $t) = @_; # Second hand $hand1 = &DrawHand ($canvas, $t / 60, $hand_len * 0.90, $sec_width); # Minute hand $hand2 = &DrawHand ($canvas, $t / 3600, $hand_len * 0.75, $min_width); } sub DrawHand { my ($canvas, $frac, $length, $line_width) = @_; my $height; my $width; my $theta; my $hand; $theta = ($frac * 2 * $pi) - ($pi / 2); $height = $length * sin($theta); $width = $length * cos($theta); $hand = $canvas->createLine($clock_center_x, $clock_center_y, $clock_center_x+$width, $clock_center_y+$height, -arrow => "last", -width => $line_width, -fill => $foreground); } sub RedrawHands { my $canvas = shift; if ($timestart - time < 0) { exit if $numbell >= $maxbell; $canvas->bell(); $numbell++; } else { $canvas->delete ($hand1, $hand2); &DrawHands ($canvas, $timestart-time, 1); } } sub DrawTicks { my $i; my ($y1, $x1, $y2, $x2); my $theta; my $scale; foreach $i (1..60) { if ($i % 15 == 0) # Major ticks { $scale = 0.80; } elsif ($i % 5 == 0) # Medium ticks { $scale = 0.90; } else # Minor ticks { $scale = 0.95; } $theta = ($i/60 * 2 * $pi) - ($pi / 2); $x1 = $face_x_radius * $scale * cos($theta) + $clock_center_x; $y1 = $face_y_radius * $scale * sin($theta) + $clock_center_y; $x2 = $face_x_radius * cos($theta) + $clock_center_x; $y2 = $face_y_radius * sin($theta) + $clock_center_y; $canvas->createLine($x1, $y1, $x2, $y2, -fill => $foreground, -width => $tick_width); } } sub usage { print 'timer.pl duration [-n bells -s size -h height -w width -u update_rate -t title]',"\n", "Example:\n",' timer.pl 7:00 -t"flip bbq"', "\n"; }