File Coverage

blib/lib/Grid/Layout.pm
Criterion Covered Total %
statement 174 178 97.7
branch 36 60 60.0
condition 4 6 66.6
subroutine 31 31 100.0
pod 1 15 6.6
total 246 290 84.8


line stmt bran cond sub pod time code
1             #_{ Encoding and name
2             =encoding utf8
3             =head1 NAME
4              
5             Grid::Layout - Create grid based layouts.
6              
7             =cut
8             #_}
9             package Grid::Layout;
10             #_{ use …
11 5     5   278906 use warnings;
  5         11  
  5         156  
12 5     5   27 use strict;
  5         10  
  5         88  
13 5     5   1668 use utf8;
  5         60  
  5         21  
14              
15 5     5   128 use Carp;
  5         8  
  5         241  
16              
17 5     5   1149 use Grid::Layout::Area;
  5         39  
  5         123  
18 5     5   1079 use Grid::Layout::Cell;
  5         11  
  5         116  
19 5     5   1544 use Grid::Layout::Line;
  5         10  
  5         116  
20 5     5   1177 use Grid::Layout::Track;
  5         8  
  5         6959  
21             #_}
22             our $VERSION = 0.02;
23             #_{ Synopsis
24              
25             =head1 SYNOPSIS
26              
27             =cut
28             #_}
29             #_{ Description
30              
31             =head1 DESCRIPTION
32             =cut
33             #_}
34             #_{ Methods
35             #_{ POD
36             =head1 METHODS
37             =cut
38             #_}
39             sub new { #_{
40             #_{ POD
41             =head2 new
42              
43             use Grid::Layout;
44              
45             my $gl = Grid::Layout->new();
46              
47             =cut
48             #_}
49              
50 5     5 0 273 my $class = shift;
51              
52 5         11 my $self = {};
53              
54 5         11 bless $self, $class;
55              
56 5         20 $self->_init_V_or_H('V');
57 5         14 $self->_init_V_or_H('H');
58              
59 5         10 $self->{cells} = [];
60              
61 5         14 return $self;
62              
63             } #_}
64             sub _init_V_or_H { #_{
65             #_{ POD
66             =head2 _init_V_or_H
67              
68             $self->_init_V_or_H('V');
69             $self->_init_V_or_H('H');
70              
71             This method is called by L twice to initialize the vertical and the horizontal components of the layout.
72              
73             The parameter C<'V'> or C<'H'> indiciates which componenents to initialize.
74              
75             =cut
76             #_}
77              
78 10     10   17 my $self = shift;
79 10         17 my $V_or_H = shift;
80              
81 10         39 $self->{$V_or_H}{tracks} = [];
82 10         21 $self->{$V_or_H}{lines } = [];
83              
84             # A grid consists of at least one vertical and a horizontal line:
85 10         25 $self->_add_line($V_or_H);
86              
87             } #_}
88             #_{ add-…-track
89             sub add_vertical_track { #_{
90             #_{ POD
91             =head2 add_vertical_track
92              
93             my $track_v = $gl->add_vertical_track(…);
94             my ($track_v, $line_v) = $gl->add_vertical_track(…);
95              
96             Adds a L<< vertical track|Grid::Layout::Track >> on the right side of the grid and returns it.
97              
98             If called in I, it returns the newly created L and L.
99             Otherwise, it returns the newly created L.
100              
101             =cut
102             #_}
103 22     22 0 3000 my $self = shift;
104              
105 22         49 my $x = $self->size_x();
106 22         38 for my $y (0 .. $self->size_y() -1) {
107 65         95 $self->_add_cell($x, $y);
108             }
109              
110 22         39 return $self->_add_track('V');
111              
112             } #_}
113             sub add_horizontal_track { #_{
114             #_{ POD
115             =head2 add_horizontal_track
116              
117             my $track_h = $gl->add_horizontal_track(…);
118             my ($track_h, $line_h) = $gl->add_horizontal_track(…);
119              
120             Adds a L<< horizontal track|Grid::Layout::Track >> at the bottom of the grid and returns it.
121              
122             If called in I, it returns the newly created L and L.
123             Otherwise, it returns the newly created L.
124              
125             =cut
126             #_}
127 22     22 0 3840 my $self = shift;
128              
129 22         39 my $y = $self->size_y;
130 22         39 for my $x (0 .. $self->size_x()-1) {
131 71         108 $self->_add_cell($x, $y);
132             }
133              
134 22         61 return ($self->_add_track('H'));
135              
136             } #_}
137             #_}
138             sub get_horizontal_line { #_{
139             #_{ POD
140             =head2 new
141              
142             my $logical_width = 5;
143             my $fourth_horizontal_line = $gl->get_horizontal_line($logical_width);
144              
145             Returns the horizontal line that is C<< $logical_width >> units from the I<< zero-line >> apart.
146              
147             =cut
148             #_}
149              
150 1     1 0 4 my $self = shift;
151 1         2 my $position = shift;
152              
153 1         2 return $self->_get_line('H', $position);
154              
155             } #_}
156             sub get_vertical_line { #_{
157             #_{ POD
158             =head2 new
159              
160             my $logical_width = 4;
161             my $third_horizontal_line = $gl->get_horizontal_line($logical_width);
162              
163             Returns the vertical line that is C<< $logical_width >> units from the I<< zero-line >> apart.
164              
165             =cut
166             #_}
167            
168 1     1 0 2123 my $self = shift;
169 1         2 my $position = shift;
170 1         4 return $self->_get_line('V', $position);
171              
172             } #_}
173             sub _get_line { #_{
174 2     2   4 my $self = shift;
175 2         2 my $V_or_H = shift;
176 2         3 my $position = shift;
177              
178 2         2 return ${$self->{$V_or_H}{lines}}[$position];
  2         6  
179              
180             } #_}
181             sub add_horizontal_line { #_{
182             #_{ POD
183             =head2 add_horizontal_line
184              
185             my $new_line = $gl->add_horizontal_line(…);
186             my ($new_line, $new_track) = $gl->add_horizontal_line(…);
187              
188             Adds a horizontal L<< line|Grid::Layout::Line >> (and by implication also a horizontal
189             L<< track||Grid::Layout::Track >>).
190              
191             If called in list contect, it returns both, if called in scalar contect, it returns the
192             new line only.
193              
194             =cut
195             #_}
196              
197 11     11 0 35 my $self = shift;
198              
199 11         21 my ($new_track, $new_line) = $self->add_horizontal_track(@_);
200              
201 11 50       64 return $new_line, $new_track if wantarray;
202 11         22 return $new_line;
203              
204             } #_}
205             sub add_vertical_line { #_{
206             #_{ POD
207             =head2 add_vertical_line
208              
209             my $new_line = $gl->add_vertical_line(…);
210             my ($new_line, $new_track) = $gl->add_vertical_line(…);
211              
212             Adds a vertical L<< line|Grid::Layout::Line >> (and by implication also a vertical
213             L<< track||Grid::Layout::Track >>).
214              
215             If called in list contect, it returns both, if called in scalar contect, it returns the
216             new line only.
217              
218             =cut
219             #_}
220 12     12 0 45 my $self = shift;
221              
222 12         25 my ($new_track, $new_line) = $self->add_vertical_track(@_);
223              
224 12 50       22 return $new_line, $new_track if wantarray;
225 12         25 return $new_line;
226             } #_}
227             sub _add_track { #_{
228             #_{ POD
229             =head2 _add_track
230              
231             my $track = $gl->_add_track($V_or_H);
232              
233             Internal function. Returns a vertical or horizontal L<< track|Grid::Layout::Track >>, depending on the value of C<< $V_or_H >> (whose should be either C<'V'> or C<'H'>).
234              
235             =cut
236             #_}
237              
238 44     44   52 my $self = shift;
239 44         83 my $V_or_H = shift;
240              
241 44         64 my $new_track = Grid::Layout::Track->new($self, $V_or_H, scalar @{$self->{$V_or_H}->{tracks}});
  44         128  
242              
243             # $self->_add_line($V_or_H) unless @{$self->{$V_or_H}->{tracks}}; # An extra line (the first one) needs to be added for the first vertical and horizontal track.
244 44         74 my $new_line = $self->_add_line($V_or_H);
245              
246 44         56 push @{$self->{$V_or_H}{tracks}}, $new_track;
  44         65  
247              
248 44 100       103 return ($new_track, $new_line) if wantarray;
249 18         34 return $new_track;
250              
251             } #_}
252             sub _add_line { #_{
253             #_{ POD
254             =head2 _add_line
255              
256             $self->_add_line($V_or_H);
257              
258             Internal function, called by L, to add a vertical or horizontal L<< Grid::Layout::Line >>.
259              
260             =cut
261             #_}
262              
263 54     54   70 my $self = shift;
264 54         68 my $V_or_H = shift;
265              
266             # print "\n\n ***\n ", scalar @{$self->{$V_or_H}->{lines}}, "\n\n *****\n";
267              
268 54         62 my $new_line = Grid::Layout::Line->new($self, $V_or_H, scalar @{$self->{$V_or_H}->{lines}});
  54         145  
269              
270 54         70 push @{$self->{$V_or_H}->{lines}}, $new_line;
  54         98  
271              
272 54         77 return $new_line;
273              
274             } #_}
275             sub area { #_{
276             #_{ POD
277             =head2 area
278              
279             $gl->area(…)
280              
281             Create an L<< area|Grid::Layout::Area >>
282              
283             =head3 creating an area from lines
284              
285             my $vertical_line_from = $gl->add_vertical_line(…);
286             my $horizontal_line_from = $gl->add_vertical_line(…);
287              
288             my $vertical_line_to = $gl->add_vertical_line(…);
289             my $horizontal_line_to = $gl->add_vertical_line(…);
290              
291             my $area = $gl->area (
292             $vertical_line_from, $horizontal_line_from,
293             $vertical_line_to ,$horizontal_line_to
294             );
295              
296             =head3 creating an area from tracks
297              
298             my $vertical_track_from = $gl->add_vertical_track(…);
299             my $horizontal_track_from = $gl->add_vertical_track(…);
300              
301             my $vertical_track_to = $gl->add_vertical_track(…);
302             my $horizontal_track_to = $gl->add_vertical_track(…);
303              
304             my $area = $gl->area($vertical_track_from, $horizontal_track_from, $vertical_track_to, $vertical_track_to);
305              
306              
307             Define an L<< area|Grid::Layout::Area >> bound by the four tracks. Both the from and the to tracks are included.
308              
309             An area that lies on only I L<< track|Grid::Layout::Track >> can be created with
310             L<< Grid::Layout::Track/area >>.
311              
312             =cut
313             #_}
314            
315 12     12 1 3302 my $self = shift;
316              
317 12 100       48 if ($_[0]->isa('Grid::Layout::Track')) { #_{
    50          
318              
319 10         16 my $track_v_from = shift;
320 10         12 my $track_h_from = shift;
321 10         13 my $track_v_to = shift;
322 10         14 my $track_h_to = shift;
323            
324 10 50       27 croak 'track_v_from is not a Grid::Layout::Track' unless $track_v_from->isa('Grid::Layout::Track');
325 10 50       23 croak 'track_v_to is not a Grid::Layout::Track' unless $track_v_to ->isa('Grid::Layout::Track');
326 10 50       23 croak 'track_h_from is not a Grid::Layout::Track' unless $track_h_from->isa('Grid::Layout::Track');
327 10 50       25 croak 'track_h_to is not a Grid::Layout::Track' unless $track_h_to ->isa('Grid::Layout::Track');
328            
329 10 50       20 croak 'track_v_from is not a vertical' unless $track_v_from->{V_or_H} eq 'V';
330 10 50       24 croak 'track_v_to is not a vertical' unless $track_v_to ->{V_or_H} eq 'V';
331 10 50       16 croak 'track_h_from is not a vertical' unless $track_h_from->{V_or_H} eq 'H';
332 10 50       17 croak 'track_h_to is not a vertical' unless $track_h_to ->{V_or_H} eq 'H';
333            
334 10         23 for my $x ($track_v_from->{position} .. $track_v_to->{position}) {
335 23         42 for my $y ($track_h_from->{position} .. $track_h_to->{position}) {
336 39 100       57 if ($self->cell($x, $y)->{area}) {
337 1         16 croak "cell $x/$y already belongs to an area";
338             }
339             }}
340            
341 9         34 my $area = Grid::Layout::Area->new($track_v_from, $track_h_from, $track_v_to, $track_h_to);
342            
343 9         18 for my $x ($track_v_from->{position} .. $track_v_to->{position}) {
344 20         32 for my $y ($track_h_from->{position} .. $track_h_to->{position}) {
345 36         51 $self->cell($x, $y)->{area}= $area;
346             }}
347              
348 9         28 return $area;
349             } #_}
350             elsif ($_[0]->isa('Grid::Layout::Line')) { #_{
351              
352 2         3 my $line_v_from = shift;
353 2         2 my $line_h_from = shift;
354 2         3 my $line_v_to = shift;
355 2         2 my $line_h_to = shift;
356              
357 2         39 print($line_v_from, "\n");
358 2         7 print($line_h_from, "\n");
359 2         4 print($line_v_to , "\n");
360 2         5 print($line_h_to , "\n");
361              
362 2         9 print "Strawberry\n";
363 2         6 $line_v_from->_next_track;
364 2         5 $line_h_from->_next_track;
365 2         5 $line_v_to->_previous_track;
366 2         5 $line_h_to->_previous_track;
367            
368 2 50       10 croak 'line_v_from is not a Grid::Layout::Line' unless $line_v_from->isa('Grid::Layout::Line');
369 2 50       5 croak 'line_v_to is not a Grid::Layout::Line' unless $line_v_to ->isa('Grid::Layout::Line');
370 2 50       6 croak 'line_h_from is not a Grid::Layout::Line' unless $line_h_from->isa('Grid::Layout::Line');
371 2 50       4 croak 'line_h_to is not a Grid::Layout::Line' unless $line_h_to ->isa('Grid::Layout::Line');
372            
373              
374 2         7 print "---->\n";
375 2         5 return $self->area($line_v_from->_next_track , $line_h_from->_next_track,
376             $line_v_to ->_previous_track, $line_h_to ->_previous_track);
377              
378             } #_}
379              
380 0         0 croak "need 4 Grid::Layout::Track's or 4 Grid::Layout::Line's";
381              
382             } #_}
383             sub size_x { #_{
384             #_{ POD
385             =head2 size_x
386              
387             my $x = $gl->size_x();
388              
389             Returns the horizontal size (x axis) in logical cell units.
390              
391             =cut
392             #_}
393 54     54 0 1450 my $self = shift;
394 54         59 return scalar @{$self->{'V'}{lines}} -1;
  54         124  
395             } #_}
396             sub size_y { #_{
397             #_{ POD
398             =head2 size_y
399              
400             my $y = $gl->size_y();
401              
402             Returns the vertical size (y axis) in logical cell units.
403              
404             =cut
405             #_}
406 54     54 0 65 my $self = shift;
407 54         67 return scalar @{$self->{'H'}{lines}} -1;
  54         124  
408             } #_}
409             sub size { #_{
410             #_{ POD
411             =head2 size
412              
413             Returns size of grid (nof vertical tracks x nof horizontal tracks);
414              
415             my ($v, $h) = $gl -> size();
416              
417             =cut
418             #_}
419              
420 5     5 0 890 my $self = shift;
421              
422 5         12 return ($self->size_x, $self->size_y);
423             } #_}
424             sub _size { #_{
425             #_{ POD
426             =head2 _size
427              
428             Internal use.
429              
430              
431             =cut
432             #_}
433              
434 55     55   69 my $self = shift;
435 55         66 my $V_or_H = shift;
436              
437 55         63 return scalar @{$self->{$V_or_H}{tracks}},
  55         218  
438              
439             } #_}
440             sub cell { #_{
441             #_{ POD
442             =head2 cell
443              
444             my $track_v = $gl->add_vertical_track(…);
445             my $track_h = $gl->add_horizontal_track(…);
446              
447             my $cell_1 = $gl->cell($x, $y);
448             my $cell_2 = $gl->cell($track_v, $track_h);
449              
450             Return the L<< Grid::Layout::Cell >> at horizontal position C<$x> and vertical position C<$y> or where C<$track_v> and C<$track_h> intersects.
451              
452             =cut
453             #_}
454              
455 259     259 0 7081 my $self = shift;
456 259         274 my $x = shift;
457 259         281 my $y = shift;
458              
459 259 100       703 unless ($x =~ /^\d+$/) {
460 16 50       48 if ($x->isa('Grid::Layout::Track')) {
461 16 50       37 croak '$x is not a vertical track' unless $x->{V_or_H} eq 'V';
462 16         24 $x = $x->{position};
463             }
464             else {
465 0         0 croak '$x neither number nor Grid::Layout::Track';
466             }
467             }
468 259 100       524 unless ($y =~ /^\d+$/) {
469 16 50       33 if ($y->isa('Grid::Layout::Track')) {
470 16 50       29 croak '$y is not a vertical track' unless $y->{V_or_H} eq 'H';
471 16         20 $y = $y->{position};
472             }
473             else {
474 0         0 croak '$y neither number nor Grid::Layout::Track';
475             }
476             }
477              
478 259         637 return $self->{cells}->[$x][$y];
479              
480             } #_}
481             sub _add_cell { #_{
482             #_{ POD
483             =head2 _add_cell
484              
485             Internal use.
486              
487             =cut
488             #_}
489              
490 136     136   147 my $self = shift;
491 136         134 my $x = shift;
492 136         136 my $y = shift;
493              
494 136         225 $self->{cells}->[$x][$y] = Grid::Layout::Cell->new($self, $x, $y);
495              
496             } #_}
497             sub line_x { #_{
498             #_{ POD
499             =head2 line_x
500              
501             my $line = $gl->line_x($postition);
502              
503             Returns the C<< $position >>th line in horizontal direction.
504              
505             =cut
506             #_}
507              
508 5     5 0 604 my $self = shift;
509 5         8 my $position = shift;
510 5         21 return $self->_line('V', $position);
511              
512             } #_}
513             sub line_y { #_{
514             #_{ POD
515             =head2 line_y
516              
517             my $line = $gl->line_y($postition);
518              
519             Returns the C<< $position >>th line in vertical direction.
520              
521             =cut
522             #_}
523              
524 6     6 0 2662 my $self = shift;
525 6         12 my $position = shift;
526              
527 6         12 return $self->_line('H', $position);
528              
529             } #_}
530             sub _line { #_{
531             #_{ POD
532             =head2 _line
533              
534             my $line = $gl->_line($V_or_H, $position)
535              
536             Returns the C<< $position >>th line in vertical or horizontal direction.
537              
538             =cut
539             #_}
540              
541 51     51   80 my $self = shift;
542 51         60 my $V_or_H = shift;
543 51         61 my $position = shift;
544              
545 51 50 66     131 croak 'need V or H' unless $V_or_H eq 'V' or $V_or_H eq 'H';
546 51 50       189 croak 'need a position' unless $position =~ /^\d+$/;
547              
548 51         60 return ${$self->{$V_or_H}->{lines}}[$position];
  51         189  
549              
550             } #_}
551             sub _track { #_{
552             #_{ POD
553             =head2 _track
554              
555             my $track = $gl->_track($V_or_H, $position)
556              
557             Returns the C<< $position >>th track in vertical or horizontal direction.
558              
559             =cut
560             #_}
561              
562 20     20   25 my $self = shift;
563 20         24 my $V_or_H = shift;
564 20         22 my $position = shift;
565              
566 20 50 66     50 croak 'need V or H' unless $V_or_H eq 'V' or $V_or_H eq 'H';
567 20 50       56 croak 'need a position' unless $position =~ /^\d+$/;
568              
569 20         24 return ${$self->{$V_or_H}->{tracks}}[$position];
  20         52  
570              
571             } #_}
572             sub VH_opposite { #_{
573             #_{ POD
574             =head2 VH_opposite
575              
576             my $o1 = Grid::Layout::VH_opposite('H');
577             my $02 = Grid::Layout::VH_opposite('V');
578              
579             Static method. Returns C<'V'> if passed C<'H'> and vice versa.
580              
581             =cut
582             #_}
583              
584 30     30 0 108 my $V_or_H = shift;
585              
586 30 100       68 return 'H' if $V_or_H eq 'V';
587 24 50       84 return 'V' if $V_or_H eq 'H';
588              
589 0           croak "$V_or_H is neither H nor V";
590              
591             } #_}
592             #_}
593             #_{ POD: Copyright
594              
595             =head1 Copyright
596              
597             Copyright © 2017 René Nyffenegger, Switzerland. All rights reserved.
598             This program is free software; you can redistribute it and/or modify it
599             under the terms of the the Artistic License (2.0). You may obtain a
600             copy of the full license at: L
601              
602             =cut
603              
604             #_}
605             #_{ POD: Source Code
606              
607             =head1 Source Code
608              
609             The source code is on L<< github|https://github.com/ReneNyffenegger/perl-Grid-Layout >>. Meaningful pull requests are welcome.
610              
611             =cut
612              
613             #_}
614              
615             'tq84';