#!perl -l #-----------------------------------------------------------------# # Calculator # pudge # Duplicate Mac OS Calculator DA in MacPerl # # Created: Chris Nandor (pudge@pobox.com) 19-Mar-98 # Last Modified: Chris Nandor (pudge@pobox.com) 20-Mar-98 #-----------------------------------------------------------------# # Why? Because I can. #-----------------------------------------------------------------# use Mac::Events; use Mac::QuickDraw; use Mac::Windows; use Mac::Fonts; use Mac::Menus; use Mac::Resources; use Mac::Memory; use Math::BigFloat; use strict; my($res, $menu, $smenu1, $smenu2, $win, %d, %b, %e, %i, $val, $vals, $op); ++$|; #================================================================= %d = ( winr => OffsetRect(Rect->new( 0, 0, 104, 148), 50, 50), wrect => Rect->new( 0, 0, 104, 148), irect => Rect->new( 0, 0, 102, 146), brect => Rect->new( 0, 0, 18, 16), hrect => Rect->new( 0, 0, 40, 16), vrect => Rect->new( 0, 0, 18, 38), trect => OffsetRect(Rect->new( 0, 0, 86, 20), 7, 7), textp => [88, 21], c0 => new_color( 0, 0, 0), c7 => new_color(65535, 65535, 65535), # white c1 => new_color(48059, 48059, 48059), # grey c2 => new_color(65535, 0, 0), # red c3 => new_color(65535, 65535, 0), # yellow c4 => new_color( 0, 65535, 0), # green c5 => new_color( 0, 0, 65535), # blue c6 => new_color(65535, 0, 65535), # violet c8 => new_color(17476, 17476, 17476), # dark grey c9 => new_color(13107, 26214, 26214), # aqua c10 => new_color( 0, 0, 30583), # dark blue c11 => new_color(26214, 13107, 39321), # purple c12 => new_color(39321, 0, 0), # dark red c13 => new_color(65535, 39321, 0), # orange ); %i = ( 'C' => [ 8, 32], '4' => [ 8, 76], '7' => [ 8, 54], '=' => [ 30, 32], '5' => [ 30, 76], '8' => [ 30, 54], '/' => [ 52, 32], '6' => [ 52, 76], '9' => [ 52, 54], '*' => [ 74, 32], '-' => [ 74, 54], '= ' => [ 74, 98], '1' => [ 8, 98], '+' => [ 74, 76], '2' => [ 30, 98], '0' => [ 8, 120], '3' => [ 52, 98], '.' => [ 52, 120], ); foreach (keys %i) { if ($_ eq '= ') { $b{$_}{'r'} = OffsetRect($d{vrect}, @{$i{$_}}); $b{$_}{'o'} = OffsetRect($d{vrect}, ${$i{$_}}[0]+2, ${$i{$_}}[1]+2); $b{$_}{'t'} = [ ${$i{$_}}[0] + 6, ${$i{$_}}[1] + 34 ]; } elsif ($_ eq '0') { $b{$_}{'r'} = OffsetRect($d{hrect}, @{$i{$_}}); $b{$_}{'o'} = OffsetRect($d{hrect}, ${$i{$_}}[0]+2, ${$i{$_}}[1]+2); $b{$_}{'t'} = [ ${$i{$_}}[0] + 6, ${$i{$_}}[1] + 12 ]; } else { $b{$_}{'r'} = OffsetRect($d{brect}, @{$i{$_}}); $b{$_}{'o'} = OffsetRect($d{brect}, ${$i{$_}}[0]+2, ${$i{$_}}[1]+2); $b{$_}{'t'} = [ ${$i{$_}}[0] + 6, ${$i{$_}}[1] + 12 ]; } $b{$_}{'d'} = [$b{$_}{'r'}->left(), $b{$_}{'r'}->top(), $b{$_}{'r'}->right(), $b{$_}{'r'}->bottom()]; } $d{bbc} = $d{c0}; $d{bgc} = $d{c1}; $res = OpenResFile($0); die $^E if !$res; $menu = MacMenu->new(2048, 'Calculator', ( ['Indicator Color', sub{}, chr(27), chr(230)], ['Window Color', sub{}, chr(27), chr(231)], ['Default Colors', \&menu_hit, 'M'], [], ['Close', \&menu_hit, 'W'], ['Quit', \&menu_hit, 'Q'], )); $smenu1 = MacHierMenu->new(230, 'Indicator Color', ( ['Grey', \&menu_hit, undef, undef, 463], ['Red', \&menu_hit, undef, undef, 465], ['Yellow', \&menu_hit, undef, undef, 464], ['Green', \&menu_hit, undef, undef, 461], ['Blue', \&menu_hit, undef, undef, 462], ['Violet', \&menu_hit, undef, undef, 460], )); $smenu2 = MacHierMenu->new(231, 'Window Color', ( ['Dark Grey', \&menu_hit, undef, undef, 450], ['Aqua', \&menu_hit, undef, undef, 451], ['Dark Blue', \&menu_hit, undef, undef, 452], ['Purple', \&menu_hit, undef, undef, 453], ['Dark Red', \&menu_hit, undef, undef, 454], ['Orange', \&menu_hit, undef, undef, 455], )); #================================================================= $win = MacWindow->new(NewCWindow($d{winr}, 'Calculator', 1, rDocProc(), 1)); $win->sethook('redraw', \&draw_win); $win->sethook('click', \&get_click); $win->sethook('key', \&get_key); $menu->insert(); $smenu1->insert(); $smenu2->insert(); while ($win->window()) { WaitNextEvent(); } #================================================================= sub menu_hit { my($m, $v) = @_; if ($m == $menu->{id} && ($v == 5 || $v == 6)) { $win->dispose(); } elsif ($m == $menu->{id} && $v == 3) { $d{bbc} = $d{c0}; $d{bgc} = $d{c1}; $win->redraw(); for (1..6) { CheckItem($smenu1->{menu}, $_, 0); CheckItem($smenu2->{menu}, $_, 0); } } elsif ($m == $smenu1->{id} && $v >= 1 && $v <= 6) { $d{bbc} = $d{'c' . $v}; $win->redraw(); for (1..6) { CheckItem($smenu1->{menu}, $_, 0); } CheckItem($smenu1->{menu}, $v, 1); } elsif ($m == $smenu2->{id} && $v >= 1 && $v <= 6) { $d{bgc} = $d{'c' . ($v + 7)}; $win->redraw(); for (1..6) { CheckItem($smenu2->{menu}, $_, 0); } CheckItem($smenu2->{menu}, $v, 1); } redo_trect('What ugly colors!') if ($d{bgc} eq $d{c11} && $d{bbc} eq $d{c2}); 1; } #================================================================= sub get_click { my($w, $p, $k, $f, $d) = @_; my($ph, $pv) = ($p->h(), $p->v()); foreach (keys %i) { if (is_point($ph, $pv, $b{$_}{'d'})) { $k = $_; } } return if !defined($k); while (WaitMouseUp()) { $p = GetMouse(); ($ph, $pv) = ($p->h(), $p->v()); $d = is_point($ph, $pv, $b{$k}{'d'}); if (!$f && $d) { but_down($k); $f++; } elsif ($f && !$d) { but_up($k); $f--; } WaitNextEvent(); } $p = GetMouse(); ($ph, $pv) = ($p->h(), $p->v()); but_up($k); if (is_point($ph, $pv, $b{$k}{'d'})) { redo_trect(calculate($k)); } } #================================================================= sub get_key { my($win, $v, $k) = @_; my($mod) = $Mac::Events::CurrentEvent->modifiers(); if ($v =~ /^(?:99|67|27)$/) { $k = 'C'; } elsif ($v =~ /^(?:3|13|61)$/) { $k = '='; #[46-57] 42|43|45 } elsif ($v =~ /^(?:4[2-35-9]|5[0-7])$/) { $k = chr($v); } if (defined($k)) { but_down($k); WaitNextEvent(); but_up($k); redo_trect(calculate($k)); # } else { # print "\007"; } } #================================================================= sub calculate { my($k, $q) = @_; if ($k =~ /[\d.]/ || ($k =~ /\-/ && (!defined($val) && !defined($vals)))) { $q = $val .= $k; } elsif ($k eq 'C') { undef $val; undef $vals; undef $op; $q = 0; } elsif ($k =~ /[\+\-\/\*\=]/) { if (defined($vals) && defined($val) && defined($op)) { if ($op eq '/' && $val == 0) { $q = 'not a number'; undef $val; undef $vals; undef $op; } else { my($v) = eval("$vals $op $val"); undef $val; $q = $vals = $v; } } elsif (defined($val)) { $vals = $val; undef $val; $q = $vals; } else { $q = $vals; } if ($k =~ /\=/) { $vals = $q; undef $val; undef $op; } else { $op = $k; } } print_num($q); } #================================================================= sub print_num { my($q) = @_; $q = 0 if $q == 0; if (abs($q) >= 10**12 || ($q != 0 && 1/abs($q) >= 10**9)) { # print "1a $q"; $q = Math::BigFloat->new($q)->fround(9); $q =~ s/\+//g; # print "1b $q"; } else { $q =~ /^(-?[0-9]+)/; my($len) = 11 - length($1); $len = 0 if $len < 0; # print "2a $q"; $q = sprintf("%11.${len}f", $q); if ($q =~ /\./) {$q =~ s/0*$//} $q =~ s/\.$//; # print "2b $q"; } $q; } #================================================================= sub redo_trect { my($v) = @_; EraseRect($d{'trect'}); FrameRect($d{'trect'}); MoveTo(${$d{'textp'}}[0] - StringWidth($v), ${$d{'textp'}}[1]); DrawString($v); } #================================================================= sub but_up { my($k) = @_; RGBForeColor($d{bbc}); PaintRect($b{$k}{'o'}); RGBForeColor($d{c7}); PaintRect($b{$k}{'r'}); RGBForeColor($d{c0}); FrameRect($b{$k}{'r'}); MoveTo(@{$b{$k}{'t'}}); DrawString($k); } #================================================================= sub but_down { my($k) = @_; RGBForeColor($d{bbc}); PaintRect($b{$k}{'o'}); RGBForeColor($d{c0}); PaintRect($b{$k}{'r'}); RGBForeColor($d{c7}); MoveTo(@{$b{$k}{'t'}}); DrawString($k); } #================================================================= sub draw_win { TextFont(geneva()); TextFace(normal()); TextSize(9); PaintRect($d{wrect}); RGBForeColor($d{bgc}); PaintRoundRect($d{irect}, 8, 8); RGBForeColor($d{bbc}); foreach (keys %i) { PaintRect($b{$_}{'o'}); } RGBForeColor($d{c7}); PaintRect($d{'trect'}); foreach (keys %i) { PaintRect($b{$_}{'r'}); } RGBForeColor($d{c0}); FrameRect($d{'trect'}); foreach (keys %i) { FrameRect($b{$_}{'r'}); MoveTo(@{$b{$_}{'t'}}); DrawString($_); } redo_trect(defined($val) ? print_num($val) : defined($vals) ? print_num($vals) : 0); } #================================================================= sub new_color { bless \pack('SSS', @_[0..2]), 'RGBColor'; } #================================================================= sub is_point { my($ph, $pv, $r) = @_; $ph > $$r[0] && $ph < $$r[2] && $pv > $$r[1] && $pv < $$r[3]; } #================================================================= END { $smenu1->dispose() if defined($smenu1); $smenu2->dispose() if defined($smenu2); $menu->dispose() if defined($menu); $win->dispose() if defined($win); CloseResFile(CurResFile()) if $res; } #================================================================= __END__