line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CAD::Drawing::IO::Tk; |
2
|
|
|
|
|
|
|
our $VERSION = '0.04'; |
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
22448
|
use CAD::Drawing; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
use CAD::Drawing::Defined; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use CAD::Calc qw(dist2d); |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# with the new plug-in architecture, this seems odd to have a |
10
|
|
|
|
|
|
|
# strictly-inherited module in the IO::* namespace (when this thing |
11
|
|
|
|
|
|
|
# finally grows-up, maybe we use a GUI::* namespace?) |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $is_inherited = 1; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use vars qw( |
17
|
|
|
|
|
|
|
%dsp |
18
|
|
|
|
|
|
|
$textsize |
19
|
|
|
|
|
|
|
$text_base |
20
|
|
|
|
|
|
|
); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$text_base = 8; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use warnings; |
25
|
|
|
|
|
|
|
use strict; |
26
|
|
|
|
|
|
|
use Carp; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my %default = ( |
29
|
|
|
|
|
|
|
width => 800, |
30
|
|
|
|
|
|
|
height => 600, |
31
|
|
|
|
|
|
|
zoom => "fit", |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=pod |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 NAME |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
CAD::Drawing::IO::Tk - GUI I/O methods for CAD::Drawing |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 NOTICE |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
This module is considered extremely pre-ALPHA and its use is probably |
43
|
|
|
|
|
|
|
deprecated by the time you read this. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head1 AUTHOR |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Eric L. Wilhelm |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
http://scratchcomputing.com |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head1 COPYRIGHT |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
This module is copyright (C) 2004-2006 by Eric L. Wilhelm. Portions |
54
|
|
|
|
|
|
|
copyright (C) 2003 by Eric L. Wilhelm and A. Zahner Co. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 LICENSE |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
This module is distributed under the same terms as Perl. See the Perl |
59
|
|
|
|
|
|
|
source package for details. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
You may use this software under one of the following licenses: |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
(1) GNU General Public License |
64
|
|
|
|
|
|
|
(found at http://www.gnu.org/copyleft/gpl.html) |
65
|
|
|
|
|
|
|
(2) Artistic License |
66
|
|
|
|
|
|
|
(found at http://www.perl.com/pub/language/misc/Artistic.html) |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head1 NO WARRANTY |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
This software is distributed with ABSOLUTELY NO WARRANTY. The author, |
71
|
|
|
|
|
|
|
his former employer, and any other contributors will in no way be held |
72
|
|
|
|
|
|
|
liable for any loss or damages resulting from its use. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 Modifications |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
The source code of this module is made freely available and |
77
|
|
|
|
|
|
|
distributable under the GPL or Artistic License. Modifications to and |
78
|
|
|
|
|
|
|
use of this software must adhere to one of these licenses. Changes to |
79
|
|
|
|
|
|
|
the code should be noted as such and this notification (as well as the |
80
|
|
|
|
|
|
|
above copyright information) must remain intact on all copies of the |
81
|
|
|
|
|
|
|
code. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Additionally, while the author is actively developing this code, |
84
|
|
|
|
|
|
|
notification of any intended changes or extensions would be most helpful |
85
|
|
|
|
|
|
|
in avoiding repeated work for all parties involved. Please contact the |
86
|
|
|
|
|
|
|
author with any such development plans. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head1 SEE ALSO |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
CAD::Drawing::IO |
91
|
|
|
|
|
|
|
Tk |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=cut |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 Methods |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
There is no constructor for this class, its methods are inherited via |
98
|
|
|
|
|
|
|
CAD::Drawing::IO |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head1 Thoughts |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Need to re-structure the entire deal to have its own object which |
103
|
|
|
|
|
|
|
belongs to the drawing object (or does the drawing object belong to this |
104
|
|
|
|
|
|
|
object?) Either way, we need to be able to build-up into interactive |
105
|
|
|
|
|
|
|
commands (possibly using eval("\$drw->$command"); ?) |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Ultimately, the focus here will likely drift toward supporting perlcad |
108
|
|
|
|
|
|
|
and enabling use of perlcad from within CAD::Drawing scripts. However, |
109
|
|
|
|
|
|
|
the nature of lights-out scripting vs the nature of on-screen drafting |
110
|
|
|
|
|
|
|
is quite different, so there will be some tricks involved. Once each |
111
|
|
|
|
|
|
|
entity has its own class, the ability to install callbacks and the |
112
|
|
|
|
|
|
|
resolution of notifications should get easier. But, there will still |
113
|
|
|
|
|
|
|
be the issue that a debug popup does not know it will appear when the |
114
|
|
|
|
|
|
|
entities are created, while a drafting viewport does (or does it?) |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
Possibly, adding a list of tk-id's to each $obj as it is drawn would be |
117
|
|
|
|
|
|
|
a good starting point, but this gets us into trouble with multiple |
118
|
|
|
|
|
|
|
viewports. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=cut |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head2 show |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Creates a new window (no options are required.) |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
$drw->show(%options); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=over |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item Available Options |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
forkokay => bool -- Attempt to fork the new window |
133
|
|
|
|
|
|
|
window => MainWindow -- Use the pre-existing Tk object |
134
|
|
|
|
|
|
|
stl => Message -- Use pre-existing Message widget |
135
|
|
|
|
|
|
|
size => [W,H] -- Specify window size in pixels |
136
|
|
|
|
|
|
|
width => W -- alias to size |
137
|
|
|
|
|
|
|
height => H -- ditto |
138
|
|
|
|
|
|
|
center => [X,Y] -- Center the drawing at (X,Y) |
139
|
|
|
|
|
|
|
scale => factor -- Zoom by factor (default to fit) |
140
|
|
|
|
|
|
|
bgcolor => color -- defaults to "white" |
141
|
|
|
|
|
|
|
hang => boolean -- if not, you just get the canvas widget |
142
|
|
|
|
|
|
|
items => \@list -- sorry, not compatible with select_addr :( |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=back |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=cut |
147
|
|
|
|
|
|
|
sub show { |
148
|
|
|
|
|
|
|
my $self = shift; |
149
|
|
|
|
|
|
|
my %options = @_; |
150
|
|
|
|
|
|
|
# XXX cannot do "use" or we get silly _TK_EXIT_(0) from everywhere! |
151
|
|
|
|
|
|
|
require Tk; |
152
|
|
|
|
|
|
|
require Tk::WorldCanvas; |
153
|
|
|
|
|
|
|
my $kidpid; |
154
|
|
|
|
|
|
|
if($options{forkokay}) { |
155
|
|
|
|
|
|
|
$SIG{CHILD} = 'IGNORE'; |
156
|
|
|
|
|
|
|
if($kidpid = fork()) { |
157
|
|
|
|
|
|
|
return($kidpid); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
defined($kidpid) or croak("cannot fork $!\n"); |
160
|
|
|
|
|
|
|
$options{forkokay} = 0; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
my $mw = $options{window}; |
163
|
|
|
|
|
|
|
defined($mw) || ($mw = MainWindow->new()); |
164
|
|
|
|
|
|
|
unless($options{size}) { |
165
|
|
|
|
|
|
|
foreach my $item ("width", "height") { |
166
|
|
|
|
|
|
|
my $val = $options{$item}; |
167
|
|
|
|
|
|
|
$val || ($val = $default{$item}); |
168
|
|
|
|
|
|
|
push(@{$options{size}}, $val); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
$options{bgcolor} || ($options{bgcolor} = "white"); |
172
|
|
|
|
|
|
|
# FIXME: should have an indication of viewport number? |
173
|
|
|
|
|
|
|
$options{title} || ($options{title} = "Drawing"); |
174
|
|
|
|
|
|
|
$mw->title($options{title}); |
175
|
|
|
|
|
|
|
my ($w,$h) = @{$options{size}}; |
176
|
|
|
|
|
|
|
# print "requesting $w x $h\n"; |
177
|
|
|
|
|
|
|
my $cnv = $mw->WorldCanvas( |
178
|
|
|
|
|
|
|
'-bg' => $options{bgcolor}, |
179
|
|
|
|
|
|
|
'-width' => $options{size}[0], |
180
|
|
|
|
|
|
|
'-height' => $options{size}[1], |
181
|
|
|
|
|
|
|
); |
182
|
|
|
|
|
|
|
# XXX scrolling when you want to wheelzoom is icky. What's up with |
183
|
|
|
|
|
|
|
# that? (Tk::Canvas is a mess, that's what!) |
184
|
|
|
|
|
|
|
## print "bound to ", $cnv->bind('<4>'), "\n"; |
185
|
|
|
|
|
|
|
$cnv->pack(-fill => 'both', -expand=>1); |
186
|
|
|
|
|
|
|
# XXX break this out into pieces |
187
|
|
|
|
|
|
|
my $stl; |
188
|
|
|
|
|
|
|
my %stl_conf = ( |
189
|
|
|
|
|
|
|
-anchor => "sw", |
190
|
|
|
|
|
|
|
-width => $w, |
191
|
|
|
|
|
|
|
-justify=>"left", |
192
|
|
|
|
|
|
|
); |
193
|
|
|
|
|
|
|
my %stl_pack = (-fill => 'x', -expand=>0, -side => "bottom"); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
unless($stl = $options{stl}) { |
196
|
|
|
|
|
|
|
$stl = $mw->Message(%stl_conf); |
197
|
|
|
|
|
|
|
$stl->pack(%stl_pack); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
else { |
200
|
|
|
|
|
|
|
$stl->configure(%stl_conf); |
201
|
|
|
|
|
|
|
$stl->pack(%stl_pack); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
# FIXME: cannot just have a simplistic command line, it has to be powerful |
204
|
|
|
|
|
|
|
# my $cmd = $mw->Text( |
205
|
|
|
|
|
|
|
# -height=> 2, |
206
|
|
|
|
|
|
|
# -width => $w, |
207
|
|
|
|
|
|
|
# ); |
208
|
|
|
|
|
|
|
# $cmd->pack(-fill => 'x', -expand=>0, -side => "bottom"); |
209
|
|
|
|
|
|
|
# XXX $self here is a drawing, maybe that's not what we want... |
210
|
|
|
|
|
|
|
$self->tkbindings($mw, $cnv, $stl); |
211
|
|
|
|
|
|
|
$options{items} || ($options{items} = $self->select_addr({all=>1})); |
212
|
|
|
|
|
|
|
$self->Draw($cnv, %options); |
213
|
|
|
|
|
|
|
$cnv->viewAll(); |
214
|
|
|
|
|
|
|
text_size_reset($cnv); |
215
|
|
|
|
|
|
|
if(defined($kidpid) or $options{hang}) { |
216
|
|
|
|
|
|
|
$mw->MainLoop; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
else { |
219
|
|
|
|
|
|
|
return($cnv); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
} # end subroutine show definition |
222
|
|
|
|
|
|
|
######################################################################## |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head2 Draw |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
Draws geometry on the Tk canvas $cnv. List of items to draw must be |
227
|
|
|
|
|
|
|
specified via addresses stored in $options{items}. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
The newest fad (:e) is the $options{tag} argument, which uses |
230
|
|
|
|
|
|
|
addr_to_tktag() to tag the item. |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
$drw->Draw($cnv, %options); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=cut |
235
|
|
|
|
|
|
|
sub Draw { |
236
|
|
|
|
|
|
|
my $self = shift; |
237
|
|
|
|
|
|
|
my $cnv = shift; |
238
|
|
|
|
|
|
|
my %options = @_; |
239
|
|
|
|
|
|
|
my @list = @{$options{items}}; |
240
|
|
|
|
|
|
|
foreach my $item (@list) { |
241
|
|
|
|
|
|
|
my $type = $item->{type}; |
242
|
|
|
|
|
|
|
# print "item: $type\n"; |
243
|
|
|
|
|
|
|
if($dsp{$type}) { |
244
|
|
|
|
|
|
|
my @tk_ids = $dsp{$type}->($self, $cnv, $item); |
245
|
|
|
|
|
|
|
if($options{tag}) { |
246
|
|
|
|
|
|
|
foreach my $tk_id (@tk_ids) { |
247
|
|
|
|
|
|
|
my $tagstring = $self->addr_to_tktag($item); |
248
|
|
|
|
|
|
|
$cnv->itemconfigure($tk_id, -tags => $tagstring); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
else { |
253
|
|
|
|
|
|
|
carp "no function for $type\n"; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
} # end subroutine Draw definition |
258
|
|
|
|
|
|
|
######################################################################## |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head2 tkbindings |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Setup the keybindings. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
$drw->tkbindings($mw, $cnv); |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=cut |
267
|
|
|
|
|
|
|
sub tkbindings { |
268
|
|
|
|
|
|
|
my $self = shift; |
269
|
|
|
|
|
|
|
my ($mw, $cnv, $stl) = @_; |
270
|
|
|
|
|
|
|
# FIXME: this should be much more robust |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# maybe a vim-style modal binding? or possibly a command-line based |
273
|
|
|
|
|
|
|
# system. |
274
|
|
|
|
|
|
|
# just bind ":" to switch to the command bindings and to go back |
275
|
|
|
|
|
|
|
# to visual mode (and the end of every command must go to visual mode.) |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# this one basically means 'focusFollowsMouse', which is evil. |
278
|
|
|
|
|
|
|
# $mw->bind('' => sub{ $cnv->Tk::focus}); |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# $mw->bind('' => sub{$mw->destroy}); |
281
|
|
|
|
|
|
|
# $cnv->CanvasBind('' => sub{print "called\n";exit;}); |
282
|
|
|
|
|
|
|
$mw->bind('' => sub {$mw->destroy}); |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# XXX move this... |
285
|
|
|
|
|
|
|
# middle-button pan: |
286
|
|
|
|
|
|
|
my @pan_start; |
287
|
|
|
|
|
|
|
my $drag_current; |
288
|
|
|
|
|
|
|
$cnv->CanvasBind( |
289
|
|
|
|
|
|
|
'' => sub { |
290
|
|
|
|
|
|
|
@pan_start = $cnv->eventLocation(); |
291
|
|
|
|
|
|
|
# print "starting pan at @pan_start\n"; |
292
|
|
|
|
|
|
|
}); |
293
|
|
|
|
|
|
|
# have to have this here to prevent spurious panning with double-clicks |
294
|
|
|
|
|
|
|
$cnv->CanvasBind('' => sub {$drag_current = 1}); |
295
|
|
|
|
|
|
|
$cnv->CanvasBind( |
296
|
|
|
|
|
|
|
'' => sub { |
297
|
|
|
|
|
|
|
$drag_current || return(); |
298
|
|
|
|
|
|
|
my @pan_stop = $cnv->eventLocation(); |
299
|
|
|
|
|
|
|
my $scale = $cnv->pixelSize(); |
300
|
|
|
|
|
|
|
# print "\tdouble: $isdouble\n"; |
301
|
|
|
|
|
|
|
# print "\tdrag: $drag_current\n"; |
302
|
|
|
|
|
|
|
# print "scale is $scale\n"; |
303
|
|
|
|
|
|
|
# print "stopping pan at @pan_stop\n"; |
304
|
|
|
|
|
|
|
my @diff = map({$pan_start[$_] - $pan_stop[$_]} 0,1); |
305
|
|
|
|
|
|
|
# my $panx = abs($diff[0])/$scale; |
306
|
|
|
|
|
|
|
# my $pany = abs($diff[1])/$scale; |
307
|
|
|
|
|
|
|
# print "pixels: ($panx,$pany)\n"; |
308
|
|
|
|
|
|
|
# my $dopan = ( $panx > 10) | ( $pany > 10); |
309
|
|
|
|
|
|
|
# $dopan && print "panning by @diff\n"; |
310
|
|
|
|
|
|
|
# $dopan && $cnv->panWorld(@diff); |
311
|
|
|
|
|
|
|
$cnv->panWorld(@diff); |
312
|
|
|
|
|
|
|
$drag_current = 0; |
313
|
|
|
|
|
|
|
}); |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# OKAY, so we've got 4 zoom actions and we don't get text or images |
316
|
|
|
|
|
|
|
# for free. |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# this takes away all of our fun of having sizable texts (hmm. I |
319
|
|
|
|
|
|
|
# guess we could create this font from anywhere?) |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# XXX this is going to have some odd behaviour for now, but it isn't |
322
|
|
|
|
|
|
|
# worth trying to make a word-processor widget behave like scalable |
323
|
|
|
|
|
|
|
# text. |
324
|
|
|
|
|
|
|
$textsize = $text_base; |
325
|
|
|
|
|
|
|
$cnv->fontCreate( |
326
|
|
|
|
|
|
|
'cad-drawing-font', |
327
|
|
|
|
|
|
|
-family => 'lucidasans', |
328
|
|
|
|
|
|
|
-size => $textsize, |
329
|
|
|
|
|
|
|
); |
330
|
|
|
|
|
|
|
text_size_reset($cnv); |
331
|
|
|
|
|
|
|
# print "view is @coords\n"; |
332
|
|
|
|
|
|
|
# print "other configs:\n", |
333
|
|
|
|
|
|
|
# join("\n", map({join(" ", @$_ )} $cnv->configure())), "\n"; |
334
|
|
|
|
|
|
|
# print "width is: ", $cnv->cget(-width), "\n"; |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# mouse-wheel zooming: |
337
|
|
|
|
|
|
|
$cnv->CanvasBind('' => sub{ |
338
|
|
|
|
|
|
|
$cnv->zoom(1.125); |
339
|
|
|
|
|
|
|
text_size_reset($cnv); |
340
|
|
|
|
|
|
|
# print "$textsize\n"; |
341
|
|
|
|
|
|
|
if(0) { |
342
|
|
|
|
|
|
|
package Tk::WorldCanvas; |
343
|
|
|
|
|
|
|
my $pdata = $cnv->privateData(); |
344
|
|
|
|
|
|
|
print "pdata: $pdata\n"; |
345
|
|
|
|
|
|
|
foreach my $key (keys(%$pdata)) { |
346
|
|
|
|
|
|
|
print "$key: $pdata->{$key}\n"; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
print "size is now $pdata->{width} x $pdata->{height}\n"; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
); |
353
|
|
|
|
|
|
|
$cnv->CanvasBind('' => sub{ |
354
|
|
|
|
|
|
|
$cnv->zoom(1/1.125); |
355
|
|
|
|
|
|
|
text_size_reset($cnv); |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
); |
358
|
|
|
|
|
|
|
# zoom extents: |
359
|
|
|
|
|
|
|
$cnv->CanvasBind('' => sub{ |
360
|
|
|
|
|
|
|
$cnv->viewAll(); |
361
|
|
|
|
|
|
|
text_size_reset($cnv); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
); |
364
|
|
|
|
|
|
|
# zoom window: |
365
|
|
|
|
|
|
|
$mw->bind( |
366
|
|
|
|
|
|
|
'' => sub { |
367
|
|
|
|
|
|
|
$stl->configure(-text=>"Pick window corners"); |
368
|
|
|
|
|
|
|
windowzoom($cnv, $stl); |
369
|
|
|
|
|
|
|
}); |
370
|
|
|
|
|
|
|
# measure: |
371
|
|
|
|
|
|
|
$mw->bind( |
372
|
|
|
|
|
|
|
'' => sub { |
373
|
|
|
|
|
|
|
$stl->configure(-text=>"Pick ends"); |
374
|
|
|
|
|
|
|
free_dist($cnv, $stl); |
375
|
|
|
|
|
|
|
}); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
} # end subroutine tkbindings definition |
379
|
|
|
|
|
|
|
######################################################################## |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head2 text_size_reset |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
text_size_reset($cnv); |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=cut |
386
|
|
|
|
|
|
|
sub text_size_reset { |
387
|
|
|
|
|
|
|
my $cnv = shift; |
388
|
|
|
|
|
|
|
my @c = $cnv->getView(); |
389
|
|
|
|
|
|
|
my $width = $c[2] - $c[0]; |
390
|
|
|
|
|
|
|
my $disp = $cnv->cget(-width); |
391
|
|
|
|
|
|
|
# print "showing $width in $disp\n"; |
392
|
|
|
|
|
|
|
# print "scale is ", $disp / $width, "\n"; |
393
|
|
|
|
|
|
|
$textsize = $text_base * $disp / $width; |
394
|
|
|
|
|
|
|
# print "textsize is $textsize\n"; |
395
|
|
|
|
|
|
|
# XXX this is really getting to be a pain (too-large text causes slow-down) |
396
|
|
|
|
|
|
|
($textsize > 100) && ($textsize = 100); |
397
|
|
|
|
|
|
|
if($textsize >= 2) { |
398
|
|
|
|
|
|
|
## print "textsize: $textsize\n"; |
399
|
|
|
|
|
|
|
$cnv->fontConfigure('cad-drawing-font', -size => $textsize); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
else { |
402
|
|
|
|
|
|
|
$cnv->fontConfigure('cad-drawing-font', -size => 2); |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
} # end subroutine text_size_reset definition |
407
|
|
|
|
|
|
|
######################################################################## |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=head2 free_dist |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
free_dist(); |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=cut |
414
|
|
|
|
|
|
|
sub free_dist { |
415
|
|
|
|
|
|
|
my $cnv = shift; |
416
|
|
|
|
|
|
|
my $stl = shift; |
417
|
|
|
|
|
|
|
# this is crappy |
418
|
|
|
|
|
|
|
$cnv->CanvasBind( |
419
|
|
|
|
|
|
|
'' => sub { |
420
|
|
|
|
|
|
|
$cnv->rubberBand(0); |
421
|
|
|
|
|
|
|
}); |
422
|
|
|
|
|
|
|
$cnv->CanvasBind( |
423
|
|
|
|
|
|
|
'' => sub { |
424
|
|
|
|
|
|
|
$cnv->rubberBand(1); |
425
|
|
|
|
|
|
|
}); |
426
|
|
|
|
|
|
|
$cnv->CanvasBind( |
427
|
|
|
|
|
|
|
'' => sub { |
428
|
|
|
|
|
|
|
my @box = $cnv->rubberBand(2); |
429
|
|
|
|
|
|
|
# print "box is @box\n"; |
430
|
|
|
|
|
|
|
my $dist = dist2d([@box[0,1]],[@box[2,3]]); |
431
|
|
|
|
|
|
|
my $dx = $box[2] - $box[0]; |
432
|
|
|
|
|
|
|
my $dy = $box[1] - $box[3]; |
433
|
|
|
|
|
|
|
foreach my $item qw( |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
) { |
438
|
|
|
|
|
|
|
# print "item: $item\n"; |
439
|
|
|
|
|
|
|
$cnv->CanvasBind($item => ""); |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
$stl->configure(-text=>"$dist ($dx,$dy)"); |
442
|
|
|
|
|
|
|
warn("measure: $dist ($dx,$dy)\n"); |
443
|
|
|
|
|
|
|
}); |
444
|
|
|
|
|
|
|
} # end subroutine free_dist definition |
445
|
|
|
|
|
|
|
######################################################################## |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head2 windowzoom |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Creates temporary bindings to drawing a rubber-band box. |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
windowzoom($cnv); |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=cut |
454
|
|
|
|
|
|
|
sub windowzoom { |
455
|
|
|
|
|
|
|
my $cnv = shift; |
456
|
|
|
|
|
|
|
my $stl = shift; |
457
|
|
|
|
|
|
|
$cnv->CanvasBind( |
458
|
|
|
|
|
|
|
'' => sub { |
459
|
|
|
|
|
|
|
$cnv->rubberBand(0); |
460
|
|
|
|
|
|
|
}); |
461
|
|
|
|
|
|
|
$cnv->CanvasBind( |
462
|
|
|
|
|
|
|
'' => sub { |
463
|
|
|
|
|
|
|
$cnv->rubberBand(1); |
464
|
|
|
|
|
|
|
}); |
465
|
|
|
|
|
|
|
$cnv->CanvasBind( |
466
|
|
|
|
|
|
|
'' => sub { |
467
|
|
|
|
|
|
|
my @box = $cnv->rubberBand(2); |
468
|
|
|
|
|
|
|
#print "box is @box\n"; |
469
|
|
|
|
|
|
|
$cnv->viewArea(@box); |
470
|
|
|
|
|
|
|
text_size_reset($cnv); |
471
|
|
|
|
|
|
|
foreach my $item qw( |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
) { |
476
|
|
|
|
|
|
|
# print "item: $item\n"; |
477
|
|
|
|
|
|
|
$cnv->CanvasBind($item => ""); |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
$stl->configure(-text=>""); |
480
|
|
|
|
|
|
|
}); |
481
|
|
|
|
|
|
|
} # end subroutine windowzoom definition |
482
|
|
|
|
|
|
|
######################################################################## |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=head2 tksetview |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
No longer used |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
$drw->tksetview($cnv, %options); |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=cut |
492
|
|
|
|
|
|
|
sub tksetview { |
493
|
|
|
|
|
|
|
my $self = shift; |
494
|
|
|
|
|
|
|
my $cnv = shift; |
495
|
|
|
|
|
|
|
my %options = @_; |
496
|
|
|
|
|
|
|
my $width = $options{size}[0]; |
497
|
|
|
|
|
|
|
my $height = $options{size}[1]; |
498
|
|
|
|
|
|
|
my @ext = $self->OrthExtents($options{items}); |
499
|
|
|
|
|
|
|
print "got extents: ", |
500
|
|
|
|
|
|
|
join(" by ", map({join(" to ", @$_)} @ext)), "\n"; |
501
|
|
|
|
|
|
|
my @cent = map({($_->[0] + $_->[1]) / 2} @ext); |
502
|
|
|
|
|
|
|
$options{center} && (@cent = @{$options{center}}); |
503
|
|
|
|
|
|
|
print "center is @cent\n"; |
504
|
|
|
|
|
|
|
my $scale = $options{scale}; |
505
|
|
|
|
|
|
|
unless($scale) { |
506
|
|
|
|
|
|
|
$scale = $self->scalebox($options{size}, \@ext); |
507
|
|
|
|
|
|
|
# print "got scale: $scale\n"; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
$cnv->scale('all'=> 0,0 , $scale, $scale); |
510
|
|
|
|
|
|
|
my $bbox = $options{bbox}; |
511
|
|
|
|
|
|
|
$_ *= $scale for @$bbox; |
512
|
|
|
|
|
|
|
# print "bbox now: @$bbox\n"; |
513
|
|
|
|
|
|
|
$cnv->configure(-scrollregion=> $bbox); |
514
|
|
|
|
|
|
|
# my $xv = $ext[0][0] * $scale / $bbox->[2]; |
515
|
|
|
|
|
|
|
my $xv = ($ext[0][0] * $scale - $bbox->[0]) / |
516
|
|
|
|
|
|
|
($bbox->[2] - $bbox->[0]); |
517
|
|
|
|
|
|
|
## my $xv = ($width / 2 - $bbox->[0]) / |
518
|
|
|
|
|
|
|
## ($bbox->[2] - $bbox->[0]); |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
print "xview: $xv\n"; |
521
|
|
|
|
|
|
|
$cnv->xviewMoveto($xv); |
522
|
|
|
|
|
|
|
my (undef(), $yv) = tkpoint([0,$ext[1][0]]); |
523
|
|
|
|
|
|
|
print "ypt: $yv\n"; |
524
|
|
|
|
|
|
|
print "ext top: $ext[1][1] bottom: $ext[1][0]\n"; |
525
|
|
|
|
|
|
|
print "bbox (t&b): $bbox->[1] $bbox->[3]\n"; |
526
|
|
|
|
|
|
|
$yv = (-$ext[1][0] * $scale + $bbox->[3] - $height / 2) / |
527
|
|
|
|
|
|
|
($bbox->[3] - $bbox->[1]); |
528
|
|
|
|
|
|
|
print "yview: $yv\n"; |
529
|
|
|
|
|
|
|
$cnv->yviewMoveto($yv); |
530
|
|
|
|
|
|
|
} # end subroutine tksetview definition |
531
|
|
|
|
|
|
|
######################################################################## |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=head2 scalebox |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Returns the scaling required to create a view which most closely |
536
|
|
|
|
|
|
|
matches @ext to @size of canvas. |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
$scale = $drw->scalebox(\@size, \@ext); |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=cut |
541
|
|
|
|
|
|
|
sub scalebox { |
542
|
|
|
|
|
|
|
my $self = shift; |
543
|
|
|
|
|
|
|
my ($size, $ext) = @_; |
544
|
|
|
|
|
|
|
my ($ew, $eh) = map({abs($_->[0] - $_->[1])} @$ext); |
545
|
|
|
|
|
|
|
my $dx = $size->[0] / $ew; |
546
|
|
|
|
|
|
|
my $dy = $size->[1] / $eh; |
547
|
|
|
|
|
|
|
# print "factors: $dx $dy\n"; |
548
|
|
|
|
|
|
|
my $scale = [$dx => $dy] -> [$dy <= $dx]; |
549
|
|
|
|
|
|
|
return($scale); |
550
|
|
|
|
|
|
|
} # end subroutine scalebox definition |
551
|
|
|
|
|
|
|
######################################################################## |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=head2 dsp subroutine refs |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
each of these should do everything necessary to draw the item on the |
556
|
|
|
|
|
|
|
canvas (but they might like to have a few options available?) and then |
557
|
|
|
|
|
|
|
return a list of the Tk id's of the created items. Caller will then |
558
|
|
|
|
|
|
|
assign identical tags to each id which is returned by each per-entity |
559
|
|
|
|
|
|
|
call. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=cut |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
%dsp = ( |
564
|
|
|
|
|
|
|
lines => sub { |
565
|
|
|
|
|
|
|
my ($self, $cnv, $addr) = @_; |
566
|
|
|
|
|
|
|
my $arrow = "none"; |
567
|
|
|
|
|
|
|
$CAD::Drawing::IO::Tk::arrow && ($arrow = "last"); |
568
|
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
569
|
|
|
|
|
|
|
my $line = $cnv->createLine( |
570
|
|
|
|
|
|
|
map({tkpoint($_)} |
571
|
|
|
|
|
|
|
@{$obj->{pts}}, |
572
|
|
|
|
|
|
|
), |
573
|
|
|
|
|
|
|
# '-dash' => "", |
574
|
|
|
|
|
|
|
# '-activedash' => ",", |
575
|
|
|
|
|
|
|
# '-activefill' => "#ff0000", |
576
|
|
|
|
|
|
|
'-fill'=> $aci2hex[$obj->{color}], |
577
|
|
|
|
|
|
|
'-arrow' => $arrow, |
578
|
|
|
|
|
|
|
); |
579
|
|
|
|
|
|
|
# print "line item: $line (ref: ", ref($line), ")\n"; |
580
|
|
|
|
|
|
|
# my @list = $cnv->itemconfigure($line); |
581
|
|
|
|
|
|
|
# foreach my $deal (@list) { |
582
|
|
|
|
|
|
|
# print "got deal: @$deal\n"; |
583
|
|
|
|
|
|
|
#} |
584
|
|
|
|
|
|
|
return($line); |
585
|
|
|
|
|
|
|
}, # end sub $dsp{lines} |
586
|
|
|
|
|
|
|
plines => sub { |
587
|
|
|
|
|
|
|
my ($self, $cnv, $addr) = @_; |
588
|
|
|
|
|
|
|
my $arrow = "none"; |
589
|
|
|
|
|
|
|
$CAD::Drawing::IO::Tk::arrow && ($arrow = "last"); |
590
|
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
591
|
|
|
|
|
|
|
my $st = $obj->{closed} ? -1 : 0; |
592
|
|
|
|
|
|
|
my @ids; |
593
|
|
|
|
|
|
|
for(my $i = $st; $i < scalar(@{$obj->{pts}}) -1; $i++) { |
594
|
|
|
|
|
|
|
my @pts = map({tkpoint($_)} |
595
|
|
|
|
|
|
|
$obj->{pts}[$i], $obj->{pts}[$i+1], |
596
|
|
|
|
|
|
|
); |
597
|
|
|
|
|
|
|
# print "adding @pts ($i -> ", $i+1, ")\n"; |
598
|
|
|
|
|
|
|
my $pline = $cnv->createLine( |
599
|
|
|
|
|
|
|
@pts, |
600
|
|
|
|
|
|
|
'-fill' => $aci2hex[$obj->{color}], |
601
|
|
|
|
|
|
|
'-arrow' => $arrow, |
602
|
|
|
|
|
|
|
); |
603
|
|
|
|
|
|
|
# print "pline item: $pline\n"; |
604
|
|
|
|
|
|
|
push(@ids, $pline); |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
return(@ids); |
607
|
|
|
|
|
|
|
}, # end sub $dsp{plines} |
608
|
|
|
|
|
|
|
arcs => sub { |
609
|
|
|
|
|
|
|
my ($self, $cnv, $addr) = @_; |
610
|
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
611
|
|
|
|
|
|
|
# print "keys: ", join(" ", keys(%$obj)), "\n"; |
612
|
|
|
|
|
|
|
my $rad = $obj->{rad}; |
613
|
|
|
|
|
|
|
my @pt = tkpoint($obj->{pt}); |
614
|
|
|
|
|
|
|
# stupid graphics packages: |
615
|
|
|
|
|
|
|
my @rec = ( |
616
|
|
|
|
|
|
|
map({$_ - $rad} @pt), |
617
|
|
|
|
|
|
|
map({$_ + $rad} @pt), |
618
|
|
|
|
|
|
|
); |
619
|
|
|
|
|
|
|
my @angs = @{$obj->{angs}}; |
620
|
|
|
|
|
|
|
# stupid graphics packages: |
621
|
|
|
|
|
|
|
@angs = map({$_ * 180 / $pi} @angs); |
622
|
|
|
|
|
|
|
$angs[1] = $angs[1] - $angs[0]; |
623
|
|
|
|
|
|
|
$angs[1] += 360; |
624
|
|
|
|
|
|
|
while($angs[1] > 360) { |
625
|
|
|
|
|
|
|
$angs[1] -= 360; |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
my $arc = $cnv->createArc( |
628
|
|
|
|
|
|
|
@rec, |
629
|
|
|
|
|
|
|
'-start' => $angs[0], |
630
|
|
|
|
|
|
|
'-extent' => $angs[1], |
631
|
|
|
|
|
|
|
'-outline' => $aci2hex[$obj->{color}], |
632
|
|
|
|
|
|
|
'-style' => "arc", |
633
|
|
|
|
|
|
|
); |
634
|
|
|
|
|
|
|
return($arc); |
635
|
|
|
|
|
|
|
}, # end sub $dsp{arcs} |
636
|
|
|
|
|
|
|
circles => sub { |
637
|
|
|
|
|
|
|
my ($self, $cnv, $addr) = @_; |
638
|
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
639
|
|
|
|
|
|
|
my $rad = $obj->{rad}; |
640
|
|
|
|
|
|
|
my @pt = tkpoint($obj->{pt}); |
641
|
|
|
|
|
|
|
# stupid graphics packages: |
642
|
|
|
|
|
|
|
my @rec = ( |
643
|
|
|
|
|
|
|
map({$_ - $rad} @pt), |
644
|
|
|
|
|
|
|
map({$_ + $rad} @pt), |
645
|
|
|
|
|
|
|
); |
646
|
|
|
|
|
|
|
my $circ = $cnv->createOval( |
647
|
|
|
|
|
|
|
@rec, |
648
|
|
|
|
|
|
|
'-outline' => $aci2hex[$obj->{color}], |
649
|
|
|
|
|
|
|
); |
650
|
|
|
|
|
|
|
return($circ); |
651
|
|
|
|
|
|
|
}, # end sub $dsp{circles} |
652
|
|
|
|
|
|
|
texts => sub { |
653
|
|
|
|
|
|
|
my ($self, $cnv, $addr) = @_; |
654
|
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
655
|
|
|
|
|
|
|
my @pt = tkpoint($obj->{pt}); |
656
|
|
|
|
|
|
|
my $height = $obj->{height}; |
657
|
|
|
|
|
|
|
my $string = $obj->{string}; |
658
|
|
|
|
|
|
|
my @text; |
659
|
|
|
|
|
|
|
# FIXME: if tk doesn't get its act together, this becomes kludge: |
660
|
|
|
|
|
|
|
if($obj->{render}) { |
661
|
|
|
|
|
|
|
die "this is broken"; |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
else { |
664
|
|
|
|
|
|
|
@text = $cnv->createText( |
665
|
|
|
|
|
|
|
@pt, |
666
|
|
|
|
|
|
|
-font => "cad-drawing-font", # |
667
|
|
|
|
|
|
|
-anchor => "sw", |
668
|
|
|
|
|
|
|
-text => $string, |
669
|
|
|
|
|
|
|
-fill => $aci2hex[$obj->{color}], |
670
|
|
|
|
|
|
|
); |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
return(@text); |
673
|
|
|
|
|
|
|
}, # end sub $dsp{texts} |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
); # end %dsp coderef hash |
676
|
|
|
|
|
|
|
######################################################################## |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head2 tkpoint |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
Returns only the first and second element of an array reference as a |
681
|
|
|
|
|
|
|
list. |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
@xy_point = tkpoint(\@pt); |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=cut |
686
|
|
|
|
|
|
|
sub tkpoint { |
687
|
|
|
|
|
|
|
return($_[0]->[0], $_[0]->[1]); |
688
|
|
|
|
|
|
|
} # end subroutine tkpoint definition |
689
|
|
|
|
|
|
|
######################################################################## |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
=head2 addr_to_tktag |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
Returns a stringified tag of form: ###### |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
my $tag = $drw->addr_to_tktag($addr); |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
=cut |
698
|
|
|
|
|
|
|
sub addr_to_tktag { |
699
|
|
|
|
|
|
|
my $self = shift; |
700
|
|
|
|
|
|
|
my $addr = shift; |
701
|
|
|
|
|
|
|
return(join("###", $addr->{layer}, $addr->{type}, $addr->{id})); |
702
|
|
|
|
|
|
|
} # end subroutine addr_to_tktag definition |
703
|
|
|
|
|
|
|
######################################################################## |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=head2 tktag_to_addr |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
Returns an anonymous hash reference which should serve as an address, |
708
|
|
|
|
|
|
|
provided that $tag is a valid ###### tag (and that the |
709
|
|
|
|
|
|
|
entity exists in the $drw object (check this yourself.) |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
my $addr = $drw->tktag_to_addr($tag); |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=cut |
714
|
|
|
|
|
|
|
sub tktag_to_addr { |
715
|
|
|
|
|
|
|
my $self = shift; |
716
|
|
|
|
|
|
|
my $tag = shift; |
717
|
|
|
|
|
|
|
my @these = split(/###/, $tag); |
718
|
|
|
|
|
|
|
(@these == 3) or croak("parsing tag failed! ($tag)\n"); |
719
|
|
|
|
|
|
|
my @order = qw(layer type id); |
720
|
|
|
|
|
|
|
return({map({$order[$_] => $these[$_]} 0..2)}); |
721
|
|
|
|
|
|
|
} # end subroutine tktag_to_addr definition |
722
|
|
|
|
|
|
|
######################################################################## |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
1; |