|
#!/usr/local/bin/perl -w
|
|
#
|
|
# modometer - the Mac Mouse Odometer, Perl/Tk style.
|
|
#
|
|
# Accumulate distances using this formula:
|
|
#
|
|
# distance = sqrt( (dX * (Xmm/Xpixels))**2 + (dY * (Ymm/Ypixels))**2\
|
|
)
|
|
#
|
|
# Where dX and dY are pixel differentials, and Xmm, Ymm and Xpixels, Y\
|
|
pixels
|
|
# are the screen dimensions in millimeters and pixels, respectively.
|
|
#
|
|
# Stephen O. Lidie, Lehigh University Computing Center, lusol@Lehigh.E\
|
|
DU
|
|
# 96/04/29.
|
|
#
|
|
# Copyright (C) 1995 - 1996 Stephen O. Lidie. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify\
|
|
it under
|
|
# the same terms as Perl itself.
|
|
|
|
require 5.002;
|
|
my $LIBDIR; BEGIN {$LIBDIR = "./lib"} # modo auxiliary files directory
|
|
use lib $LIBDIR;
|
|
use English;
|
|
use strict;
|
|
use Tk;
|
|
use Tk::ColorEditor;
|
|
use Tk::ErrorDialog;
|
|
use Tk::Odometer;
|
|
use Tk::ROText;
|
|
# Predeclare global subroutines and variables.
|
|
use subs qw(sub build_main_window build_usage_window build_verify_wind\
|
|
ow
|
|
initialize modo save_modo set_modo_colors update_status wh\
|
|
ich_odo);
|
|
|
|
my $ABOUT; # modo's About Dialog widget
|
|
my $ACCELERATION; # pointing device's acceleration facto\
|
|
r
|
|
my ($AUTOSAVE_COUNT, $AUTOSAVE_TICKS); # .modo auto-save information
|
|
my $COLOR_STATE; # do we have a color monitor?
|
|
my $CREF; # ColorEditor widget reference
|
|
my $CURSOR; # mouse cursor list reference
|
|
my $DEFAULT_UNITS; # default human units
|
|
my ($LAST_X, $LAST_Y); # previous pointing device coordinates
|
|
my $MILLISECOND_DELAY; # time delay before rescheduling the m\
|
|
ain loop
|
|
my ($MM_PIXEL_X, $MM_PIXEL_Y); # mm/pixel in width and height
|
|
my $MODO_UNITS; # numeric conversion factor --> mil\
|
|
limeters
|
|
my $MODO_UNITS_HUMAN; # description of above for human consu\
|
|
mption
|
|
my $MW; # Tk main Window
|
|
my $NUMBERS; # verify toplevel widget
|
|
my %OPT; # command line option values go here
|
|
my ($PIXELS_IN_X, $PIXELS_IN_Y); # pixels/inch in width and height
|
|
my ($PIXELS_CM_X, $PIXELS_CM_Y); # pixels/cm in width and height
|
|
my $QUIT_COMMAND; # code reference of Quit subroutine
|
|
my ($STATUS, $STATUS_B, $STATUS_L); # initialization status widgets
|
|
my $THRESHOLD; # pointer threshold
|
|
my @UNITS; # modo units list
|
|
my $USAGE; # usage toplevel widget
|
|
my $VERSION; # version number
|
|
my ($W_CODO, $W_PODO); # cursor and pointer Odometer widgets
|
|
my ($W_MISC, $W_MISC_TEXT); # miscellaneous status line widget
|
|
|
|
# Begin main.
|
|
|
|
initialize;
|
|
modo;
|
|
MainLoop;
|
|
|
|
# End main.
|
|
|
|
sub build_main_window {
|
|
|
|
# Construct the main modometer window.
|
|
|
|
update_status 'Odometer Window';
|
|
|
|
my $w = $MW->Frame;
|
|
|
|
# Frame to contain the menu buttons across the top of the main win\
|
|
dow.
|
|
|
|
my $mb = $w->Frame(qw(-bd 1 -relief raised));
|
|
|
|
# File menu.
|
|
|
|
my $mbf = $mb->Menubutton(
|
|
-text => 'File',
|
|
-underline => 0,
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
-cursor => $CURSOR,
|
|
-padx => 0,
|
|
);
|
|
$mbf->command(-label => 'Abort', -underline => 0, -comman\
|
|
d => \&exit);
|
|
$mbf->separator;
|
|
my $close_command = [$MW => 'iconify'];
|
|
$mbf->command(
|
|
-label => 'Close',
|
|
-underline => 0,
|
|
-command => $close_command,
|
|
-accelerator => 'Ctrl-w',
|
|
);
|
|
$MW->bind('<Control-Key-w>' => $close_command);
|
|
$mbf->separator;
|
|
my $save_command = \&save_modo;
|
|
$mbf->command(
|
|
-label => 'Save',
|
|
-underline => 0,
|
|
-command => $save_command,
|
|
-accelerator => 'Ctrl-s',
|
|
);
|
|
$MW->bind('<Control-Key-s>' => $save_command);
|
|
$mbf->separator;
|
|
$mbf->command(
|
|
-label => 'Quit',
|
|
-underline => 0,
|
|
-command => $QUIT_COMMAND,
|
|
-accelerator => 'Ctrl-q',
|
|
);
|
|
$MW->bind('<Control-Key-q>' => $QUIT_COMMAND);
|
|
|
|
# Prefs menu.
|
|
|
|
my $mbp = $mb->Menubutton(
|
|
-text => 'Prefs',
|
|
-underline => 0,
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
-cursor => $CURSOR,
|
|
-padx => 0,
|
|
);
|
|
my $odometers = 'Odometers';
|
|
$mbp->cascade(
|
|
-label => $odometers,
|
|
-underline => 0,
|
|
);
|
|
$mbp->separator;
|
|
$mbp->command(
|
|
-label => 'Color Editor',
|
|
-underline => 0,
|
|
-state => $COLOR_STATE,
|
|
-command => [$CREF => 'Show'],
|
|
);
|
|
my $mbpm = $mbp->cget(-menu);
|
|
my $mbpmo = $mbpm->Menu;
|
|
$mbp->entryconfigure($odometers, -menu => $mbpmo);
|
|
$mbpmo->radiobutton(
|
|
-label => 'Cursor',
|
|
-variable => \$OPT{'odometer'},
|
|
-value => 'cursor',
|
|
-command => \&which_odo,
|
|
);
|
|
$mbpmo->radiobutton(
|
|
-label => 'Pointer',
|
|
-variable => \$OPT{'odometer'},
|
|
-value => 'pointer',
|
|
-command => \&which_odo,
|
|
);
|
|
$mbpmo->radiobutton(
|
|
-label => 'Both',
|
|
-variable => \$OPT{'odometer'},
|
|
-value => 'both',
|
|
-command => \&which_odo,
|
|
);
|
|
|
|
# Units menu.
|
|
|
|
my $mbu = $mb->Menubutton(
|
|
-text => 'Units',
|
|
-underline => 0,
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
-cursor => $CURSOR,
|
|
-padx => 0,
|
|
);
|
|
foreach (@UNITS) {
|
|
my($un, @ur) = @$ARG;
|
|
$mbu->cascade(-label => $un, -underline => 0);
|
|
my $mbum = $mbu->cget(-menu);
|
|
my $m = $mbum->Menu;
|
|
$mbu->entryconfigure($un, -menu => $m);
|
|
foreach (@ur) {
|
|
my($l, $a, $v) = @$ARG;
|
|
$m->radiobutton(
|
|
-label => $l,
|
|
-variable => \$MODO_UNITS,
|
|
-value => $v,
|
|
-command => sub {$MODO_UNITS_HUMAN = $a},
|
|
);
|
|
$m->invoke($l) if $l eq $DEFAULT_UNITS; # initialize va\
|
|
riables
|
|
} # forend all radiobuttons
|
|
} # forend all units
|
|
|
|
# Help Menu.
|
|
|
|
my $mbh = $mb->Menubutton(
|
|
-text => 'Help',
|
|
-underline => 0,
|
|
-cursor => $CURSOR,
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
-padx => 0,
|
|
);
|
|
$mbh->command(
|
|
-label => 'About',
|
|
-underline => 0,
|
|
-command => [$ABOUT => 'Show'],
|
|
);
|
|
$mbh->separator;
|
|
my $usage_command = [$USAGE => 'deiconify'];
|
|
$mbh->command(
|
|
-label => 'Usage',
|
|
-underline => 0,
|
|
-command => $usage_command,
|
|
-accelerator => 'Ctrl-u',
|
|
);
|
|
$MW->bind('<Control-Key-u>' => $usage_command);
|
|
$mbh->separator;
|
|
$mbh->command(
|
|
-label => 'Verify',
|
|
-underline => 0,
|
|
-command => [$NUMBERS => 'deiconify'],
|
|
);
|
|
# Create two odometers, one for the cursor and one for the pointin\
|
|
g device.
|
|
# Create bindings to reset both trip values simultaneously.
|
|
|
|
$W_CODO = $w->Odometer(
|
|
-odometerlabel => 'Cursor',
|
|
-font => $OPT{'fontname'},
|
|
-foreground => $OPT{'foreground'},
|
|
-background => $OPT{'background'},
|
|
-cursor => $CURSOR,
|
|
);
|
|
$W_PODO = $w->Odometer(
|
|
-odometerlabel => 'Pointer',
|
|
-font => $OPT{'fontname'},
|
|
-foreground => $OPT{'foreground'},
|
|
-background => $OPT{'background'},
|
|
-cursor => $CURSOR,
|
|
);
|
|
my $b2_release_code = sub {$W_CODO->reset_trip; $W_PODO->res\
|
|
et_trip};
|
|
$W_CODO->bind('<Button2-ButtonRelease>' => $b2_release\
|
|
_code);
|
|
$W_PODO->bind('<Button2-ButtonRelease>' => $b2_release\
|
|
_code);
|
|
|
|
# Miscellaneous information.
|
|
|
|
$W_MISC_TEXT = '';
|
|
$W_MISC = $w->Label(-font => 'fixed', -textvariable => \$\
|
|
W_MISC_TEXT);
|
|
# Pack it all up. We may see one or the other odometer, or perhap\
|
|
s both.
|
|
$w->pack;
|
|
$mb->pack(qw(-side top -fill x));
|
|
$mbf->pack(qw(-side left));
|
|
$mbp->pack(qw(-side left));
|
|
$mbu->pack(qw(-side left));
|
|
$mbh->pack(qw(-side right));
|
|
$W_MISC->pack(-pady => '2m');
|
|
which_odo;
|
|
} # end build_main_window
|
|
sub build_usage_window {
|
|
# Configure the usage information window using Evaluate Parameters\
|
|
'
|
|
# -full_help and stuff the data into a scrolled read-only Text wid\
|
|
get.
|
|
|
|
update_status 'Usage Window';
|
|
|
|
$USAGE = $MW->Toplevel;
|
|
$USAGE->withdraw;
|
|
$USAGE->title('modo Usage');
|
|
$USAGE->iconname('Usage');
|
|
$USAGE->iconbitmap("\@$LIBDIR/icon.xbm");
|
|
|
|
my $mb = $USAGE->Frame(
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
)->pack(-fill => 'x');
|
|
my $mbf = $mb->Menubutton(
|
|
-text => 'File',
|
|
-underline => 0,
|
|
-cursor => $CURSOR,
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
)->pack(-side => 'left');
|
|
my $close_command = [$USAGE => 'withdraw'];
|
|
$mbf->command(
|
|
-label => 'Close',
|
|
-underline => 0,
|
|
-command => $close_command,
|
|
-accelerator => 'Ctrl-w',
|
|
);
|
|
$USAGE->bind('<Control-Key-w>' => $close_command);
|
|
|
|
my $ut = $USAGE->Scrolled(
|
|
'ROText',
|
|
qw(-wrap word -bd 1 -relief raised),
|
|
)->pack;
|
|
my $help = `$OPT{'help'} -full_help`;
|
|
$ut->insert('end', $help);
|
|
}; # end build_usage_window
|
|
sub build_verify_window {
|
|
# Create the modometer Verify window to ensure correct calibration\
|
|
.
|
|
# Some items are tagged so our special ColorEditor colorizer can
|
|
# configure canvas items.
|
|
update_status 'Verify Window';
|
|
$NUMBERS = $MW->Toplevel;
|
|
$NUMBERS->withdraw;
|
|
$NUMBERS->title('Verify modo');
|
|
$NUMBERS->iconname('Verify');
|
|
$NUMBERS->iconbitmap("\@$LIBDIR/icon.xbm");
|
|
# Create the File menu.
|
|
my $mb = $NUMBERS->Frame(qw(-bd 1 -relief raised))->pack(-fi\
|
|
ll => 'x');
|
|
my $mbf = $mb->Menubutton(
|
|
-text => 'File',
|
|
-underline => 0,
|
|
-cursor => $CURSOR,
|
|
-borderwidth => 1,
|
|
-relief => 'raised',
|
|
)->pack(-side => 'left');
|
|
my $close_command = [$NUMBERS => 'withdraw'];
|
|
$mbf->command(
|
|
-label => 'Close',
|
|
-underline => 0,
|
|
-command => $close_command,
|
|
-accelerator => 'Ctrl-w',
|
|
);
|
|
$NUMBERS->bind('<Control-Key-w>' => $close_command);
|
|
|
|
# Create a cm/in scale for modometer scaling verification.
|
|
|
|
my $nf = $NUMBERS->Frame(qw(-relief raised -bd 1))->pack;
|
|
my $nfc = $nf->Canvas(qw(-width 3.2i -height 2.25i))->pack;
|
|
my $nfm = $nf->Message(
|
|
-borderwidth => 1,
|
|
-relief => 'sunken',
|
|
-text => 'Use this data to verify that modometer is \
|
|
properly ' .
|
|
'calibrated. The X-Y axes should both be 1 in\
|
|
ch ' .
|
|
'(2.54 centimeters) in length.',
|
|
);
|
|
$nfc->create('window', 200, 50, -window => $nfm);
|
|
$nfc->create('bitmap', '2.55i', '1.75i',
|
|
-bitmap => "\@$LIBDIR/icon.xbm",
|
|
-tags => ['background', 'foreground'],
|
|
);
|
|
$nfc->create('line', 10, 10, 10, $PIXELS_IN_Y+10, $PIXELS_IN_X+\
|
|
10,
|
|
$PIXELS_IN_Y+10, -tags => 'fill');
|
|
$nfc->create('line', 10, $PIXELS_IN_Y+10-$PIXELS_CM_Y, 20,
|
|
$PIXELS_IN_Y+10-$PIXELS_CM_Y, -tags => 'fill');
|
|
$nfc->create('line', 10, $PIXELS_IN_Y+10-(2*$PIXELS_CM_Y), 20,
|
|
$PIXELS_IN_Y+10-(2*$PIXELS_CM_Y), -tags => 'fill')\
|
|
;
|
|
$nfc->create('line', $PIXELS_CM_X+10, $PIXELS_IN_Y+10, $PIXELS_\
|
|
CM_X+10,
|
|
$PIXELS_IN_Y+10-10, -tags => 'fill');
|
|
$nfc->create('line', (2*$PIXELS_CM_X)+10, $PIXELS_IN_Y+10,
|
|
(2*$PIXELS_CM_X)+10, $PIXELS_IN_Y+10-10, -tags => \
|
|
'fill');
|
|
# Create miscellaneous textual information.
|
|
my $numbers = sprintf(
|
|
" Pointer Scale Factor : %.2f\n" .
|
|
" Threshold : %d\n" .
|
|
" Acceleration : %.2f\n" .
|
|
" Pixles/inch X : %d\n" .
|
|
" Pixles/inch Y : %d",
|
|
$OPT{'pointer_scale_factor'},
|
|
$THRESHOLD,
|
|
$ACCELERATION,
|
|
$PIXELS_IN_X,
|
|
$PIXELS_IN_Y,
|
|
);
|
|
$nfc->create('text', '1.0i', '1.75i',
|
|
-text => $numbers,
|
|
-font => 'fixed',
|
|
-tags => 'fill',
|
|
);
|
|
$nfc->create('text', '0.7i', '0.55i',
|
|
-text => '2.54 cm/in',
|
|
-font => 'fixed',
|
|
-tags => 'fill',
|
|
);
|
|
|
|
} # end build_verify_window
|
|
|
|
sub initialize {
|
|
|
|
# First evaluate command line parameters and store values in the h\
|
|
ash %OPT.
|
|
# Create the main window and, unless modo is starting up iconified\
|
|
, the
|
|
# initialization status window.
|
|
|
|
use Getopt::EvaP; # Evaluate Parameters
|
|
use inied; # initialize Evaluate Parameters\
|
|
data
|
|
EvaP \@inied::PDT, \@inied::MM, \%OPT; # evaluate command line par\
|
|
ameters
|
|
|
|
$VERSION = '1.1';
|
|
$QUIT_COMMAND = sub {save_modo; exit};
|
|
$MW = MainWindow->new($OPT{'display'});
|
|
$MW->withdraw;
|
|
$MW->title($OPT{'title'});
|
|
$MW->iconname('modo');
|
|
$MW->iconbitmap("\@$LIBDIR/icon.xbm");
|
|
$MW->minsize(50, 50);
|
|
$MW->protocol('WM_DELETE_WINDOW' => $QUIT_COMMAND);
|
|
foreach (qw(foreground background)) {
|
|
no strict 'refs';
|
|
my $o = $OPT{$ARG}; # command line overrides option database
|
|
$MW->optionAdd("*${ARG}", $o) if $o ne ${"inied::def_${ARG}\
|
|
"};
|
|
}
|
|
unless ($OPT{'iconic'}) {
|
|
# Realize a transient toplevel to display modo's initializatio\
|
|
n status.
|
|
$STATUS = $MW->Toplevel;
|
|
$STATUS->positionfrom('user');
|
|
$STATUS->geometry('+100+100');
|
|
$STATUS->title('Initializing modo');
|
|
$STATUS_B = $STATUS->Label(-bitmap => "\@$LIBDIR/icon.xb\
|
|
m")->pack;
|
|
$STATUS_L = $STATUS->Label(
|
|
-text => 'Main Window ...',
|
|
-width => 25,
|
|
)->pack;
|
|
$MW->idletasks;
|
|
} # unlessend iconic
|
|
# Global objects and variables.
|
|
update_status 'Global Stuff';
|
|
# Convert microseconds to milliseconds for after();
|
|
if ($OPT{'microsecond_interval_time'} >= 1000) {
|
|
$MILLISECOND_DELAY = $OPT{'microsecond_interval_time'} / 1000;
|
|
} else {
|
|
$MILLISECOND_DELAY = 100;
|
|
}
|
|
$ABOUT = $MW->Dialog(
|
|
-title => 'About modo',
|
|
-bitmap => "\@$LIBDIR/SOL.xbm",
|
|
);
|
|
$ABOUT->configure(
|
|
-wraplength => '5i',
|
|
-text => "modometer $VERSION\n\nThe Mac Mouse Odometer, P\
|
|
erl/Tk " .
|
|
"Style\n\nStephen O. Lidie, 96/02/11\nlusol\@Lehigh\
|
|
.EDU",
|
|
);
|
|
$ACCELERATION = 2.0;
|
|
$AUTOSAVE_TICKS = $OPT{'odometer_autosave_time'} * 60 * 1000 /
|
|
$MILLISECOND_DELAY;
|
|
$AUTOSAVE_COUNT = $AUTOSAVE_TICKS;
|
|
$COLOR_STATE = $MW->depth > 1 ? 'normal' : 'disabled';
|
|
$CREF = $MW->ColorEditor(-title => 'modo') if $COLOR_STATE e\
|
|
q 'normal';
|
|
$CURSOR = ["\@$LIBDIR/mouse.xbm", "$LIBDIR/mouse.mask", 'Black', '\
|
|
White'];
|
|
$DEFAULT_UNITS = 'kilometers';
|
|
($LAST_X, $LAST_Y) = $MW->pointerxy;
|
|
$MM_PIXEL_X = $OPT{'display_width_millimeters'} /
|
|
$OPT{'display_width_pixels'};
|
|
$MM_PIXEL_Y = $OPT{'display_height_millimeters'} /
|
|
$OPT{'display_height_pixels'};
|
|
$PIXELS_IN_X = int((25.4 / $MM_PIXEL_X) + 0.5);
|
|
$PIXELS_IN_Y = int((25.4 / $MM_PIXEL_Y) + 0.5);
|
|
$PIXELS_CM_X = int((10.0 / $MM_PIXEL_X) + 0.5);
|
|
$PIXELS_CM_Y = int((10.0 / $MM_PIXEL_Y) + 0.5);
|
|
$SIG{'INT'} = $QUIT_COMMAND;
|
|
$THRESHOLD = 4.0;
|
|
@UNITS = (
|
|
['Metric',
|
|
[qw(millimeters mm), 1.],
|
|
[qw(centimeters cm), 0.1],
|
|
[qw(decimeters dm), 0.01],
|
|
[qw(meters m), 0.001],
|
|
[qw(dekameters dam), 0.0001],
|
|
[qw(hectometers hm), 0.00001],
|
|
[qw(kilometers km), 0.000001],
|
|
[qw(myriameters mym), 0.0000001],
|
|
],
|
|
['English',
|
|
[qw(inches in), 0.1/2.54],
|
|
[qw(feet ft), 0.1/2.54/12.0],
|
|
[qw(yards yd), 0.1/2.54/12.0/3.0],
|
|
[qw(fathoms fm), 0.1/2.54/12.0/6.0],
|
|
[qw(rods rd), 0.1/2.54/12.0/3.0/6.0],
|
|
[qw(furlongs fl), 0.1/2.54/12.0/3.0/220.0],
|
|
[qw(miles mi), 0.1/2.54/12.0/3.0/1760.0],
|
|
],
|
|
['Other',
|
|
['light-nanoseconds', 'lns', 0.001/299792458.0*1.0E+9],
|
|
['nautical miles', 'nm', 0.001/1852.0],
|
|
['marine leagues', 'mlg', 0.001/1852.0/3.0],
|
|
],
|
|
); # end UNITS
|
|
|
|
# See if xset is around so we can get true pointer control informa\
|
|
tion.
|
|
|
|
update_status 'Pointer Control Information';
|
|
|
|
my ($xset, $a, $t);
|
|
if (($xset) = grep /acceleration:/, `xset -q`) {
|
|
$xset =~ s/\d+\s+=//;
|
|
if (($a, $t) = $xset =~ /acceleration:\s+(.*)\s+threshold:\s+(\
|
|
.*)$/) {
|
|
$ACCELERATION = eval $a;
|
|
$THRESHOLD = eval $t;
|
|
}
|
|
}
|
|
# Build widgets.
|
|
build_verify_window;
|
|
build_usage_window;
|
|
build_main_window;
|
|
# Initialize odometers from modo state file.
|
|
update_status 'State Information';
|
|
$SIG{'INT'} = $QUIT_COMMAND;
|
|
my ($tc, $tp) = (0.0, 0.0);
|
|
my $o = $OPT{'odometer_file'};
|
|
if (-s $o and -r $o) {
|
|
open MODO, "<$o";
|
|
($tc, $tp, $MODO_UNITS_HUMAN, $MODO_UNITS) = split ' ', <MO\
|
|
DO>;
|
|
close MODO;
|
|
}
|
|
$W_CODO->add($tc, $MODO_UNITS); $W_CODO->reset_trip;
|
|
$W_PODO->add($tp, $MODO_UNITS); $W_PODO->reset_trip;
|
|
$MW->geometry($OPT{'geometry'}) if $OPT{'geometry'} ne $inied::\
|
|
def_geometry;
|
|
if ($COLOR_STATE eq 'normal') {
|
|
# Establish the list of widgets for the ColorEditor to coloriz\
|
|
e,
|
|
# excluding ColorEditor itself and the Odometers' descendants.
|
|
#
|
|
# A special colorizing procedure is required for canvas items.
|
|
#
|
|
# See if background/foreground command line options were speci\
|
|
fied and
|
|
# use them to initialize modo's colors.
|
|
$CREF->configure(
|
|
-widgets => [$MW, $MW->Descendants],
|
|
-command => [\&set_modo_colors, $CREF],
|
|
-cursor => $CURSOR,
|
|
);
|
|
$CREF->delete_widgets(
|
|
[$CREF, # ColorEditor ...
|
|
$CREF->Descendants, # ... and all its descendant wid\
|
|
gets
|
|
$W_CODO->Descendants, # Odometer descendants because .\
|
|
..
|
|
$W_PODO->Descendants, # the class handles configuratio\
|
|
n changes
|
|
]
|
|
);
|
|
|
|
foreach ([qw(foreground Foreground)], [qw(background Backgroun\
|
|
d)]) {
|
|
my $color = $MW->optionGet($ARG->[0], $ARG->[1]);
|
|
set_modo_colors($CREF, $ARG->[0], $color) if defined $c\
|
|
olor;
|
|
}
|
|
} # ifend color
|
|
|
|
if ($OPT{'iconic'}) {
|
|
$MW->iconify;
|
|
} else {
|
|
$CREF->delete_widgets([$STATUS, $STATUS->Descendants]);
|
|
$STATUS->destroy;
|
|
$MW->update;
|
|
$MW->deiconify;
|
|
}
|
|
} # end initialize
|
|
sub modo {
|
|
# Track the cursor forever, updating the odometer file every so of\
|
|
ten.
|
|
my($x, $y) = $MW->pointerxy;
|
|
$W_MISC_TEXT = sprintf("U=%-3s (%4d,%4d)", $MODO_UNITS_HUMAN, $x, \
|
|
$y);
|
|
my($dx, $dy) = (abs($x - $LAST_X), abs($y - $LAST_Y));
|
|
($LAST_X, $LAST_Y) = ($x, $y);
|
|
my($dxmm, $dymm) = ($dx * $MM_PIXEL_X, $dy * $MM_PIXEL_Y);
|
|
my $d = sqrt( ($dxmm * $dxmm) + ($dymm * $dymm) );
|
|
if ($d > 0) {
|
|
$W_CODO->add($d, $MODO_UNITS);
|
|
if ($dx > $THRESHOLD || $dy > $THRESHOLD) {
|
|
$d /= $ACCELERATION;
|
|
}
|
|
$d /= $OPT{'pointer_scale_factor'};
|
|
$W_PODO->add($d, $MODO_UNITS);
|
|
}
|
|
|
|
if ($AUTOSAVE_COUNT-- <= 0) {
|
|
$AUTOSAVE_COUNT = $AUTOSAVE_TICKS;
|
|
eval {save_modo};
|
|
}
|
|
$MW->after($MILLISECOND_DELAY, \&modo);
|
|
} # end modo
|
|
sub save_modo {
|
|
# Update modometer state file.
|
|
open(MODO, ">$OPT{'odometer_file'}") or die "Cannot open: $OS_\
|
|
ERROR";
|
|
printf MODO "%f %f %s %s\n", $W_CODO->get_total_distance,
|
|
$W_PODO->get_total_distance,
|
|
$MODO_UNITS_HUMAN,
|
|
$MODO_UNITS;
|
|
close MODO;
|
|
|
|
} # end save_modo
|
|
|
|
sub set_modo_colors {
|
|
|
|
# Configure all the widgets in $widgets for attribute $type and co\
|
|
lor
|
|
# $color. If $color is undef then reset all colors to the Tk defa\
|
|
ults.
|
|
#
|
|
# This is a special modometer version of the released ColorEditor \
|
|
color
|
|
# configurator to handle coloring Canvas items.
|
|
|
|
my($objref, $type, $color) = @ARG;
|
|
|
|
my $display = $objref->cget('-display_status');
|
|
|
|
$objref->{'Status'}->title("Configure $type");
|
|
$objref->{'Status'}->deiconify if $display;
|
|
my $w;
|
|
my $reset = not defined($color);
|
|
foreach $w (@{$objref->cget('-widgets')}) {
|
|
if ($display) {
|
|
$objref->{'Status_l'}->configure(
|
|
-text => "WIDGET: " . $w->PathName
|
|
);
|
|
$objref->update;
|
|
}
|
|
if ($w->class eq 'Canvas') {
|
|
eval {$w->configure("-\L${type}" => $color)};
|
|
my $tag;
|
|
if ($type eq 'background') {
|
|
foreach $tag ($w->find('withtag', 'background')) {
|
|
eval {$color = ($w->configure("-\L${type}"))[3]\
|
|
} if $reset;
|
|
$w->itemconfigure($tag, -background => $colo\
|
|
r);
|
|
}
|
|
} elsif ($type eq 'foreground') {
|
|
foreach $tag ($w->find('withtag', 'foreground')) {
|
|
eval {$color = ($w->configure("-\L${type}"))[3]\
|
|
} if $reset;
|
|
$w->itemconfigure($tag, -foreground => $colo\
|
|
r);
|
|
}
|
|
foreach $tag ($w->find('withtag', 'fill')) {
|
|
eval {$color = ($w->configure("-\L${type}"))[3]\
|
|
} if $reset;
|
|
$w->itemconfigure($tag, -fill => $color);
|
|
}
|
|
}
|
|
} else {
|
|
eval {$color = ($w->configure("-\L${type}"))[3]} if $re\
|
|
set;
|
|
eval {$w->configure("-\L${type}" => $color)};
|
|
}
|
|
} # forend all widgets
|
|
|
|
$objref->{'Status'}->withdraw if $display;
|
|
|
|
} # end set_modo_colors
|
|
|
|
sub update_status {
|
|
|
|
my($state_text) = @ARG;
|
|
|
|
unless ($OPT{'iconic'}) {
|
|
$STATUS_L->configure(-text => "$state_text ...");
|
|
$MW->idletasks;
|
|
}
|
|
} # end update_status
|
|
sub which_odo {
|
|
$W_CODO->packForget;
|
|
$W_PODO->packForget;
|
|
|
|
if ($OPT{'odometer'} eq 'cursor') {
|
|
$W_CODO->pack(-before => $W_MISC);
|
|
} elsif ($OPT{'odometer'} eq 'pointer') {
|
|
$W_PODO->pack(-before => $W_MISC);
|
|
} else {
|
|
$W_CODO->pack(-before => $W_MISC);
|
|
$W_PODO->pack(-before => $W_MISC);
|
|
}
|
|
|
|
} # end which_odo
|