File Coverage

lib/PDF/Boxer/Content/Box.pm
Criterion Covered Total %
statement 6 122 4.9
branch 0 54 0.0
condition 0 17 0.0
subroutine 2 11 18.1
pod 3 9 33.3
total 11 213 5.1


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