| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Tk::Dial; |
|
2
|
1
|
|
|
1
|
|
715
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
44
|
|
|
3
|
|
|
|
|
|
|
require Tk::Frame; |
|
4
|
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use vars qw($VERSION @ISA); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1097
|
|
|
6
|
|
|
|
|
|
|
$VERSION = substr(q$Revision: 1.5 $, 10) + 1; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
@ISA = qw(Tk::Derived Tk::Frame); |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
my $pi = atan2(1, 1) * 4; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Construct Tk::Widget 'Dial'; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 NAME |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Tk::Dial - An alternative to the Scale widget |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=for category Derived Widgets |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
use Tk::Dial; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
$dial = $widget->Dial(-margin => 20, |
|
25
|
|
|
|
|
|
|
-radius => 48, |
|
26
|
|
|
|
|
|
|
-min => 0, |
|
27
|
|
|
|
|
|
|
-max => 100, |
|
28
|
|
|
|
|
|
|
-value => 0, |
|
29
|
|
|
|
|
|
|
-format => '%d'); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
margin - blank space to leave around dial |
|
33
|
|
|
|
|
|
|
radius - radius of dial |
|
34
|
|
|
|
|
|
|
min, max - range of possible values |
|
35
|
|
|
|
|
|
|
value - current value |
|
36
|
|
|
|
|
|
|
format - printf-style format for displaying format |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
Values shown above are defaults. |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
A dial looks like a speedometer: a 3/4 circle with a needle indicating |
|
44
|
|
|
|
|
|
|
the current value. Below the graphical dial is an entry that displays |
|
45
|
|
|
|
|
|
|
the current value, and which can be used to enter a value by hand. |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
The needle is moved by pressing button 1 in the canvas and dragging. The |
|
48
|
|
|
|
|
|
|
needle will follow the mouse, even if the mouse leaves the canvas, which |
|
49
|
|
|
|
|
|
|
allows for high precision. Alternatively, the user can enter a value in |
|
50
|
|
|
|
|
|
|
the entry space and press Return to set the value; the needle will be |
|
51
|
|
|
|
|
|
|
set accordingly. |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head1 TO DO |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Configure |
|
56
|
|
|
|
|
|
|
Tick marks |
|
57
|
|
|
|
|
|
|
Step size |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=head1 AUTHORS |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Roy Johnson |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Based on a similar widget in XV, a program by |
|
64
|
|
|
|
|
|
|
John Bradley |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head1 HISTORY |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
August 1995: Released for critique by pTk mailing list |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=cut |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my @flags = qw(-margin -radius -min -max -value -format); |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub Populate |
|
76
|
|
|
|
|
|
|
{ |
|
77
|
0
|
|
|
0
|
|
|
my ($w, $args) = @_; |
|
78
|
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
@$w{@flags} = (20, 48, (0, 100), 0, '%d'); |
|
80
|
0
|
|
|
|
|
|
my $key; |
|
81
|
0
|
|
|
|
|
|
for $key (@flags) { |
|
82
|
0
|
|
|
|
|
|
my $val = delete $args->{$key}; |
|
83
|
0
|
0
|
|
|
|
|
if (defined $val) { |
|
84
|
0
|
|
|
|
|
|
$$w{$key} = $val; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Pass other args on to Frame |
|
89
|
0
|
|
|
|
|
|
$w->SUPER::Populate($args); |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Convenience variables, based on flag settings |
|
92
|
0
|
|
|
|
|
|
my ($margin, $radius, $min, $max, $format) = @$w{@flags}; |
|
93
|
0
|
|
|
|
|
|
my ($center_x, $center_y) = ($margin + $radius) x 2; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# Create Widgets |
|
96
|
0
|
|
|
|
|
|
my $c = $w->Canvas(-width => 2 * ($radius + $margin), |
|
97
|
|
|
|
|
|
|
-height => 1.75 * $radius + $margin); |
|
98
|
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
$c->create('arc', |
|
100
|
|
|
|
|
|
|
($center_x - $radius, $center_y - $radius), |
|
101
|
|
|
|
|
|
|
($center_x + $radius, $center_y + $radius), |
|
102
|
|
|
|
|
|
|
-start => -45, -extent => 270, -style => 'chord', |
|
103
|
|
|
|
|
|
|
-width => 2); |
|
104
|
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
|
$c->pack(-expand => 1, -fill => 'both'); |
|
106
|
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
$w->bind($c, '<1>' => \&drawPointer); |
|
108
|
0
|
|
|
|
|
|
$w->bind($c, '' => \&drawPointer); |
|
109
|
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
|
my $e = $w->Entry(-textvariable => \$w->{-value}); |
|
111
|
0
|
|
|
|
|
|
$e->pack(); |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
0
|
|
|
$w->bind($e, '' => sub { &setvalue($c) }); |
|
|
0
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
&setvalue($c); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
#------------------------------ |
|
118
|
|
|
|
|
|
|
sub drawPointer |
|
119
|
|
|
|
|
|
|
{ |
|
120
|
0
|
|
|
0
|
|
|
my $c = shift; |
|
121
|
0
|
|
|
|
|
|
my $w = $c->parent; |
|
122
|
0
|
|
|
|
|
|
my $e = $c->XEvent; |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Convenience variables, based on flag settings |
|
125
|
0
|
|
|
|
|
|
my ($margin, $radius, $min, $max, $value, $format) = @$w{@flags}; |
|
126
|
0
|
|
|
|
|
|
my ($center_x, $center_y) = ($margin + $radius) x 2; |
|
127
|
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
|
my ($delta_x, $delta_y) = ($e->x - $center_x, $e->y - $center_y); |
|
129
|
0
|
|
|
|
|
|
my $distance = sqrt($delta_x**2 + $delta_y**2); |
|
130
|
0
|
0
|
|
|
|
|
return if ($distance < 1); |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# atan2/pi returns the angle in pi-radians, but out-of-phase; |
|
133
|
|
|
|
|
|
|
# here we correct it to be 0 at the start of the arc |
|
134
|
0
|
|
|
|
|
|
my $angle = atan2($delta_y, $delta_x) / $pi + 1.25; |
|
135
|
0
|
0
|
|
|
|
|
if ($angle > 2) { $angle -= 2 } |
|
|
0
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
|
|
137
|
0
|
0
|
|
|
|
|
if ($angle < 1.5) { |
|
|
|
0
|
|
|
|
|
|
|
138
|
0
|
|
|
|
|
|
my $factor = $radius/$distance; |
|
139
|
0
|
|
|
|
|
|
my $newx = $center_x + int($factor * $delta_x); |
|
140
|
0
|
|
|
|
|
|
my $newy = $center_y + int($factor * $delta_y); |
|
141
|
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
$c->delete('oldpointer'); |
|
143
|
0
|
|
|
|
|
|
$c->create('line', ($newx, $newy, $center_x, $center_y), |
|
144
|
|
|
|
|
|
|
-arrow => 'first', -tags => 'oldpointer', |
|
145
|
|
|
|
|
|
|
-width => 2); |
|
146
|
|
|
|
|
|
|
|
|
147
|
0
|
|
|
|
|
|
$w->{-value} = sprintf($format, |
|
148
|
|
|
|
|
|
|
$angle / 1.5 * ($max - $min) + $min); |
|
149
|
|
|
|
|
|
|
} elsif ($angle < 1.75) { |
|
150
|
0
|
0
|
|
|
|
|
if ($w->{-value} < $max) { |
|
151
|
0
|
|
|
|
|
|
&setvalue($c); |
|
152
|
0
|
|
|
|
|
|
$w->{-value} = $max; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
} else { |
|
155
|
0
|
0
|
|
|
|
|
if ($w->{-value} > $min) { |
|
156
|
0
|
|
|
|
|
|
&setvalue($c); |
|
157
|
0
|
|
|
|
|
|
$w->{-value} = $min; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
#------------------------------ |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub setvalue { |
|
166
|
0
|
|
|
0
|
|
|
my $c = shift; |
|
167
|
0
|
|
|
|
|
|
my $w = $c->parent; |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
my $value = $w->{-value}; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# Convenience variables, based on flag settings |
|
172
|
0
|
|
|
|
|
|
my ($margin, $radius, $min, $max, $dummy, $format) = @$w{@flags}; |
|
173
|
0
|
|
|
|
|
|
my ($center_x, $center_y) = ($margin + $radius) x 2; |
|
174
|
|
|
|
|
|
|
|
|
175
|
0
|
0
|
|
|
|
|
if ($value > $max) { |
|
|
|
0
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
|
$value = $max; |
|
177
|
|
|
|
|
|
|
} elsif ($value < $min) { |
|
178
|
0
|
|
|
|
|
|
$value = $min; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
$w->{-value} = sprintf($format, $value); |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# value = (angle / 1.5) * (max-min) + min |
|
184
|
|
|
|
|
|
|
# Solving backwards... |
|
185
|
|
|
|
|
|
|
# value - min = angle / 1.5 * (max-min) |
|
186
|
|
|
|
|
|
|
# (value - min) * 1.5 / (max-min) = angle |
|
187
|
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
my $angle = ($value - $min) * 1.5 / ($max - $min); |
|
189
|
0
|
|
|
|
|
|
$angle -= 1.25; |
|
190
|
0
|
|
|
|
|
|
$angle *= $pi; |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Now just figure out X and Y where atan2 == $angle |
|
193
|
0
|
|
|
|
|
|
my($x, $y) = (cos($angle) * $radius, sin($angle) * $radius); |
|
194
|
0
|
|
|
|
|
|
$x += $center_x; |
|
195
|
0
|
|
|
|
|
|
$y += $center_y; |
|
196
|
0
|
|
|
|
|
|
$c->delete('oldpointer'); |
|
197
|
0
|
|
|
|
|
|
$c->create('line', ($x, $y, $center_x, $center_y), |
|
198
|
|
|
|
|
|
|
-arrow => 'first', -tags => 'oldpointer', |
|
199
|
|
|
|
|
|
|
-width => 2); |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
1; |