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; |