File Coverage

lib/PDF/Boxer/Content/Box.pm
Criterion Covered Total %
statement 6 103 5.8
branch 0 44 0.0
condition 0 8 0.0
subroutine 2 11 18.1
pod 3 9 33.3
total 11 175 6.2


line stmt bran cond sub pod time code
1             package PDF::Boxer::Content::Box;
2             {
3             $PDF::Boxer::Content::Box::VERSION = '0.001'; # TRIAL
4             }
5 3     3   20 use Moose;
  3         6  
  3         21  
6             # ABSTRACT: a box
7              
8 3     3   18290 use Scalar::Util qw/weaken/;
  3         6  
  3         3042  
9              
10             has 'debug' => ( isa => 'Bool', is => 'ro', default => 0 );
11              
12             has 'margin' => ( isa => 'ArrayRef', is => 'ro', default => sub{ [0,0,0,0] } );
13              
14             has 'border' => ( isa => 'ArrayRef', is => 'ro', default => sub{ [0,0,0,0] } );
15              
16             has 'padding' => ( isa => 'ArrayRef', is => 'ro', default => sub{ [0,0,0,0] } );
17              
18             has 'children' => ( isa => 'ArrayRef', is => 'rw', default => sub{ [] } );
19              
20              
21             with 'PDF::Boxer::Role::SizePosition'; #, 'PDF::Boxer::Role::BoxDev';
22              
23              
24             has 'boxer' => ( isa => 'PDF::Boxer', is => 'ro' );
25              
26             has 'parent' => ( isa => 'Object', is => 'ro' );
27              
28             has 'name' => ( isa => 'Str', is => 'ro' );
29              
30             has 'type' => ( isa => 'Str', is => 'ro', default => 'Box' );
31              
32             has 'background' => ( isa => 'Str', is => 'ro' );
33              
34             has 'border_color' => ( isa => 'Str', is => 'ro' );
35              
36             has 'font' => ( isa => 'Str', is => 'ro', default => 'Helvetica' );
37              
38             has 'align' => ( isa => 'Str', is => 'ro', default => '' );
39              
40             sub BUILDARGS{
41 0     0 1   my ($class, $args) = @_;
42              
43 0           foreach my $attr (qw! margin border padding !){
44 0 0         next unless exists $args->{$attr};
45 0           my $arg = $args->{$attr};
46 0 0         if (ref($arg)){
47 0 0         unless (ref($arg) eq 'ARRAY'){
48 0           die "Arg to $attr must be string or array reference";
49             }
50             } else {
51 0           $arg = [split(/\s+/, $arg)];
52             }
53 0           my $val = [$arg->[0]];
54 0 0         $val->[1] = defined $arg->[1] ? $arg->[1] : $val->[0];
55 0 0         $val->[2] = defined $arg->[2] ? $arg->[2] : $val->[0];
56 0 0         $val->[3] = defined $arg->[3] ? $arg->[3] : $val->[1];
57              
58 0           $args->{$attr} = $val;
59             }
60              
61 0           return $args;
62             }
63              
64             sub BUILD{
65 0     0 0   my ($self) = @_;
66 0 0         unless($self->parent){
67 0           $self->adjust({
68             margin_top => $self->boxer->max_height,
69             margin_left => 0,
70             margin_width => $self->boxer->max_width,
71             margin_height => $self->boxer->max_height,
72             },'self');
73             }
74              
75 0           foreach my $child (@{$self->children}){
  0            
76 0           $child->{boxer} = $self->boxer;
77 0           $child->{debug} = $self->debug;
78 0   0       $child->{font} ||= $self->font;
79 0   0       $child->{align} ||= $self->align;
80 0           my $weak_me = $self;
81 0           weaken($weak_me);
82 0           $child->{parent} = $weak_me;
83 0           my $class = 'PDF::Boxer::Content::'.$child->{type};
84 0           $child = $class->new($child);
85 0           $self->boxer->register_box($child);
86             }
87              
88             }
89              
90             sub propagate{
91 0     0 0   my ($self, $method, $args) = @_;
92 0 0         return unless $method;
93 0           my @kids = @{$self->children};
  0            
94 0 0         if (@kids){
95 0           foreach my $kid (@kids){
96 0           $kid->$method($args);
97             }
98             }
99 0           return @kids;
100             }
101              
102             # initialize objects with default sizes
103             # - text gets width of widest line and height of all lines (wrapped at page width)
104             # - images get their scaled size
105             # - rows get the height of their tallest child and the width of all of them
106             # - columns get the width of their widest child and the height of all of them
107             # - grids (same as columns)
108             # - box gets the width of all it's kids (wrapped at page width) and the height of the line of kids
109              
110             # if text or box are too wide they need to be resized and they're contents re-wrapped.
111             # this may result in their height increasing which needs to be communicated to their parent.
112             # the parent can then adjust itself accordingly.
113              
114              
115             sub initialize{
116 0     0 1   my ($self) = @_;
117              
118 0           my @kids = $self->propagate('initialize');
119              
120 0 0         $self->update unless $self->parent;
121              
122             # the main box should stay wide open.
123 0 0         return unless $self->parent;
124              
125 0           my ($width, $height) = $self->get_default_size;
126              
127 0           $self->set_width($width);
128 0           $self->set_height($height);
129              
130 0           return 1;
131             }
132              
133              
134             # we get our size from the children
135             sub get_default_size{
136 0     0 1   my ($self) = @_;
137 0           my ($width, $height) = (0,0);
138 0           my $kids = $self->children;
139 0 0         if (@$kids){
140 0           my ($widest, $highest, $x, $y) = (0, 0, 0);
141 0           foreach(@$kids){
142 0 0         $highest = $_->margin_height if $_->margin_height > $highest;
143 0 0         if ($width + $_->margin_width > $self->boxer->max_width){
144 0           $height += $highest;
145 0           $highest = 0;
146 0 0         $widest = $width if $width > $widest;
147             } else {
148 0           $width += $_->margin_width;
149             }
150 0 0         $width = $width ? (sort($_->margin_width,$width))[1] : $_->margin_width;
151             }
152 0           $height += $highest;
153             }
154 0           return ($width, $height);
155             }
156              
157             sub update{
158 0     0 0   my ($self) = @_;
159 0           $self->update_children;
160 0           return 1;
161             }
162              
163       0 0   sub child_adjusted_height{}
164              
165             sub update_children{
166 0     0 0   my ($self) = @_;
167 0 0         if ($self->position_set){
168 0           my $kids = $self->children;
169 0 0         if (@$kids){
170 0           my ($highest, $x, $y) = (0, $self->content_left, $self->content_top);
171 0           foreach my $kid (@$kids){
172 0 0         $highest = $kid->margin_height if $kid->margin_height > $highest;
173 0 0         if ($x + $kid->margin_width > $self->width){
174 0           $kid->move($x,$y);
175 0           $y -= $highest;
176 0           $highest = 0;
177 0           $x = $self->content_left;
178             } else {
179 0           $kid->move($x,$y);
180 0           $x += $kid->margin_width;
181             }
182             }
183             }
184             }
185             }
186              
187             sub render{
188 0     0 0   my ($self) = @_;
189              
190 0           my $gfx = $self->boxer->doc->gfx;
191              
192 0 0         if ($self->background){
193 0           $gfx->fillcolor($self->background);
194 0           $gfx->rect($self->border_left, $self->border_top, $self->border_width, -$self->border_height);
195 0           $gfx->fill;
196             }
197              
198             # === Need to change to respect all border sides sizes ===
199             # increasing linewidth thickens the border "around" the lines of the rectangle.
200             # we want to thinken "inside" the rectangle..
201 0 0         if (my $width = $self->border->[0]){
202 0           $gfx->linewidth(1);
203 0   0       $gfx->strokecolor($self->border_color || 'black');
204 0           my ($bl,$bt,$bw,$bh) = ($self->border_left, $self->border_top, $self->border_width, $self->border_height);
205 0           foreach(1..$width){
206 0           $gfx->rect($bl,$bt,$bw,-$bh);
207 0           $gfx->stroke;
208 0           $bl++; $bt--;
  0            
209 0           $bw -= 2;
210 0           $bh -= 2;
211             }
212             }
213              
214 0           foreach(@{$self->children}){
  0            
215 0           $_->render;
216             }
217              
218             }
219              
220              
221             __PACKAGE__->meta->make_immutable;
222              
223             1;
224              
225             __END__
226             =pod
227              
228             =head1 NAME
229              
230             PDF::Boxer::Content::Box - a box
231              
232             =head1 VERSION
233              
234             version 0.001
235              
236             =head1 ATTRIBUTES
237              
238             =head2 debug
239              
240             set true to turn on debugging
241              
242             =head2 margin
243              
244             Arrayref containing the size of the margin on each side of the box.
245             (top, right, bottom, left)
246              
247             =head2 border
248              
249             Arrayref containing the size of the border on each side of the box.
250             (top, right, bottom, left)
251              
252             =head2 padding
253              
254             Arrayref containing the size of the padding on each side of the box.
255             (top, right, bottom, left)
256              
257             =head2 children
258              
259             Arrayref of boxes contained in this box.
260              
261             =head2 boxer
262              
263             the Boxer object.
264              
265             =head2 parent
266              
267             The box we are in.
268              
269             =head2 name
270              
271             The name of this box. Access boxes through the box register using this.
272              
273             =head2 type
274              
275             The type of this box. eg text, row, column
276              
277             =head2 background
278              
279             The background color of this box. (hex string or name)
280              
281             =head2 border_color
282              
283             The border color of this box. (hex string or name)
284              
285             =head2 font
286              
287             Non-text boxes will pass this to their children.
288              
289             =head2 align
290              
291             The alignment of this box (text string; right or center)
292             No align means left.
293              
294             =head1 METHODS
295              
296             =head2 initialize
297              
298             Set the width & height for the box and call initialize on children
299              
300             =head2 get_default_size
301              
302             Returns the default width and height for this box.
303              
304             =head1 AUTHOR
305              
306             Jason Galea <lecstor@cpan.org>
307              
308             =head1 COPYRIGHT AND LICENSE
309              
310             This software is copyright (c) 2011 by Jason Galea.
311              
312             This is free software; you can redistribute it and/or modify it under
313             the same terms as the Perl 5 programming language system itself.
314              
315             =cut
316