| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package CAD::Drawing::GUI::View; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | require Tk::Zinc; | 
| 4 |  |  |  |  |  |  | require Tk::Derived; | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 1 |  |  | 1 |  | 7 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 34 |  | 
| 7 | 1 |  |  | 1 |  | 10 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 50 |  | 
| 8 | 1 |  |  | 1 |  | 588 | use Tk; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | use Carp; | 
| 11 |  |  |  |  |  |  | use CAD::Calc qw( | 
| 12 |  |  |  |  |  |  | pi | 
| 13 |  |  |  |  |  |  | dist2d | 
| 14 |  |  |  |  |  |  | ); | 
| 15 |  |  |  |  |  |  | use CAD::DXF::Color qw( | 
| 16 |  |  |  |  |  |  | aci2hex | 
| 17 |  |  |  |  |  |  | ); | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | our $VERSION = '0.01'; | 
| 20 |  |  |  |  |  |  | our @ISA = qw( | 
| 21 |  |  |  |  |  |  | Tk::Derived | 
| 22 |  |  |  |  |  |  | Tk::Zinc | 
| 23 |  |  |  |  |  |  | ); | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | =head1 NAME | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | CAD::Drawing::GUI::View - 2D graphics for CAD built on Tk::Zinc | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | This module provides methods to turn a CAD::Drawing object into a Zinc | 
| 32 |  |  |  |  |  |  | canvas. | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | write me | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | =head1 AUTHOR | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | Eric L. Wilhelm | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | http://scratchcomputing.com | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | This module is copyright (C) 2004-2006 by Eric L. Wilhelm. | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | =head1 LICENSE | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | This module is distributed under the same terms as Perl.  See the Perl | 
| 51 |  |  |  |  |  |  | source package for details. | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | You may use this software under one of the following licenses: | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | (1) GNU General Public License | 
| 56 |  |  |  |  |  |  | (found at http://www.gnu.org/copyleft/gpl.html) | 
| 57 |  |  |  |  |  |  | (2) Artistic License | 
| 58 |  |  |  |  |  |  | (found at http://www.perl.com/pub/language/misc/Artistic.html) | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | =head1 Modifications | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | The source code of this module is made freely available and | 
| 63 |  |  |  |  |  |  | distributable under the GPL or Artistic License.  Modifications to and | 
| 64 |  |  |  |  |  |  | use of this software must adhere to one of these licenses.  Changes to | 
| 65 |  |  |  |  |  |  | the code should be noted as such and this notification (as well as the | 
| 66 |  |  |  |  |  |  | above copyright information) must remain intact on all copies of the | 
| 67 |  |  |  |  |  |  | code. | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | Additionally, while the author is actively developing this code, | 
| 70 |  |  |  |  |  |  | notification of any intended changes or extensions would be most helpful | 
| 71 |  |  |  |  |  |  | in avoiding repeated work for all parties involved.  Please contact the | 
| 72 |  |  |  |  |  |  | author with any such development plans. | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | CAD::Drawing::GUI | 
| 77 |  |  |  |  |  |  | Tk::Zinc | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | =cut | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | Construct Tk::Widget 'CADView'; | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | =head1 Overridden Methods | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | These make me behave like a Tk widget. | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | =head2 ClassInit | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | $view->ClassInit(); | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | =cut | 
| 93 |  |  |  |  |  |  | sub ClassInit { | 
| 94 |  |  |  |  |  |  | my $self = shift; | 
| 95 |  |  |  |  |  |  | my ($mw) = @_; | 
| 96 |  |  |  |  |  |  | $self->SUPER::ClassInit($mw); | 
| 97 |  |  |  |  |  |  | } # end subroutine ClassInit definition | 
| 98 |  |  |  |  |  |  | ######################################################################## | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | =head2 InitObject | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | $view->InitObject(); | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | =cut | 
| 105 |  |  |  |  |  |  | sub InitObject { | 
| 106 |  |  |  |  |  |  | my $self = shift; | 
| 107 |  |  |  |  |  |  | my ($args) = @_; | 
| 108 |  |  |  |  |  |  | my $pData = $self->privateData; | 
| 109 |  |  |  |  |  |  | # $pData->{'bbox'} = [0, 0, -1, -1]; | 
| 110 |  |  |  |  |  |  | $pData->{'scale'} = 1; | 
| 111 |  |  |  |  |  |  | $pData->{'move'} = [0,0]; | 
| 112 |  |  |  |  |  |  | # $pData->{'bboxvalid'} = 1; | 
| 113 |  |  |  |  |  |  | $pData->{'width'} = $self->width; | 
| 114 |  |  |  |  |  |  | $pData->{'height'} = $self->height; | 
| 115 |  |  |  |  |  |  | $pData->{'-pandist'} = 5; | 
| 116 |  |  |  |  |  |  | # strip other args | 
| 117 |  |  |  |  |  |  | $args = {$self->args_filter(%$args)}; | 
| 118 |  |  |  |  |  |  | $pData->{group} = $self->add('group', 1, -visible => 1); | 
| 119 |  |  |  |  |  |  | $self->configure(-confine => 0); | 
| 120 |  |  |  |  |  |  | # $self->configure('-highlightbackground' => '#FF0000'); | 
| 121 |  |  |  |  |  |  | $self->ConfigSpecs( | 
| 122 |  |  |  |  |  |  | '-bandColor' => ['PASSIVE', 'bandColor', 'BandColor', 'red'], | 
| 123 |  |  |  |  |  |  | '-bandcolor' => '-bandColor', | 
| 124 |  |  |  |  |  |  | '-changeView' => ['CALLBACK', 'changeView', 'ChangeView', undef], | 
| 125 |  |  |  |  |  |  | '-changeview'  => '-changeView' | 
| 126 |  |  |  |  |  |  | ); | 
| 127 |  |  |  |  |  |  | $self->Tk::bind('' => | 
| 128 |  |  |  |  |  |  | sub { | 
| 129 |  |  |  |  |  |  | # print "hi\n" | 
| 130 |  |  |  |  |  |  | $self->active(1); | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  | ); | 
| 133 |  |  |  |  |  |  | $self->Tk::bind('' => | 
| 134 |  |  |  |  |  |  | sub { | 
| 135 |  |  |  |  |  |  | # print "bye\n" | 
| 136 |  |  |  |  |  |  | $self->active(0); | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  | ); | 
| 139 |  |  |  |  |  |  | # $self->Tk::bind('' => sub {print "no\n"}); | 
| 140 |  |  |  |  |  |  | ## $self->Tk::bind('' => | 
| 141 |  |  |  |  |  |  | ## 	sub { | 
| 142 |  |  |  |  |  |  | ## 		print "hi @_\n"; | 
| 143 |  |  |  |  |  |  | ## 	} | 
| 144 |  |  |  |  |  |  | ## 	); | 
| 145 |  |  |  |  |  |  | $self->SUPER::InitObject($args); | 
| 146 |  |  |  |  |  |  | } # end subroutine InitObject definition | 
| 147 |  |  |  |  |  |  | ######################################################################## | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | =head2 configure | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | $view->configure(%args); | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =cut | 
| 154 |  |  |  |  |  |  | sub configure { | 
| 155 |  |  |  |  |  |  | my $self = shift; | 
| 156 |  |  |  |  |  |  | my %args = @_; | 
| 157 |  |  |  |  |  |  | %args = $self->args_filter(%args); | 
| 158 |  |  |  |  |  |  | $self->SUPER::configure(%args); | 
| 159 |  |  |  |  |  |  | } # end subroutine configure definition | 
| 160 |  |  |  |  |  |  | ######################################################################## | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | =head2 args_filter | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | Filters configure arguments and adds non-tk args to our private data. | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | %args = $view->args_filter(%args); | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | =cut | 
| 169 |  |  |  |  |  |  | sub args_filter { | 
| 170 |  |  |  |  |  |  | my $self = shift; | 
| 171 |  |  |  |  |  |  | my %args = @_; | 
| 172 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 173 |  |  |  |  |  |  | my %req = ( | 
| 174 |  |  |  |  |  |  | map({$_ => 1} | 
| 175 |  |  |  |  |  |  | qw( | 
| 176 |  |  |  |  |  |  | -parent | 
| 177 |  |  |  |  |  |  | )), | 
| 178 |  |  |  |  |  |  | map({$_ => 0} | 
| 179 |  |  |  |  |  |  | qw( | 
| 180 |  |  |  |  |  |  | -pandist | 
| 181 |  |  |  |  |  |  | ) | 
| 182 |  |  |  |  |  |  | ) | 
| 183 |  |  |  |  |  |  | ); | 
| 184 |  |  |  |  |  |  | foreach my $key (keys(%req)) { | 
| 185 |  |  |  |  |  |  | if(exists($args{$key})) { | 
| 186 |  |  |  |  |  |  | # print "configuring $key\n"; | 
| 187 |  |  |  |  |  |  | $pdata->{$key} = $args{$key}; | 
| 188 |  |  |  |  |  |  | delete($args{$key}); | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  | else { | 
| 191 |  |  |  |  |  |  | if($req{$key}) { | 
| 192 |  |  |  |  |  |  | exists($pdata->{$key}) or | 
| 193 |  |  |  |  |  |  | croak("required option $key missing\n"); | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  | return(%args); | 
| 198 |  |  |  |  |  |  | } # end subroutine args_filter definition | 
| 199 |  |  |  |  |  |  | ######################################################################## | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | =head1 privateData accessor methods | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | =head2 group_is | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | This object expects you to draw all of your items in this group. | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | $view->group_is(); | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | =cut | 
| 210 |  |  |  |  |  |  | sub group_is { | 
| 211 |  |  |  |  |  |  | my $self = shift; | 
| 212 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 213 |  |  |  |  |  |  | return($pdata->{group}); | 
| 214 |  |  |  |  |  |  | } # end subroutine group_is definition | 
| 215 |  |  |  |  |  |  | ######################################################################## | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | =head2 active | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | $view->active() or print "no\n"; | 
| 220 |  |  |  |  |  |  | $view->active(1); | 
| 221 |  |  |  |  |  |  | $view->active(0); | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | =cut | 
| 224 |  |  |  |  |  |  | sub active { | 
| 225 |  |  |  |  |  |  | my $self = shift; | 
| 226 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 227 |  |  |  |  |  |  | if(@_) { | 
| 228 |  |  |  |  |  |  | my $act = $_[0]; | 
| 229 |  |  |  |  |  |  | if($act == 1) { | 
| 230 |  |  |  |  |  |  | $self->configure('-highlightbackground' => '#FF0000'); | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  | elsif($act == 0) { | 
| 233 |  |  |  |  |  |  | $self->configure('-highlightbackground' => '#666666'); | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  | else { | 
| 236 |  |  |  |  |  |  | croak("act must be 1 or 0"); | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  | $pdata->{active} = $act; | 
| 239 |  |  |  |  |  |  | return(1); | 
| 240 |  |  |  |  |  |  | } | 
| 241 |  |  |  |  |  |  | else { | 
| 242 |  |  |  |  |  |  | return($pdata->{active}); | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  | } # end subroutine active definition | 
| 245 |  |  |  |  |  |  | ######################################################################## | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | =head2 gui_parent | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | Retrieves or sets the -parent attribute (not to be confused with a | 
| 250 |  |  |  |  |  |  | parent window.) | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | $gui = $view->gui_parent(); | 
| 253 |  |  |  |  |  |  | $view->gui_parent($gui); | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | =cut | 
| 256 |  |  |  |  |  |  | sub gui_parent { | 
| 257 |  |  |  |  |  |  | my $self = shift; | 
| 258 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 259 |  |  |  |  |  |  | if(@_) { | 
| 260 |  |  |  |  |  |  | $pdata->{-parent} = $_[0]; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  | else { | 
| 263 |  |  |  |  |  |  | return($pdata->{-parent}); | 
| 264 |  |  |  |  |  |  | } | 
| 265 |  |  |  |  |  |  | } # end subroutine gui_parent definition | 
| 266 |  |  |  |  |  |  | ######################################################################## | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | =head1 Drawing Methods | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | The following methods handle the drawing of items from CAD::Drawing | 
| 271 |  |  |  |  |  |  | objects. | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | =head2 add_drawing | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | Adds drawing $drw as number $number.  This tags all of the items drawn | 
| 276 |  |  |  |  |  |  | by "$number:$type:$id:$layer". | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | $view->add_drawing($number, $drw); | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | =cut | 
| 281 |  |  |  |  |  |  | sub add_drawing { | 
| 282 |  |  |  |  |  |  | my $self = shift; | 
| 283 |  |  |  |  |  |  | my ($n, $drw) = @_; | 
| 284 |  |  |  |  |  |  | foreach my $addr (@{$drw->select_addr()}) { | 
| 285 |  |  |  |  |  |  | # print "draw $addr as $tag\n"; | 
| 286 |  |  |  |  |  |  | my $tag = addr_to_tag($n, $addr); | 
| 287 |  |  |  |  |  |  | my $obj = $drw->getobj($addr); | 
| 288 |  |  |  |  |  |  | $self->draw_item($obj, $tag); | 
| 289 |  |  |  |  |  |  | if(0) { | 
| 290 |  |  |  |  |  |  | require YAML; | 
| 291 |  |  |  |  |  |  | print YAML::Dump($obj), "\n"; | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | } | 
| 295 |  |  |  |  |  |  | } # end subroutine add_drawing definition | 
| 296 |  |  |  |  |  |  | ######################################################################## | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | =head2 drawing_update | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | Updates the canvas with the item at $addr. | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | $view->drawing_update($n, $drw, $addr); | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | =cut | 
| 305 |  |  |  |  |  |  | sub drawing_update { | 
| 306 |  |  |  |  |  |  | my $self = shift; | 
| 307 |  |  |  |  |  |  | my ($n, $drw, $addr) = @_; | 
| 308 |  |  |  |  |  |  | my $tag = addr_to_tag($n, $addr); | 
| 309 |  |  |  |  |  |  | # XXX select? | 
| 310 |  |  |  |  |  |  | my $obj = $drw->getobj($addr); | 
| 311 |  |  |  |  |  |  | $self->redraw_item($obj, $tag); | 
| 312 |  |  |  |  |  |  | } # end subroutine drawing_update definition | 
| 313 |  |  |  |  |  |  | ######################################################################## | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | #these return the tk::zinc type and a data list. | 
| 316 |  |  |  |  |  |  | our %trans_subs = ( | 
| 317 |  |  |  |  |  |  | lines => sub { | 
| 318 |  |  |  |  |  |  | my ($self,$o) = @_; | 
| 319 |  |  |  |  |  |  | my $data = [ | 
| 320 |  |  |  |  |  |  | [map({[$self->cnv_pt(@$_)]} @{$o->{pts}})], | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | ]; | 
| 323 |  |  |  |  |  |  | my $args = { | 
| 324 |  |  |  |  |  |  | -linecolor => undef(), | 
| 325 |  |  |  |  |  |  | }; | 
| 326 |  |  |  |  |  |  | return(['curve', $data, $args]); | 
| 327 |  |  |  |  |  |  | }, | 
| 328 |  |  |  |  |  |  | plines => sub { | 
| 329 |  |  |  |  |  |  | my ($self,$o) = @_; | 
| 330 |  |  |  |  |  |  | my $data = [ | 
| 331 |  |  |  |  |  |  | [map({[$self->cnv_pt(@$_)]} @{$o->{pts}})], | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | ]; | 
| 334 |  |  |  |  |  |  | my $args = { | 
| 335 |  |  |  |  |  |  | ($o->{closed} ? (-closed => 1) : ()), | 
| 336 |  |  |  |  |  |  | -linecolor => undef(), | 
| 337 |  |  |  |  |  |  | }; | 
| 338 |  |  |  |  |  |  | return(['curve', $data, $args]); | 
| 339 |  |  |  |  |  |  | }, | 
| 340 |  |  |  |  |  |  | points => sub { | 
| 341 |  |  |  |  |  |  | my ($self,$o) = @_; | 
| 342 |  |  |  |  |  |  | my @pt = $self->cnv_pt(@{$o->{pt}}); | 
| 343 |  |  |  |  |  |  | # ack! the size of this needs to float! | 
| 344 |  |  |  |  |  |  | # print "drawing point\n"; | 
| 345 |  |  |  |  |  |  | my $sz = 1; | 
| 346 |  |  |  |  |  |  | my $pts = [ | 
| 347 |  |  |  |  |  |  | [$pt[0] - $sz, $pt[1] - $sz], | 
| 348 |  |  |  |  |  |  | [$pt[0] + $sz, $pt[1] + $sz], | 
| 349 |  |  |  |  |  |  | ]; | 
| 350 |  |  |  |  |  |  | my $args = { | 
| 351 |  |  |  |  |  |  | -linecolor => undef(), | 
| 352 |  |  |  |  |  |  | }; | 
| 353 |  |  |  |  |  |  | return(['arc', [$pts, -closed => 1], $args]); | 
| 354 |  |  |  |  |  |  | }, | 
| 355 |  |  |  |  |  |  | arcs => sub { | 
| 356 |  |  |  |  |  |  | my ($self, $o) = @_; | 
| 357 |  |  |  |  |  |  | my $data = [ | 
| 358 |  |  |  |  |  |  | [ | 
| 359 |  |  |  |  |  |  | # this might make a mess: | 
| 360 |  |  |  |  |  |  | # [$self->cnv_pt(map({$_ - $o->{rad}} @{$o->{pt}}))], | 
| 361 |  |  |  |  |  |  | # [$self->cnv_pt(map({$_ + $o->{rad}} @{$o->{pt}}))], | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | # XXX will somebody please explain why every toolkit | 
| 364 |  |  |  |  |  |  | # must be so incredibly braindead! | 
| 365 |  |  |  |  |  |  | [ # "top left" rectangle point | 
| 366 |  |  |  |  |  |  | $self->cnv_pt( | 
| 367 |  |  |  |  |  |  | $o->{pt}[0] - $o->{rad}, | 
| 368 |  |  |  |  |  |  | $o->{pt}[1] + $o->{rad}, | 
| 369 |  |  |  |  |  |  | ) | 
| 370 |  |  |  |  |  |  | ], | 
| 371 |  |  |  |  |  |  | [ # "bottom right" rectangle point | 
| 372 |  |  |  |  |  |  | $self->cnv_pt( | 
| 373 |  |  |  |  |  |  | $o->{pt}[0] + $o->{rad}, | 
| 374 |  |  |  |  |  |  | $o->{pt}[1] - $o->{rad}, | 
| 375 |  |  |  |  |  |  | ) | 
| 376 |  |  |  |  |  |  | ], | 
| 377 |  |  |  |  |  |  | ], | 
| 378 |  |  |  |  |  |  | ]; | 
| 379 |  |  |  |  |  |  | my $args = { | 
| 380 |  |  |  |  |  |  | -startangle => $o->{angs}[0] * 180 / pi, | 
| 381 |  |  |  |  |  |  | -extent => abs(($o->{angs}[1] - $o->{angs}[0]) * 180 / pi), | 
| 382 |  |  |  |  |  |  | -linecolor => undef(), | 
| 383 |  |  |  |  |  |  | }; | 
| 384 |  |  |  |  |  |  | return(['arc', $data, $args]); | 
| 385 |  |  |  |  |  |  | }, | 
| 386 |  |  |  |  |  |  | circles => sub { | 
| 387 |  |  |  |  |  |  | my ($self, $o) = @_; | 
| 388 |  |  |  |  |  |  | my $data = [ | 
| 389 |  |  |  |  |  |  | [ | 
| 390 |  |  |  |  |  |  | # XXX will somebody please explain why every toolkit | 
| 391 |  |  |  |  |  |  | # must be so incredibly braindead! | 
| 392 |  |  |  |  |  |  | [ # "top left" rectangle point | 
| 393 |  |  |  |  |  |  | $self->cnv_pt( | 
| 394 |  |  |  |  |  |  | $o->{pt}[0] - $o->{rad}, | 
| 395 |  |  |  |  |  |  | $o->{pt}[1] + $o->{rad}, | 
| 396 |  |  |  |  |  |  | ) | 
| 397 |  |  |  |  |  |  | ], | 
| 398 |  |  |  |  |  |  | [ # "bottom right" rectangle point | 
| 399 |  |  |  |  |  |  | $self->cnv_pt( | 
| 400 |  |  |  |  |  |  | $o->{pt}[0] + $o->{rad}, | 
| 401 |  |  |  |  |  |  | $o->{pt}[1] - $o->{rad}, | 
| 402 |  |  |  |  |  |  | ) | 
| 403 |  |  |  |  |  |  | ], | 
| 404 |  |  |  |  |  |  | ], | 
| 405 |  |  |  |  |  |  | ]; | 
| 406 |  |  |  |  |  |  | # print "points: $data->[0][0][0],$data->[0][0][1] and ", | 
| 407 |  |  |  |  |  |  | # 	"$data->[0][1][0],$data->[0][1][1]\n"; | 
| 408 |  |  |  |  |  |  | my $args = { | 
| 409 |  |  |  |  |  |  | -startangle => 0, | 
| 410 |  |  |  |  |  |  | -closed => 1, | 
| 411 |  |  |  |  |  |  | # -extent => 360, | 
| 412 |  |  |  |  |  |  | -linecolor => undef(), | 
| 413 |  |  |  |  |  |  | }; | 
| 414 |  |  |  |  |  |  | return(['arc', $data, $args]); | 
| 415 |  |  |  |  |  |  | }, | 
| 416 |  |  |  |  |  |  | texts => sub { | 
| 417 |  |  |  |  |  |  | my ($self, $o) = @_; | 
| 418 |  |  |  |  |  |  | my @pt = $self->cnv_pt(@{$o->{pt}}); | 
| 419 |  |  |  |  |  |  | # XXX there's some kind of buffer under my text! | 
| 420 |  |  |  |  |  |  | $pt[1] += 3/12; | 
| 421 |  |  |  |  |  |  | my $data = [ | 
| 422 |  |  |  |  |  |  | ]; | 
| 423 |  |  |  |  |  |  | my $args = { | 
| 424 |  |  |  |  |  |  | -position => [@pt], | 
| 425 |  |  |  |  |  |  | -text => $o->{string}, | 
| 426 |  |  |  |  |  |  | -composescale => 1, # enable scaling! | 
| 427 |  |  |  |  |  |  | -composerotation => 1, | 
| 428 |  |  |  |  |  |  | -anchor => 'sw', | 
| 429 |  |  |  |  |  |  | # -font => $self->fontCreate( | 
| 430 |  |  |  |  |  |  | # 	$o, | 
| 431 |  |  |  |  |  |  | # 	-family => 'Courier', | 
| 432 |  |  |  |  |  |  | # 	-size => 12, | 
| 433 |  |  |  |  |  |  | # 	), | 
| 434 |  |  |  |  |  |  | # -font => 'lucidiasans-' . 2, | 
| 435 |  |  |  |  |  |  | # XXX okay, assume a 12pt font is 9px high: | 
| 436 |  |  |  |  |  |  | # -font => '-adobe-helvetica-bold-r-normal--12-120-*-*-*-*-*-*', | 
| 437 |  |  |  |  |  |  | # XXX or, 24pt is 15 high: | 
| 438 |  |  |  |  |  |  | -font => '-adobe-helvetica-*-r-normal--24-240-*-*-*-*-*-*', | 
| 439 |  |  |  |  |  |  | -color => undef(), | 
| 440 |  |  |  |  |  |  | }; | 
| 441 |  |  |  |  |  |  | ## print "text add at point: ", | 
| 442 |  |  |  |  |  |  | ## 	join(",", $self->cnv_pt(@{$o->{pt}})), | 
| 443 |  |  |  |  |  |  | ## 	"(", join(",", @{$o->{pt}}), ")", "\n"; | 
| 444 |  |  |  |  |  |  | return(['text', $data, $args]); | 
| 445 |  |  |  |  |  |  | }, | 
| 446 |  |  |  |  |  |  | ); | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | =head2 draw_item | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | Draws the $obj (possibly in multiple pieces), using $tag as the | 
| 451 |  |  |  |  |  |  | identifier. | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | $view->draw_item($obj, $tag); | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | =cut | 
| 456 |  |  |  |  |  |  | sub draw_item { | 
| 457 |  |  |  |  |  |  | my $self = shift; | 
| 458 |  |  |  |  |  |  | my ($obj, $tag) = @_; | 
| 459 |  |  |  |  |  |  | my $group = $self->group_is(); | 
| 460 |  |  |  |  |  |  | if(my $sub = $trans_subs{$obj->{addr}{type}}) { | 
| 461 |  |  |  |  |  |  | ## print "found sub for $obj->{addr}{type}\n"; | 
| 462 |  |  |  |  |  |  | my @bits = $sub->($self, $obj); | 
| 463 |  |  |  |  |  |  | foreach my $bit (@bits) { | 
| 464 |  |  |  |  |  |  | my $type = $bit->[0]; | 
| 465 |  |  |  |  |  |  | my $data = $bit->[1]; | 
| 466 |  |  |  |  |  |  | my %args = %{$bit->[2]}; | 
| 467 |  |  |  |  |  |  | # XXX try to handle colors in *ONE* place | 
| 468 |  |  |  |  |  |  | foreach my $key (keys(%args)) { | 
| 469 |  |  |  |  |  |  | if($key =~ m/color$/) { | 
| 470 |  |  |  |  |  |  | my $c = $obj->{color}; | 
| 471 |  |  |  |  |  |  | # XXX still punting bylayer/byblock colors | 
| 472 |  |  |  |  |  |  | #     ack! we would need the drawing for that info! | 
| 473 |  |  |  |  |  |  | ($c == 256) and ($c = 255); | 
| 474 |  |  |  |  |  |  | ($c == 0) and ($c = 255); | 
| 475 |  |  |  |  |  |  | $args{$key} = "#" . aci2hex($c); | 
| 476 |  |  |  |  |  |  | } | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | ## print "using data @$data\n"; | 
| 480 |  |  |  |  |  |  | my $item = $self->add($type, $group, | 
| 481 |  |  |  |  |  |  | @$data, %args, | 
| 482 |  |  |  |  |  |  | -tags => [$tag], | 
| 483 |  |  |  |  |  |  | ); | 
| 484 |  |  |  |  |  |  | # XXX I guess I need to index these? | 
| 485 |  |  |  |  |  |  | # print "item $item for $tag\n"; | 
| 486 |  |  |  |  |  |  | if(1 and $type eq 'text') { | 
| 487 |  |  |  |  |  |  | my $font = $self->itemcget($item, '-font'); | 
| 488 |  |  |  |  |  |  | my $base = $self->itemcget($item, '-position'); | 
| 489 |  |  |  |  |  |  | ## print "text has font $font and @$base\n"; | 
| 490 |  |  |  |  |  |  | # ack! why is this so hard! | 
| 491 |  |  |  |  |  |  | $self->itemconfigure($item, -position => [0,0]); | 
| 492 |  |  |  |  |  |  | # XXX how do I find the height of this text? | 
| 493 |  |  |  |  |  |  | # (see assumption above: | 
| 494 |  |  |  |  |  |  | #   1 unit is 12 pt and takes 9 pixels) | 
| 495 |  |  |  |  |  |  | #   1 unit is 24 pt and takes 15 pixels) | 
| 496 |  |  |  |  |  |  | my $scale = $obj->{height} / 15; | 
| 497 |  |  |  |  |  |  | ## print "initial scaling text by $scale\n"; | 
| 498 |  |  |  |  |  |  | $self->scale($item, $scale, $scale); | 
| 499 |  |  |  |  |  |  | if($obj->{ang}) { | 
| 500 |  |  |  |  |  |  | die "need text-angle support\n"; | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  | $self->itemconfigure($item, -position => $base); | 
| 503 |  |  |  |  |  |  | } | 
| 504 |  |  |  |  |  |  | ## print "mapping:  $tag -> $item\n"; | 
| 505 |  |  |  |  |  |  | } | 
| 506 |  |  |  |  |  |  | } | 
| 507 |  |  |  |  |  |  | else { | 
| 508 |  |  |  |  |  |  | warn("no sub for $obj->{addr}{type}\n"); | 
| 509 |  |  |  |  |  |  | } | 
| 510 |  |  |  |  |  |  | } # end subroutine draw_item definition | 
| 511 |  |  |  |  |  |  | ######################################################################## | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | =head2 redraw_item | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | $view->redraw_item(); | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | =cut | 
| 518 |  |  |  |  |  |  | sub redraw_item { | 
| 519 |  |  |  |  |  |  | my $self = shift; | 
| 520 |  |  |  |  |  |  | my ($obj, $tag) = @_; | 
| 521 |  |  |  |  |  |  | ## print "item $tag ", $self->coords($tag), "\n"; | 
| 522 |  |  |  |  |  |  | if(my $sub = $trans_subs{$obj->{addr}{type}}) { | 
| 523 |  |  |  |  |  |  | ## print "found sub for $obj->{addr}{type}\n"; | 
| 524 |  |  |  |  |  |  | my @bits = $sub->($self, $obj); | 
| 525 |  |  |  |  |  |  | foreach my $bit (@bits) { | 
| 526 |  |  |  |  |  |  | # XXX ack! | 
| 527 |  |  |  |  |  |  | my $type = $bit->[0]; | 
| 528 |  |  |  |  |  |  | my $data = $bit->[1]; | 
| 529 |  |  |  |  |  |  | my %args = %{$bit->[2]}; | 
| 530 |  |  |  |  |  |  | foreach my $key (keys(%args)) { | 
| 531 |  |  |  |  |  |  | if($key =~ m/color$/) { | 
| 532 |  |  |  |  |  |  | my $c = $obj->{color}; | 
| 533 |  |  |  |  |  |  | # XXX still punting bylayer/byblock colors | 
| 534 |  |  |  |  |  |  | #     ack! we would need the drawing for that info! | 
| 535 |  |  |  |  |  |  | ($c == 256) and ($c = 255); | 
| 536 |  |  |  |  |  |  | ($c == 0) and ($c = 255); | 
| 537 |  |  |  |  |  |  | $args{$key} = "#" . aci2hex($c); | 
| 538 |  |  |  |  |  |  | } | 
| 539 |  |  |  |  |  |  | } | 
| 540 |  |  |  |  |  |  | 0 and print "configure $tag to be @$data, ", | 
| 541 |  |  |  |  |  |  | join(" ", each(%args)), " etc\n"; | 
| 542 |  |  |  |  |  |  | $self->itemconfigure($tag, %args); | 
| 543 |  |  |  |  |  |  | if(ref($data->[0]) eq "ARRAY") { | 
| 544 |  |  |  |  |  |  | ## XXX the transform is off! | 
| 545 |  |  |  |  |  |  | ## print "input data: ", join(" ", map({join(",", @$_)} @{$data->[0]})), "\n"; | 
| 546 |  |  |  |  |  |  | ## print "current coords: ", join(" ", map({join(",", @$_)} $self->coords($tag))), "\n"; | 
| 547 |  |  |  |  |  |  | # ack! XXX this is screwy! | 
| 548 |  |  |  |  |  |  | my @coords = map({ | 
| 549 |  |  |  |  |  |  | my @p = $self->world_pt(@$_); [$p[0], -$p[1]] | 
| 550 |  |  |  |  |  |  | } @{$data->[0]}); | 
| 551 |  |  |  |  |  |  | ## print "input data2: ", join(" ", map({join(",", @$_)} @coords)), "\n"; | 
| 552 |  |  |  |  |  |  | $self->coords($tag, \@coords); | 
| 553 |  |  |  |  |  |  | ## print "current coords: ", join(" ", map({join(",", @$_)} $self->coords($tag))), "\n"; | 
| 554 |  |  |  |  |  |  | } | 
| 555 |  |  |  |  |  |  | } | 
| 556 |  |  |  |  |  |  | } | 
| 557 |  |  |  |  |  |  | } # end subroutine redraw_item definition | 
| 558 |  |  |  |  |  |  | ######################################################################## | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  |  | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =head1 Useful Methods | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | =head2 viewAll | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | $view->viewAll(); | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | =cut | 
| 569 |  |  |  |  |  |  | sub viewAll { | 
| 570 |  |  |  |  |  |  | my $self = shift; | 
| 571 |  |  |  |  |  |  | # ($self->width == 1 and $self->height == 1) and return(); | 
| 572 |  |  |  |  |  |  | if (!$self->type($self->group_is())) {return;} # can't find anything! | 
| 573 |  |  |  |  |  |  | my @bbox = $self->bbox('all'); | 
| 574 |  |  |  |  |  |  | $self->viewArea(@bbox); | 
| 575 |  |  |  |  |  |  | } # end subroutine viewAll definition | 
| 576 |  |  |  |  |  |  | ######################################################################## | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | =head2 viewArea | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | $view->viewArea(@bbox); | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | =cut | 
| 583 |  |  |  |  |  |  | sub viewArea { | 
| 584 |  |  |  |  |  |  | my $self = shift; | 
| 585 |  |  |  |  |  |  | my (@bbox) = @_; | 
| 586 |  |  |  |  |  |  | # let's be nice and sort these for the caller: | 
| 587 |  |  |  |  |  |  | ($bbox[0],$bbox[2]) = sort({$a<=>$b} $bbox[0],$bbox[2]); | 
| 588 |  |  |  |  |  |  | ($bbox[1],$bbox[3]) = sort({$a<=>$b} $bbox[1],$bbox[3]); | 
| 589 |  |  |  |  |  |  | my @span = ($bbox[2]-$bbox[0], $bbox[3]-$bbox[1]); | 
| 590 |  |  |  |  |  |  | ($span[0] and $span[1]) or return(); # nothing on canvas | 
| 591 |  |  |  |  |  |  | ## print "bbox says @bbox (@span)\n"; | 
| 592 |  |  |  |  |  |  | my @d_cent = map({$_ / 2} $bbox[2]+$bbox[0], $bbox[3]+$bbox[1]); | 
| 593 |  |  |  |  |  |  | my @view = ($self->width, $self->height); | 
| 594 |  |  |  |  |  |  | my @c_cent = map({$_ / 2} @view); | 
| 595 |  |  |  |  |  |  | ## print "change center @c_cent to @d_cent\n"; | 
| 596 |  |  |  |  |  |  | my @move = map({$c_cent[$_] - $d_cent[$_]} 0,1); | 
| 597 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 598 |  |  |  |  |  |  | if(abs($move[0]) >= 1 and abs($move[1]) >=1) { | 
| 599 |  |  |  |  |  |  | ## print "move by @move\n"; | 
| 600 |  |  |  |  |  |  | $pdata->{move}[$_] += $move[$_] * $pdata->{scale} foreach 0,1; | 
| 601 |  |  |  |  |  |  | $self->translate($pdata->{group}, @move); | 
| 602 |  |  |  |  |  |  | } | 
| 603 |  |  |  |  |  |  | my $scale = (sort({$a<=>$b} map({$view[$_] / $span[$_]} 0,1)))[0]; | 
| 604 |  |  |  |  |  |  | $self->zoom($scale); | 
| 605 |  |  |  |  |  |  | } # end subroutine viewArea definition | 
| 606 |  |  |  |  |  |  | ######################################################################## | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | =head2 viewWorldArea | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | $view->viewWorldArea([$x1,$y1],[$x2,$y2]); | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | =cut | 
| 613 |  |  |  |  |  |  | sub viewWorldArea { | 
| 614 |  |  |  |  |  |  | my $self = shift; | 
| 615 |  |  |  |  |  |  | my (@rec) = @_; | 
| 616 |  |  |  |  |  |  | my @bbox = ( | 
| 617 |  |  |  |  |  |  | $self->cnv_pt(@{$rec[0]}), | 
| 618 |  |  |  |  |  |  | $self->cnv_pt(@{$rec[1]}) | 
| 619 |  |  |  |  |  |  | ); | 
| 620 |  |  |  |  |  |  | $self->viewArea(@bbox); | 
| 621 |  |  |  |  |  |  | } # end subroutine viewWorldArea definition | 
| 622 |  |  |  |  |  |  | ######################################################################## | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  | =head2 zoom | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | $view->zoom($factor); | 
| 627 |  |  |  |  |  |  |  | 
| 628 |  |  |  |  |  |  | =cut | 
| 629 |  |  |  |  |  |  | sub zoom { | 
| 630 |  |  |  |  |  |  | my $self = shift; | 
| 631 |  |  |  |  |  |  | my $scale = shift; | 
| 632 |  |  |  |  |  |  | my @view = ($self->width, $self->height); | 
| 633 |  |  |  |  |  |  | my @c_cent = map({$_ / 2} @view); | 
| 634 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 635 |  |  |  |  |  |  | $self->scale($pdata->{group}, $scale, $scale, @c_cent); | 
| 636 |  |  |  |  |  |  | $pdata->{scale} *= $scale; | 
| 637 |  |  |  |  |  |  | } # end subroutine zoom definition | 
| 638 |  |  |  |  |  |  | ######################################################################## | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | =head2 windowzoom | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | Creates temporary bindings for drawing a rubber-band box and zooming on | 
| 643 |  |  |  |  |  |  | the area described by it.  This will put back your existing bindings. | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | $view->windowzoom(); | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | =cut | 
| 648 |  |  |  |  |  |  | sub windowzoom { | 
| 649 |  |  |  |  |  |  | my $self = shift; | 
| 650 |  |  |  |  |  |  | # XXX how to get my stl? | 
| 651 |  |  |  |  |  |  | my $stl = shift; | 
| 652 |  |  |  |  |  |  | $stl and $stl->configure(-text=>"Pick window corners"); | 
| 653 |  |  |  |  |  |  | my %was; | 
| 654 |  |  |  |  |  |  | my %tmp; # must declare before declaring | 
| 655 |  |  |  |  |  |  | %tmp = ( | 
| 656 |  |  |  |  |  |  | '' => sub { | 
| 657 |  |  |  |  |  |  | $self->rubberBand(0); | 
| 658 |  |  |  |  |  |  | }, | 
| 659 |  |  |  |  |  |  | '' => sub { | 
| 660 |  |  |  |  |  |  | $self->rubberBand(1); | 
| 661 |  |  |  |  |  |  | }, | 
| 662 |  |  |  |  |  |  | '' => sub { | 
| 663 |  |  |  |  |  |  | my @box = $self->rubberBand(2); | 
| 664 |  |  |  |  |  |  | ## print "box is @box\n"; | 
| 665 |  |  |  |  |  |  | $self->viewArea(@box); | 
| 666 |  |  |  |  |  |  | my $parent = $self->gui_parent(); | 
| 667 |  |  |  |  |  |  | $parent->event_done(); | 
| 668 |  |  |  |  |  |  | $stl and  $stl->configure(-text=>""); | 
| 669 |  |  |  |  |  |  | }, | 
| 670 |  |  |  |  |  |  | ); | 
| 671 |  |  |  |  |  |  | %was = $self->bind_on(\%tmp); | 
| 672 |  |  |  |  |  |  | return(\%tmp, \%was); | 
| 673 |  |  |  |  |  |  | } # end subroutine windowzoom definition | 
| 674 |  |  |  |  |  |  | ######################################################################## | 
| 675 |  |  |  |  |  |  |  | 
| 676 |  |  |  |  |  |  | =head2 free_dist | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | This is a freehand measuring tape.  Maybe we'll have some snaps someday | 
| 679 |  |  |  |  |  |  | (but likely not with this graphical toolkit.) | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | $view->free_dist(); | 
| 682 |  |  |  |  |  |  |  | 
| 683 |  |  |  |  |  |  | =cut | 
| 684 |  |  |  |  |  |  | sub free_dist { | 
| 685 |  |  |  |  |  |  | my $self = shift; | 
| 686 |  |  |  |  |  |  | my $stl = shift; | 
| 687 |  |  |  |  |  |  | $stl and $stl->configure(-text=>"Pick ends"); | 
| 688 |  |  |  |  |  |  | my %was; | 
| 689 |  |  |  |  |  |  | my %tmp; | 
| 690 |  |  |  |  |  |  | %tmp = ( | 
| 691 |  |  |  |  |  |  | '' => sub { | 
| 692 |  |  |  |  |  |  | $self->rubberBand(0); | 
| 693 |  |  |  |  |  |  | }, | 
| 694 |  |  |  |  |  |  | '' => sub { | 
| 695 |  |  |  |  |  |  | $self->rubberBand(1, 'line'); | 
| 696 |  |  |  |  |  |  | }, | 
| 697 |  |  |  |  |  |  | '' => sub { | 
| 698 |  |  |  |  |  |  | my @box = $self->rubberBand(2); | 
| 699 |  |  |  |  |  |  | # this needs to involve the parent | 
| 700 |  |  |  |  |  |  | # XXX how to make it cleaner? | 
| 701 |  |  |  |  |  |  | my $parent = $self->gui_parent(); | 
| 702 |  |  |  |  |  |  | $parent->event_done(); | 
| 703 |  |  |  |  |  |  | # print "box is @box\n"; | 
| 704 |  |  |  |  |  |  | my @pts = map({[$self->world_pt(@$_)]} | 
| 705 |  |  |  |  |  |  | [@box[0,1]],[@box[2,3]] | 
| 706 |  |  |  |  |  |  | ); | 
| 707 |  |  |  |  |  |  | my $dist = dist2d(@pts); | 
| 708 |  |  |  |  |  |  | my $dx = $pts[1][0] - $pts[0][0]; | 
| 709 |  |  |  |  |  |  | my $dy = $pts[1][1] - $pts[0][1]; | 
| 710 |  |  |  |  |  |  | $stl and $stl->configure(-text=>"$dist ($dx,$dy)"); | 
| 711 |  |  |  |  |  |  | warn("measure: $dist ($dx,$dy)\n"); | 
| 712 |  |  |  |  |  |  | }, | 
| 713 |  |  |  |  |  |  | ); | 
| 714 |  |  |  |  |  |  | %was = $self->bind_on(\%tmp); | 
| 715 |  |  |  |  |  |  | return(\%tmp, \%was); | 
| 716 |  |  |  |  |  |  | } # end subroutine free_dist definition | 
| 717 |  |  |  |  |  |  | ######################################################################## | 
| 718 |  |  |  |  |  |  |  | 
| 719 |  |  |  |  |  |  | =head2 pan | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | $view->pan($x,$y); | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | =cut | 
| 724 |  |  |  |  |  |  | sub pan { | 
| 725 |  |  |  |  |  |  | my $self = shift; | 
| 726 |  |  |  |  |  |  | my (@move) = @_; | 
| 727 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 728 |  |  |  |  |  |  | # print "pan\n"; | 
| 729 |  |  |  |  |  |  | $pdata->{move}[$_] += $move[$_] * $pdata->{scale} foreach 0,1; | 
| 730 |  |  |  |  |  |  | $self->translate($pdata->{group}, @move); | 
| 731 |  |  |  |  |  |  | } # end subroutine pan definition | 
| 732 |  |  |  |  |  |  | ######################################################################## | 
| 733 |  |  |  |  |  |  |  | 
| 734 |  |  |  |  |  |  | =head1 Additional Methods | 
| 735 |  |  |  |  |  |  |  | 
| 736 |  |  |  |  |  |  | =head2 click_bind | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | Binds a subroutine to mouse button-1 clicks.  In addition to creating | 
| 739 |  |  |  |  |  |  | the binding, this subroutine is guaranteed to be passed world | 
| 740 |  |  |  |  |  |  | coordinates. (its arguments are: $view, $x, $y) | 
| 741 |  |  |  |  |  |  |  | 
| 742 |  |  |  |  |  |  | $view->click_bind($sub, $button); | 
| 743 |  |  |  |  |  |  |  | 
| 744 |  |  |  |  |  |  | The $button argument is optional, and defaults to 1. | 
| 745 |  |  |  |  |  |  |  | 
| 746 |  |  |  |  |  |  | I advise you to not use 2 if view_bindings() is active. | 
| 747 |  |  |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | =cut | 
| 749 |  |  |  |  |  |  | sub click_bind { | 
| 750 |  |  |  |  |  |  | my $self = shift; | 
| 751 |  |  |  |  |  |  | my ($sub, $num)  = @_; | 
| 752 |  |  |  |  |  |  | $num or ($num = 1); | 
| 753 |  |  |  |  |  |  | (ref($sub) eq "CODE") or croak("cannot bind without code\n"); | 
| 754 |  |  |  |  |  |  | # sorry, no restore method here! | 
| 755 |  |  |  |  |  |  | $self->Tk::bind( | 
| 756 |  |  |  |  |  |  | "" => | 
| 757 |  |  |  |  |  |  | sub { | 
| 758 |  |  |  |  |  |  | my @loc = $self->eventLocation(); | 
| 759 |  |  |  |  |  |  | @loc = $self->world_pt(@loc); | 
| 760 |  |  |  |  |  |  | $sub->($self, @loc); | 
| 761 |  |  |  |  |  |  | } | 
| 762 |  |  |  |  |  |  | ); | 
| 763 |  |  |  |  |  |  | } # end subroutine click_bind definition | 
| 764 |  |  |  |  |  |  | ######################################################################## | 
| 765 |  |  |  |  |  |  |  | 
| 766 |  |  |  |  |  |  | =head2 view_bindings | 
| 767 |  |  |  |  |  |  |  | 
| 768 |  |  |  |  |  |  | Sets-up the wheel-zoom and middle-button pan.  (This over-writes any | 
| 769 |  |  |  |  |  |  | bindings that you have made.) | 
| 770 |  |  |  |  |  |  |  | 
| 771 |  |  |  |  |  |  | $view->view_bindings(); | 
| 772 |  |  |  |  |  |  |  | 
| 773 |  |  |  |  |  |  | =cut | 
| 774 |  |  |  |  |  |  | sub view_bindings { | 
| 775 |  |  |  |  |  |  | my $self = shift; | 
| 776 |  |  |  |  |  |  | $self->Tk::bind('' => sub{ $self->viewAll(); }); | 
| 777 |  |  |  |  |  |  | $self->Tk::bind('<4>' => sub{ | 
| 778 |  |  |  |  |  |  | ## print "zoom in\n"; | 
| 779 |  |  |  |  |  |  | $self->zoom(1.125); | 
| 780 |  |  |  |  |  |  | ## print "zoom in done\n"; | 
| 781 |  |  |  |  |  |  | } | 
| 782 |  |  |  |  |  |  | ); | 
| 783 |  |  |  |  |  |  | $self->Tk::bind('<5>' => sub{ | 
| 784 |  |  |  |  |  |  | $self->zoom(1/1.125); | 
| 785 |  |  |  |  |  |  | } | 
| 786 |  |  |  |  |  |  | ); | 
| 787 |  |  |  |  |  |  | my $pdata = $self->privateData(); | 
| 788 |  |  |  |  |  |  | my @pan_start; | 
| 789 |  |  |  |  |  |  | my $drag_current; | 
| 790 |  |  |  |  |  |  | $self->Tk::bind( | 
| 791 |  |  |  |  |  |  | '' => sub { | 
| 792 |  |  |  |  |  |  | @pan_start = $self->eventLocation(); | 
| 793 |  |  |  |  |  |  | ## print "starting pan at @pan_start\n"; | 
| 794 |  |  |  |  |  |  | }); | 
| 795 |  |  |  |  |  |  | # have to have this here to prevent spurious panning with double-clicks | 
| 796 |  |  |  |  |  |  | $self->Tk::bind('' => sub { | 
| 797 |  |  |  |  |  |  | $drag_current = 1; | 
| 798 |  |  |  |  |  |  | my @pan_stop = $self->eventLocation(); | 
| 799 |  |  |  |  |  |  | my @diff = map({$pan_stop[$_] - $pan_start[$_]} 0,1); | 
| 800 |  |  |  |  |  |  | if(sqrt($diff[0]**2 + $diff[1]**2) > $pdata->{-pandist}) { | 
| 801 |  |  |  |  |  |  | $self->pan(@diff); | 
| 802 |  |  |  |  |  |  | @pan_start = @pan_stop; | 
| 803 |  |  |  |  |  |  | } | 
| 804 |  |  |  |  |  |  |  | 
| 805 |  |  |  |  |  |  | } | 
| 806 |  |  |  |  |  |  | ); | 
| 807 |  |  |  |  |  |  | $self->Tk::bind( | 
| 808 |  |  |  |  |  |  | '' => sub { | 
| 809 |  |  |  |  |  |  | $drag_current || return(); | 
| 810 |  |  |  |  |  |  | my @pan_stop = $self->eventLocation(); | 
| 811 |  |  |  |  |  |  | # my $scale = $self->pixelSize(); | 
| 812 |  |  |  |  |  |  | #            print "\tdouble: $isdouble\n"; | 
| 813 |  |  |  |  |  |  | #            print "\tdrag: $drag_current\n"; | 
| 814 |  |  |  |  |  |  | #            print "scale is $scale\n"; | 
| 815 |  |  |  |  |  |  | #            print "stopping pan at @pan_stop\n"; | 
| 816 |  |  |  |  |  |  | my @diff = map({$pan_stop[$_] - $pan_start[$_]} 0,1); | 
| 817 |  |  |  |  |  |  | #            my $panx = abs($diff[0])/$scale; | 
| 818 |  |  |  |  |  |  | #            my $pany = abs($diff[1])/$scale; | 
| 819 |  |  |  |  |  |  | #            print "pixels: ($panx,$pany)\n"; | 
| 820 |  |  |  |  |  |  | #            my $dopan = ( $panx > 10) | ( $pany > 10); | 
| 821 |  |  |  |  |  |  | #            $dopan && print "panning by @diff\n"; | 
| 822 |  |  |  |  |  |  | #            $dopan && $self->panWorld(@diff); | 
| 823 |  |  |  |  |  |  | $self->pan(@diff); | 
| 824 |  |  |  |  |  |  | $drag_current = 0; | 
| 825 |  |  |  |  |  |  | }); | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  | } # end subroutine view_bindings definition | 
| 828 |  |  |  |  |  |  | ######################################################################## | 
| 829 |  |  |  |  |  |  |  | 
| 830 |  |  |  |  |  |  | =head1 Coordinate System Methods | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | =head2 world_pt | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | Change a canvas coordinate into a world coordinate. | 
| 835 |  |  |  |  |  |  |  | 
| 836 |  |  |  |  |  |  | @w_pt = $view->world_pt(@cnv_pt); | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | =cut | 
| 839 |  |  |  |  |  |  | sub world_pt { | 
| 840 |  |  |  |  |  |  | my $self = shift; | 
| 841 |  |  |  |  |  |  | my (@pt) = @_; | 
| 842 |  |  |  |  |  |  | ## print "start with @pt\n"; | 
| 843 |  |  |  |  |  |  | # print "look at transform effect:", | 
| 844 |  |  |  |  |  |  | # 	join(",", $self->transform($self->group_is(), \@pt)), "\n"; | 
| 845 |  |  |  |  |  |  | # # XXX use scale and movement | 
| 846 |  |  |  |  |  |  | # my $pdata = $self->privateData(); | 
| 847 |  |  |  |  |  |  | # $pdata->{scale} or die("no scale!"); | 
| 848 |  |  |  |  |  |  | # @pt = map({$pt[$_] - $pdata->{move}[$_]} 0,1); | 
| 849 |  |  |  |  |  |  | # print "after move: @pt\n"; | 
| 850 |  |  |  |  |  |  | # # XXX scaling has happened about canvas center | 
| 851 |  |  |  |  |  |  | # @pt = map({$pt[$_] / $pdata->{scale}} 0,1); | 
| 852 |  |  |  |  |  |  | @pt = $self->transform($self->group_is(), \@pt); | 
| 853 |  |  |  |  |  |  | return($pt[0], -$pt[1]); | 
| 854 |  |  |  |  |  |  | } # end subroutine world_pt definition | 
| 855 |  |  |  |  |  |  | ######################################################################## | 
| 856 |  |  |  |  |  |  |  | 
| 857 |  |  |  |  |  |  | =head2 cnv_pt | 
| 858 |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  | Change a world coordinate into a canvas coordinate. | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  | @cnv_pt = $view->cnv_pt(@w_pt); | 
| 862 |  |  |  |  |  |  |  | 
| 863 |  |  |  |  |  |  | =cut | 
| 864 |  |  |  |  |  |  | sub cnv_pt { | 
| 865 |  |  |  |  |  |  | my $self = shift; | 
| 866 |  |  |  |  |  |  | my (@pt) = @_; | 
| 867 |  |  |  |  |  |  | @pt = $self->transform($self->group_is(), 'device', [$pt[0], -$pt[1]]); | 
| 868 |  |  |  |  |  |  | return(@pt); | 
| 869 |  |  |  |  |  |  | } # end subroutine cnv_pt definition | 
| 870 |  |  |  |  |  |  | ######################################################################## | 
| 871 |  |  |  |  |  |  |  | 
| 872 |  |  |  |  |  |  | =head2 eventLocation | 
| 873 |  |  |  |  |  |  |  | 
| 874 |  |  |  |  |  |  | Returns the canvas (x,y) coordinates of the last event. | 
| 875 |  |  |  |  |  |  |  | 
| 876 |  |  |  |  |  |  | my ($x,$y) = $view->eventLocation(); | 
| 877 |  |  |  |  |  |  |  | 
| 878 |  |  |  |  |  |  | =cut | 
| 879 |  |  |  |  |  |  | sub eventLocation { | 
| 880 |  |  |  |  |  |  | my ($canvas) = @_; | 
| 881 |  |  |  |  |  |  | my $ev = $canvas->XEvent; | 
| 882 |  |  |  |  |  |  | return ($ev->x,$ev->y) if defined $ev; | 
| 883 |  |  |  |  |  |  | return; | 
| 884 |  |  |  |  |  |  | } # end subroutine eventLocation definition | 
| 885 |  |  |  |  |  |  | ######################################################################## | 
| 886 |  |  |  |  |  |  |  | 
| 887 |  |  |  |  |  |  | =head2 event_coords | 
| 888 |  |  |  |  |  |  |  | 
| 889 |  |  |  |  |  |  | Returns the world (x,y) coordinates of the last event. | 
| 890 |  |  |  |  |  |  |  | 
| 891 |  |  |  |  |  |  | ($x,$y) = $view->event_coords(); | 
| 892 |  |  |  |  |  |  |  | 
| 893 |  |  |  |  |  |  | =cut | 
| 894 |  |  |  |  |  |  | sub event_coords { | 
| 895 |  |  |  |  |  |  | my $self = shift; | 
| 896 |  |  |  |  |  |  | my ($x,$y) = $self->eventLocation(); | 
| 897 |  |  |  |  |  |  | return($self->world_pt($x,$y)); | 
| 898 |  |  |  |  |  |  | } # end subroutine event_coords definition | 
| 899 |  |  |  |  |  |  | ######################################################################## | 
| 900 |  |  |  |  |  |  |  | 
| 901 |  |  |  |  |  |  | ######################################################################## | 
| 902 |  |  |  |  |  |  |  | 
| 903 |  |  |  |  |  |  | =head2 rubberBand | 
| 904 |  |  |  |  |  |  |  | 
| 905 |  |  |  |  |  |  | almost straight from WorldCanvas | 
| 906 |  |  |  |  |  |  |  | 
| 907 |  |  |  |  |  |  | =cut | 
| 908 |  |  |  |  |  |  | sub rubberBand { | 
| 909 |  |  |  |  |  |  | my ($canvas, $step, $thing) = @_; | 
| 910 |  |  |  |  |  |  |  | 
| 911 |  |  |  |  |  |  | my $pData = $canvas->privateData; | 
| 912 |  |  |  |  |  |  | if($step >= 1 and not defined $pData->{'RubberBand'}) { | 
| 913 |  |  |  |  |  |  | return(); | 
| 914 |  |  |  |  |  |  | } | 
| 915 |  |  |  |  |  |  |  | 
| 916 |  |  |  |  |  |  | my $ev = $canvas->XEvent; | 
| 917 |  |  |  |  |  |  | my $x = $ev->x; | 
| 918 |  |  |  |  |  |  | my $y = $ev->y; | 
| 919 |  |  |  |  |  |  |  | 
| 920 |  |  |  |  |  |  | if ($step == 0) { | 
| 921 |  |  |  |  |  |  | # create anchor for rubberband | 
| 922 |  |  |  |  |  |  | _killBand($canvas); | 
| 923 |  |  |  |  |  |  | $pData->{'RubberBand'} = [$x, $y, $x, $y]; | 
| 924 |  |  |  |  |  |  | } elsif ($step == 1) { | 
| 925 |  |  |  |  |  |  | # update end of rubber band and redraw | 
| 926 |  |  |  |  |  |  | $pData->{'RubberBand'}[2] = $x; | 
| 927 |  |  |  |  |  |  | $pData->{'RubberBand'}[3] = $y; | 
| 928 |  |  |  |  |  |  | _killBand($canvas); | 
| 929 |  |  |  |  |  |  | $thing or ($thing = "rectangle"); | 
| 930 |  |  |  |  |  |  | _makeBand($canvas, $thing); | 
| 931 |  |  |  |  |  |  | } elsif ($step == 2) { | 
| 932 |  |  |  |  |  |  | # step == 2: done | 
| 933 |  |  |  |  |  |  | _killBand($canvas) or return; | 
| 934 |  |  |  |  |  |  |  | 
| 935 |  |  |  |  |  |  | my ($x1, $y1, $x2, $y2) = @{$pData->{'RubberBand'}}; | 
| 936 |  |  |  |  |  |  | undef($pData->{'RubberBand'}); | 
| 937 |  |  |  |  |  |  |  | 
| 938 |  |  |  |  |  |  | return ($x1, $y1, $x2, $y2); | 
| 939 |  |  |  |  |  |  | } | 
| 940 |  |  |  |  |  |  | } | 
| 941 |  |  |  |  |  |  |  | 
| 942 |  |  |  |  |  |  | sub _killBand { | 
| 943 |  |  |  |  |  |  | my ($canvas) = @_; | 
| 944 |  |  |  |  |  |  |  | 
| 945 |  |  |  |  |  |  | my $id = $canvas->privateData->{'RubberBandID'}; | 
| 946 |  |  |  |  |  |  | return 0 if !defined($id); | 
| 947 |  |  |  |  |  |  |  | 
| 948 |  |  |  |  |  |  | $canvas->SUPER::remove($id); | 
| 949 |  |  |  |  |  |  | undef($canvas->privateData->{'RubberBandID'}); | 
| 950 |  |  |  |  |  |  |  | 
| 951 |  |  |  |  |  |  | return 1; | 
| 952 |  |  |  |  |  |  | } | 
| 953 |  |  |  |  |  |  |  | 
| 954 |  |  |  |  |  |  | sub _makeBand { | 
| 955 |  |  |  |  |  |  | my ($canvas, $thing) = @_; | 
| 956 |  |  |  |  |  |  |  | 
| 957 |  |  |  |  |  |  | my $pData = $canvas->privateData; | 
| 958 |  |  |  |  |  |  | my $rb = $pData->{'RubberBand'}; | 
| 959 |  |  |  |  |  |  | die "Error: RubberBand is not defined" if !$rb; | 
| 960 |  |  |  |  |  |  | die "Error: RubberBand does not have 4 values." if @$rb != 4; | 
| 961 |  |  |  |  |  |  |  | 
| 962 |  |  |  |  |  |  | my $crbx1 = $rb->[0]; | 
| 963 |  |  |  |  |  |  | my $crbx2 = $rb->[2]; | 
| 964 |  |  |  |  |  |  | my $crby1 = $rb->[1]; | 
| 965 |  |  |  |  |  |  | my $crby2 = $rb->[3]; | 
| 966 |  |  |  |  |  |  |  | 
| 967 |  |  |  |  |  |  | my $color = $canvas->cget('-bandColor'); | 
| 968 |  |  |  |  |  |  | # print "color: $color\n"; | 
| 969 |  |  |  |  |  |  | # print "points: $crbx1, $crby1, $crbx2, $crbx1\n"; | 
| 970 |  |  |  |  |  |  | $color = '#FF0000'; | 
| 971 |  |  |  |  |  |  | my $id; | 
| 972 |  |  |  |  |  |  | if($thing eq "rectangle") { | 
| 973 |  |  |  |  |  |  | $id = $canvas->add( | 
| 974 |  |  |  |  |  |  | 'rectangle', 1, | 
| 975 |  |  |  |  |  |  | [$crbx1, $crby1, $crbx2, $crby2], | 
| 976 |  |  |  |  |  |  | -linecolor => $color | 
| 977 |  |  |  |  |  |  | ); | 
| 978 |  |  |  |  |  |  | } | 
| 979 |  |  |  |  |  |  | elsif($thing eq "line") { | 
| 980 |  |  |  |  |  |  | $id = $canvas->add( | 
| 981 |  |  |  |  |  |  | 'curve', 1, | 
| 982 |  |  |  |  |  |  | [[$crbx1, $crby1], [$crbx2, $crby2]], | 
| 983 |  |  |  |  |  |  | -linecolor => $color | 
| 984 |  |  |  |  |  |  | ); | 
| 985 |  |  |  |  |  |  | } | 
| 986 |  |  |  |  |  |  | else { | 
| 987 |  |  |  |  |  |  | croak("'thing' must be (currently) rectangle or line\n"); | 
| 988 |  |  |  |  |  |  | } | 
| 989 |  |  |  |  |  |  | $pData->{'RubberBandID'} = $id; | 
| 990 |  |  |  |  |  |  | } | 
| 991 |  |  |  |  |  |  | ######################################################################## | 
| 992 |  |  |  |  |  |  |  | 
| 993 |  |  |  |  |  |  | =head2 bind_on | 
| 994 |  |  |  |  |  |  |  | 
| 995 |  |  |  |  |  |  | Sets all of the bindings specified in %tmp and returns the old | 
| 996 |  |  |  |  |  |  | bindings in %was. | 
| 997 |  |  |  |  |  |  |  | 
| 998 |  |  |  |  |  |  | %was = $view->bind_on(\%tmp); | 
| 999 |  |  |  |  |  |  |  | 
| 1000 |  |  |  |  |  |  | =cut | 
| 1001 |  |  |  |  |  |  | sub bind_on { | 
| 1002 |  |  |  |  |  |  | my $self = shift; | 
| 1003 |  |  |  |  |  |  | my ($tmp) = @_; | 
| 1004 |  |  |  |  |  |  | my %was; | 
| 1005 |  |  |  |  |  |  | my %tmp = %$tmp; | 
| 1006 |  |  |  |  |  |  | foreach my $key (keys(%tmp)) { | 
| 1007 |  |  |  |  |  |  | if(my $sub = $self->Tk::bind($key)) { | 
| 1008 |  |  |  |  |  |  | $was{$key} = $sub; | 
| 1009 |  |  |  |  |  |  | } | 
| 1010 |  |  |  |  |  |  | $self->Tk::bind($key, $tmp{$key}); | 
| 1011 |  |  |  |  |  |  | } | 
| 1012 |  |  |  |  |  |  | return(%was); | 
| 1013 |  |  |  |  |  |  | } # end subroutine bind_on definition | 
| 1014 |  |  |  |  |  |  | ######################################################################## | 
| 1015 |  |  |  |  |  |  |  | 
| 1016 |  |  |  |  |  |  | =head2 bind_off | 
| 1017 |  |  |  |  |  |  |  | 
| 1018 |  |  |  |  |  |  | Replaces the %was bindings and removes any leftover from %tmp. | 
| 1019 |  |  |  |  |  |  |  | 
| 1020 |  |  |  |  |  |  | $view->bind_off(\%tmp, \%was); | 
| 1021 |  |  |  |  |  |  |  | 
| 1022 |  |  |  |  |  |  | =cut | 
| 1023 |  |  |  |  |  |  | sub bind_off { | 
| 1024 |  |  |  |  |  |  | my $self = shift; | 
| 1025 |  |  |  |  |  |  | my ($tmp, $was) = @_; | 
| 1026 |  |  |  |  |  |  | my %tmp = %$tmp; | 
| 1027 |  |  |  |  |  |  | my %was = %$was; | 
| 1028 |  |  |  |  |  |  | foreach my $item (keys(%tmp)) { | 
| 1029 |  |  |  |  |  |  | # print "item: $item\n"; | 
| 1030 |  |  |  |  |  |  | if($was{$item}) { | 
| 1031 |  |  |  |  |  |  | $self->Tk::bind($item => $was{$item}); | 
| 1032 |  |  |  |  |  |  | } | 
| 1033 |  |  |  |  |  |  | else { | 
| 1034 |  |  |  |  |  |  | $self->Tk::bind($item => ""); | 
| 1035 |  |  |  |  |  |  | } | 
| 1036 |  |  |  |  |  |  | } | 
| 1037 |  |  |  |  |  |  | } # end subroutine bind_off definition | 
| 1038 |  |  |  |  |  |  | ######################################################################## | 
| 1039 |  |  |  |  |  |  |  | 
| 1040 |  |  |  |  |  |  | =head1 Functions | 
| 1041 |  |  |  |  |  |  |  | 
| 1042 |  |  |  |  |  |  | =head2 addr_to_tag | 
| 1043 |  |  |  |  |  |  |  | 
| 1044 |  |  |  |  |  |  | $tag = addr_to_tag($n, $addr); | 
| 1045 |  |  |  |  |  |  |  | 
| 1046 |  |  |  |  |  |  | =cut | 
| 1047 |  |  |  |  |  |  | sub addr_to_tag { | 
| 1048 |  |  |  |  |  |  | my ($n, $addr) = @_; | 
| 1049 |  |  |  |  |  |  | my $tag = join(":", | 
| 1050 |  |  |  |  |  |  | $n, | 
| 1051 |  |  |  |  |  |  | $addr->{type}, | 
| 1052 |  |  |  |  |  |  | $addr->{id}, | 
| 1053 |  |  |  |  |  |  | $addr->{layer} | 
| 1054 |  |  |  |  |  |  | ); | 
| 1055 |  |  |  |  |  |  | return($tag); | 
| 1056 |  |  |  |  |  |  | } # end subroutine addr_to_tag definition | 
| 1057 |  |  |  |  |  |  | ######################################################################## | 
| 1058 |  |  |  |  |  |  |  | 
| 1059 |  |  |  |  |  |  | =head2 tag_to_addr | 
| 1060 |  |  |  |  |  |  |  | 
| 1061 |  |  |  |  |  |  | ($n, $addr) = tag_to_addr($tag); | 
| 1062 |  |  |  |  |  |  |  | 
| 1063 |  |  |  |  |  |  | =cut | 
| 1064 |  |  |  |  |  |  | sub tag_to_addr { | 
| 1065 |  |  |  |  |  |  | } # end subroutine tag_to_addr definition | 
| 1066 |  |  |  |  |  |  | ######################################################################## | 
| 1067 |  |  |  |  |  |  |  | 
| 1068 |  |  |  |  |  |  | 1; |