File Coverage

blib/lib/Data/Region.pm
Criterion Covered Total %
statement 126 126 100.0
branch 16 18 88.8
condition n/a
subroutine 20 20 100.0
pod 17 17 100.0
total 179 181 98.9


line stmt bran cond sub pod time code
1             package Data::Region;
2 3     3   116795 use strict;
  3         8  
  3         9155  
3              
4             our $VERSION = '1.0';
5             our $REVISION = '$Id: Region.pm,v 1.5 2002/11/09 02:32:19 gdf Exp $ ';
6              
7              
8             # Reading the perldoc at the end is probably a better place to start
9             # than reading these inline comments...
10              
11             our @_Keys = qw( warnings data );
12              
13             sub new {
14 150     150 1 4217 my $class = shift;
15 150         330 my $self = bless {}, $class;
16 150         301 $self->_init(@_);
17 150         294 return $self;
18             }
19              
20             #
21             # warnings => if true, bounds errors generate gripes
22             # data => ref to some random data to associate with this region
23             # x =>
24             # y => specify top left corner (defaults to 0,0)
25             #
26             # coords start from top left, and proceed to lower right
27             #
28             sub _init {
29 150     150   162 my $self = shift;
30 150         175 my( $w, $h, $opt ) = @_;
31              
32 150 100       319 my $x = (defined($opt->{x}) ? $opt->{x} : 0);
33 150 100       265 my $y = (defined($opt->{y}) ? $opt->{y} : 0);
34              
35             #w; warn "DIAG Creating $w x $h @ ($x, $y)\n";
36 150         533 $self->{tl} = [$x,$y];
37 150         374 $self->{br} = [$x+$w,$y+$h];
38 150         282 $self->{_kids} = [];
39 150         489 $self->{_calls} = [];
40              
41 150         207 foreach my $k (@_Keys) {
42 300         720 $self->{$k} = $opt->{$k};
43             }
44             }
45              
46             # Returns a list of sub-areas, tiled vertically into $self,
47             # where each successive area has a height given by the list of args.
48             # A final area will be returned comprising the remaining height of $self,
49             # if the arguments do not entirely fill $self.
50             # eg, if $self->height()==13, then
51             # @a = $self->split_vertical( 2, 5, 1 );
52             # $a[0]->height() == 2 # y=[0..2]
53             # $a[1]->height() == 5 # y=[2..7]
54             # $a[2]->height() == 1 # y=[7..8]
55             # $a[3]->height() == 5 # y=[8..13], ie all the rest of $self
56             #
57             sub split_vertical {
58 1     1 1 14 my $self = shift;
59 1         4 my( @offs ) = @_;
60 1         2 my @ret;
61              
62 1         6 my($x,$w) = ($self->{tl}->[0], ($self->{br}->[0] - $self->{tl}->[0]));
63 1         2 my $yc = $self->{tl}->[1];
64 1         9 for( my $i=0; $i<@offs; $i++ ) {
65 3         10 push( @ret, $self->_spawn($x,$yc, $w, $offs[$i]) );
66 3         11 $yc += $offs[$i];
67             }
68 1 50       6 if ( $yc < $self->{br}->[1] ) { # any area of $self left?
69 1         4 push( @ret, $self->_spawn($x,$yc, $w, ($self->{br}->[1]-$yc)) );
70             }
71 1         78 return @ret;
72              
73             }
74              
75              
76             sub split_horizontal {
77 1     1 1 8 my $self = shift;
78 1         4 my( @offs ) = @_;
79 1         3 my @ret;
80              
81 1         5 my($y,$h) = ($self->{tl}->[1], ($self->{br}->[1] - $self->{tl}->[1]));
82 1         3 my $xc = $self->{tl}->[0];
83 1         6 for( my $i=0; $i<@offs; $i++) {
84 3         8 push(@ret, $self->_spawn($xc,$y, $offs[$i],$h) );
85 3         9 $xc+=$offs[$i];
86             }
87 1 50       696 if ( $xc < $self->{br}->[0] ) {
88 1         6 push(@ret, $self->_spawn($xc,$y, ($self->{br}->[0]-$xc),$h) );
89             }
90 1         11 return @ret;
91             }
92              
93             # returns list of sub-areas, tiled vertically into $self,
94             # with successive Y coordinates given by @stops
95             sub split_vertical_abs {
96 1     1 1 8 my $self = shift;
97 1         3 my( @stops ) = @_;
98 1         3 my @ret;
99              
100 1         4 my($x,$w) = ($self->{tl}->[0], ($self->{br}->[0] - $self->{tl}->[0]));
101 1         5 for( my $i=0; $i<@stops; $i++ ) {
102 3         5 my $yc = $stops[$i];
103 3         4 my $nexty = $stops[$i+1];
104 3 100       9 $nexty = $self->{br}->[1] unless defined($nexty);
105 3         5 my $hc = $nexty-$yc;
106 3         8 push(@ret, $self->_spawn($x,$yc, $w,$hc));
107             }
108 1         10 return @ret;
109             }
110              
111             # returns list of sub-areas, tiled horizontally into $self,
112             # with successive X coordinates given by @stops
113             # XXX rename this split_horizontal_abs, and create a non-abs one
114             sub split_horizontal_abs {
115 1     1 1 24 my $self = shift;
116 1         4 my( @stops ) = @_;
117 1         2 my @ret;
118              
119 1         3 my($y, $h) = ($self->{tl}->[1], ($self->{br}->[1] - $self->{tl}->[1]));
120 1         6 for( my $i=0; $i<@stops; $i++) {
121 3         4 my $xc = $stops[$i];
122 3         4 my $nextx = $stops[$i+1];
123             # last area fills to the right
124 3 100       8 $nextx = $self->{br}->[0] unless defined($nextx);
125 3         4 my $wc = ($nextx-$xc);
126 3         6 push(@ret, $self->_spawn($xc,$y, $wc,$h));
127             }
128 1         8 return @ret;
129             }
130              
131              
132             # returns a list of new regions tiled into this one, with the given size
133             # may not fill this entire region (only whole regions will be created)
134             sub subdivide {
135 2     2 1 19 my $self = shift;
136 2         17 my( $w, $h ) = @_;
137 2         6 my @ret = ();
138              
139             #w; warn "DIAG entering subd\n";
140              
141 2         4 my($xc,$yc) = @{$self->{tl}};
  2         6  
142 2         11 while( $yc+$h <= $self->{br}->[1] ) {
143 13         33 while( $xc+$w <= $self->{br}->[0] ) {
144 109         235 push(@ret, $self->_spawn($xc,$yc,$w,$h));
145 109         295 $xc += $w;
146             }
147 13         18 $xc = $self->{tl}->[0];
148 13         33 $yc += $h;
149             }
150              
151 2         32 return @ret;
152             }
153              
154             # returns new region with coords relative to this one
155             sub area {
156 16     16 1 452 my $self = shift;
157 16         25 my( $x1,$y1, $x2,$y2 ) = @_;
158              
159             #w; warn "DIAG entering area ( $x1,$y1, $x2,$y2 )\n";
160              
161 16         44 my( $x,$y ) = ( $self->{tl}->[0]+$x1, $self->{tl}->[1]+$y1 );
162             #w; warn "DIAG tl corner = ($x,$y)\n";
163             # allow second (x,y) to be negative (=back off from br corner)
164 16         18 my( $brx, $bry );
165 16 100       31 if ( $x2<0 ) {
166 14         25 $brx = $self->{br}->[0] + $x2;
167             } else {
168 2         3 $brx = $self->{tl}->[0] + $x2;
169             }
170 16 100       30 if ( $y2<0 ) {
171 14         25 $bry = $self->{br}->[1] + $y2;
172             } else {
173 2         2 $bry = $self->{tl}->[1] + $y2;
174             }
175             #w; warn "DIAG br corner = ($x2,$y2)\n";
176 16         26 my( $w,$h ) = ( $brx-$x, $bry-$y );
177              
178             # should warn here if warnings on and this w/h > $self->w/h
179             # or if the tlc>brc
180              
181 16         38 return $self->_spawn($x,$y,$w,$h);
182             }
183              
184              
185             # _spawn( $x,$y, $w,$h );
186             # x, y absolute
187             sub _spawn {
188 139     139   154 my $self = shift;
189 139         182 my( $x,$y,$w,$h ) = @_;
190              
191 139         494 my $new = ref($self)->new( $w,$h, {x=>$x, y=>$y} );
192 139         270 foreach my $k (@_Keys) { # inherit parent's attributes
193 278         501 $new->{$k} = $self->{$k};
194             }
195 139         159 push(@{$self->{_kids}}, $new);
  139         247  
196 139         260 return $new;
197             }
198              
199              
200             # returns the coords of the top left, bottom right corners of this region
201             sub coords {
202 28     28 1 6523 my $self = shift;
203 28         34 return (@{$self->{tl}}, @{$self->{br}});
  28         58  
  28         86  
204             }
205              
206             sub width {
207 1     1 1 396 my $self = shift;
208 1         5 return $self->{br}->[0] - $self->{tl}->[0];
209             }
210              
211             sub height {
212 1     1 1 2 my $self = shift;
213 1         7 return $self->{br}->[1] - $self->{tl}->[1];
214             }
215              
216             sub top_left {
217 1     1 1 2 my $self = shift;
218 1         3 return @{$self->{tl}};
  1         6  
219             }
220              
221             sub top_right {
222 1     1 1 640 my $self = shift;
223 1         10 return ($self->{br}->[0], $self->{tl}->[1]);
224             }
225              
226             sub bottom_right {
227 1     1 1 410 my $self = shift;
228 1         3 return @{$self->{br}};
  1         6  
229             }
230              
231             sub bottom_left {
232 1     1 1 399 my $self = shift;
233 1         6 return ($self->{tl}->[0], $self->{br}->[1]);
234             }
235              
236             sub data {
237 15     15 1 477 my $self = shift;
238 15 100       33 if (defined(my $arg = shift)) {
239 1         4 return $self->{data} = $arg;
240             } else {
241 14         49 return $self->{data};
242             }
243             }
244              
245             sub action {
246 12     12 1 87 my $self = shift;
247 12         16 my $subref = shift;
248              
249 12         10 push( @{$self->{_calls}}, $subref );
  12         64  
250             }
251              
252             sub render {
253 22     22 1 31 my $self = shift;
254              
255 22         21 foreach my $s (@{$self->{_calls}}) {
  22         42  
256 12         29 $s->($self);
257             }
258 22         161 foreach my $child (@{$self->{_kids}}) {
  22         57  
259 20         43 $child->render();
260             }
261             }
262              
263              
264             1;
265             __END__