File Coverage

blib/lib/Text/Flowchart.pm
Criterion Covered Total %
statement 373 442 84.3
branch 138 234 58.9
condition 62 142 43.6
subroutine 71 72 98.6
pod 5 8 62.5
total 649 898 72.2


line stmt bran cond sub pod time code
1             package Text::Flowchart;
2              
3             #Copyright (c) 1999 James A Thomason III (jim3@psynet.net). All rights reserved.
4             #This program is free software; you can redistribute it under the terms of the licence listed at the end
5             #of the module.
6              
7             $VERSION = "1.00";
8              
9 1     1   1119 use Carp;
  1         1  
  1         1350  
10              
11              
12             {
13             my $i = 0;
14             foreach ($boxes, $grid, $lines, $directed){
15             $_ = $i++
16             };
17            
18             };
19              
20             sub accessor {
21 198     198 0 220 my $self = shift;
22 198         217 my $prop = shift;
23            
24 198 100       588 $self->[$prop] = shift if @_;
25            
26 198         781 return $self->[$prop];
27             };
28              
29 17     17 1 41 sub directed{ shift->accessor($directed, @_)};
30              
31             sub new {
32              
33 1     1 1 17 my $class = shift;
34 1         6 my %init = @_;
35 1         4 my $self = []; #why not a hash? An array is a smidgen bit faster and no one is gonna see the underlying structure anyway
36 1         4 bless $self, $class; #Hey! What are you doing looking in here anyway? Use the nice OO interface I wrote you!
37            
38 1 50       14 $self->size(
    50          
39             "width" => $init{"width"} ? $init{"width"} : -1,
40             "height" => $init{"height"} ? $init{"height"} : -1,
41             "pad" => $init{"pad"},
42             "debug" => $init{"debug"}
43             );
44            
45 1   50     7 $self->directed($init{"directed"} || 0);
46            
47 1         3 return $self;
48            
49             };
50              
51             sub box {
52              
53 5     5 1 23 my $self = shift;
54            
55 5         18 my $box = Text::Flowchart::Shape::Box->new(@_, "parent" => $self);
56            
57 5 50       13 croak("Box was not created properly\n") unless $box;
58            
59            
60 5   33     4 push @{$self->[$boxes]}, $box || croak("Cannot add box to flowchart stack\n");
  5         15  
61            
62 5         16 return $self->[$boxes]->[-1];
63             };
64              
65             sub line {
66              
67 5     5 0 6 my $self = shift;
68            
69 5         30 my %init = @_;
70            
71 5         6 my $line;
72 5 50       52 if ($init{"orientation"} eq "V"){
    100          
    50          
73 0         0 $line = Text::Flowchart::Shape::Line::Vertical->new(@_, "parent" => $self);
74             }
75             elsif ($init{"orientation"} =~ m/^(T|B)C$/){
76 4         25 $line = Text::Flowchart::Shape::Line::Corner->new(@_, "parent" => $self);
77             }
78 0         0 elsif ($init{"orientation"} eq "H"){
79 1         28 $line = Text::Flowchart::Shape::Line::Horizontal->new(@_, "parent" => $self);
80             }
81             else {croak("Invalid orientation. Must be 'H', 'V', 'TC', or 'BC'\n")};
82            
83 5 50       14 croak("Line was not created properly.\n") unless $line;
84            
85            
86            
87 5   33     6 push @{$self->[$lines]}, $line || croak("Cannot add line to flowchart stack\n");
  5         17  
88            
89 5         88 return $self->[$lines]->[-1];
90             };
91              
92             sub size {
93            
94 12     12 0 15 my $self = shift;
95            
96 12 100       26 if (@_) {
97 1         9 my $_grid = Text::Flowchart::Grid->new(@_);
98 1 50       4 croak("Cannot create grid\n") unless $_grid;
99 1         6 $self->[$grid] = $_grid;
100             };
101            
102 12         22 return $self->[$grid];
103              
104             };
105              
106             sub draw {
107 1     1 1 8 my $self = shift;
108            
109 1         5 local *OUTPUT;
110 1   33     11 *OUTPUT = shift || *STDOUT;
111            
112 1         3 my $grid = $self->size();
113 1         3 my ($x, $y, $x2, $y2) = (0,0,0,0);
114            
115 1         2 foreach $box (@{$self->[$boxes]}){
  1         3  
116 5         13 $grid->insert($box)
117             };
118            
119 1         3 foreach $line (@{$self->[$lines]}){
  1         4  
120 5         11 $grid->insert($line)
121             };
122            
123             #print OUTPUT "\n";
124            
125 1         19 $grid->repair();
126            
127 1 50       4 if ($grid->debug()){
128 0         0 print OUTPUT " ";
129 0         0 my $width = $grid->width();
130 0         0 while ($width-- > 0){
131 0   0     0 print OUTPUT ($x++ % 10 || $x2++);
132             };
133 0         0 print OUTPUT "\n";
134             };
135 1         3 foreach (0..$#{$grid->grid()}){
  1         3  
136 24 50 0     56 print OUTPUT ($y++ % 10 || $y2++) if $grid->debug();
137 24 50       43 if (length $grid->grid->[$_] == $grid->width()){print OUTPUT $grid->grid->[$_], "\n"}
  24         45  
  0         0  
138             else {print OUTPUT $grid->pad() x $grid->width(), "\n"};
139             };
140             };
141              
142             sub relate {
143 5     5 1 45 my $self = shift;
144              
145 5         5 my $from_array = shift;
146 5         7 my $to_array = shift;
147            
148 5         12 my %init = @_;
149              
150 5         6 my ($from, $from_side, $from_offset) = @{$from_array};
  5         64  
151 5         7 my ($to, $to_side, $to_offset) = @{$to_array};
  5         9  
152 5 50       16 if ($from->parent() ne $self){croak("Cannot relate from a box not inside this flowchart.\n")};
  0         0  
153 5 50       12 if ($to->parent() ne $self){croak("Cannot relate to a box not inside this flowchart.\n")};
  0         0  
154 5 50       34 if ($from_side !~ /^(top|bottom|right|left)$/){croak("Invalid side. Side must be 'top', 'bottom', 'left', or 'right'.\n")};
  0         0  
155 5 50       22 if ($to_side !~ /^(top|bottom|right|left)$/){croak("Invalid side. Side must be 'top', 'bottom', 'left', or 'right'.\n")};
  0         0  
156 5 50       13 if ($from_side eq $to_side){croak("Cannot relate the same sides of boxes. Use different sides.\n")};
  0         0  
157 5 50       17 if (length $init{"reason"} > 1){croak("Reasons must be a single character.\n")};
  0         0  
158            
159 5         21 return $from->relate(
160             "to" => $to,
161             "from_side" => $from_side,
162             "to_side" => $to_side,
163             "from_offset" => $from_offset,
164             "to_offset" => $to_offset,
165             "reason" => $init{"reason"}
166             );
167            
168             };
169              
170             package Text::Flowchart::Grid;
171              
172 1     1   11 use Carp;
  1         2  
  1         793  
173              
174             @ISA = qw(Text::Flowchart);
175              
176             $def_width = 72;
177             $def_height = 0;
178             $def_pad = " ";
179              
180             {
181             my $i = 0;
182             foreach ($width, $height, $grid, $pad, $debug){
183             $_ = $i++
184             };
185            
186             };
187              
188 59     59   111 sub width {shift->accessor($width, @_)};
189 22     22   170 sub height {shift->accessor($height, @_)};
190 49     49   93 sub grid {shift->accessor($grid, @_)};
191 25     25   49 sub pad {shift->accessor($pad, @_)};
192 26     26   48 sub debug {shift->accessor($debug, @_)};
193              
194             sub new {
195 1     1   3 my $class = shift;
196 1         3 my $self = [];
197 1         3 bless $self, $class;
198 1         10 my %init = @_;
199            
200 1         25 my $width = $init{"width"};
201 1         3 my $height = $init{"height"};
202 1         2 my $pad = $init{"pad"};
203 1         2 my $debug = $init{"debug"};
204            
205 1 50 33     28 croak("Invalid dimensions.\n") unless $width =~ /^-?\d*$/ && $height =~ /^-?\d*$/;
206            
207 1 50       7 $self->width($width > 0 ? $width : $def_width);
208 1 50       6 $self->height($height >= 0 ? $height : $def_height);
209 1 50       7 $self->pad(length $pad == 1 ? $pad : $def_pad);
210 1   50     9 $self->debug($debug || 0);
211 1         3 $self->[$grid] = [];
212 1         4 foreach (1..$self->height){
213 0         0 push @{$self->[$grid]}, $pad x $self->width();
  0         0  
214             };
215            
216 1         15 return $self;
217              
218             };
219              
220             sub insert {
221 10     10   13 my $self = shift;
222 10         13 my $box = shift;
223 10         50 my $x = $box->x_coord();
224 10         21 my $y = $box->y_coord();
225            
226 10 50       23 defined $box || croak("Nothing to insert.\n");
227 10 50 33     37 if (($x < 0 || $x + length $box->render->[0] > $self->width) && $self->width != 0) {croak("Your object is too wide for the page.\n")};
  0   33     0  
228 10 50 33     31 if (($y < 0 || $y + @{$box->render()} > $self->height) && $self->height != 0) {croak("Your object is too tall for the page.\n")};
  0   33     0  
229 10         14 foreach $entry (@{$box->render()}){
  10         20  
230 66         143 my ($line, $offset) = @{$entry};
  66         200  
231 66 100       162 $self->[$grid]->[$y] = $self->pad() x $self->width() unless $self->[$grid]->[$y];
232 66         278 substr($self->[$grid]->[$y++], $x + $offset, length $line) = $line;
233             };
234            
235 10         29 return 1;
236             };
237              
238             sub repair {
239 1     1   2 my $self = shift;
240              
241              
242 1         3 return 1;
243             };
244              
245              
246              
247             package Text::Flowchart::Shape;
248              
249 1     1   6 use Carp;
  1         5  
  1         509  
250              
251             $def_width = 15;
252             $def_height = 0;
253              
254             $PROP_COUNT = 0;
255             foreach ($string, $width, $height, $x_coord, $y_coord, $parent,
256             $real_width, $real_height, $rendered){
257             $_ = $PROP_COUNT++;
258             };
259              
260              
261             sub accessor {
262              
263 990     990   1495 my $self = shift;
264 990         1894 my $prop = shift;
265              
266 990 100       2952 $self->[$prop] = shift if @_;
267            
268 990         4521 return $self->[$prop];
269             };
270              
271 15     15   45 sub string {shift->accessor($string, @_)};
272 15     15   27 sub width {shift->accessor($width, @_)};
273 20     20   43 sub height {shift->accessor($height, @_)};
274 35     35   182 sub x_coord {shift->accessor($x_coord, @_)};
275 35     35   67 sub y_coord {shift->accessor($y_coord, @_)};
276 61     61   124 sub parent {shift->accessor($parent, @_)};
277 18     18   39 sub real_width {shift->accessor($real_width, @_)};
278 17     17   33 sub real_height {shift->accessor($real_height, @_)};
279 80     80   145 sub rendered {shift->accessor($rendered, @_)};
280              
281             sub init {
282 10     10   13 my $class = shift;
283 10         14 my $self = [];
284 10         31 bless $self, $class;
285              
286 10         40 my %init = @_;
287            
288 10   100     62 $self->string($init{"string"} || undef);
289 10 100       48 $self->width($init{"width"} > 0 ? $init{"width"} : $def_width);
290 10 50       50 $self->height($init{"height"} > 0 ? $init{"height"} : $def_height);
291 10 50       261 $self->x_coord($init{"x_coord"} >= 0 ? $init{"x_coord"} : croak("X coordinate must be specified and non-negative\n"));
292 10 50       53 $self->y_coord($init{"y_coord"} >= 0 ? $init{"y_coord"} : croak("X coordinate must be specified and non-negative\n"));
293            
294 10         30 return $self;
295              
296             };
297              
298             package Text::Flowchart::Shape::Box;
299              
300 1     1   6 use Carp;
  1         1  
  1         2080  
301              
302              
303             @ISA = qw(Text::Flowchart::Shape);
304              
305             $def_x_pad = 1;
306             $def_y_pad = 1;
307              
308             {
309             my $PROP_COUNT = $Text::Flowchart::Shape::PROP_COUNT;
310             foreach ($x_pad, $y_pad, $format_char, $top_links, $bottom_links, $left_links, $right_links){
311             $_ = $PROP_COUNT++;
312             };
313             };
314              
315 15     15   27 sub x_pad {shift->accessor($x_pad, @_)};
316 15     15   27 sub y_pad {shift->accessor($y_pad, @_)};
317 5     5   23 sub format_char {shift->accessor($format_char, @_)};
318 7     7   16 sub top_links {shift->accessor($top_links, @_)};
319 7     7   15 sub bottom_links{shift->accessor($bottom_links, @_)};
320 8     8   16 sub left_links {shift->accessor($left_links, @_)};
321 8     8   14 sub right_links {shift->accessor($right_links, @_)};
322              
323             sub relate {
324 5     5   10 my $from = shift;
325            
326 5         163 my %init = @_;
327            
328 5   33     14 my $to = $init{"to"} || croak("No shape to relate to.\n");
329 5   33     15 my $from_side = $init{"from_side"} || croak("No shape to relate from.\n");
330 5   33     15 my $to_side = $init{"to_side"} || croak("No side to relate to.\n");
331 5   100     27 my $from_offset = $init{"from_offset"} || 0;
332 5   50     12 my $to_offset = $init{"to_offset"} || 0;
333 5   100     19 my $reason = $init{"reason"} || undef;
334              
335 5 50       10 if ($from->parent() ne $to->parent){croak("No shape to relate to.\n")};
  0         0  
336 5 50       25 if ($from_side !~ /^(top|bottom|right|left)$/){croak("Invalid side. Side must be 'top', 'bottom', 'left', or 'right'.\n")};
  0         0  
337 5 50       27 if ($to_side !~ /^(top|bottom|right|left)$/){croak("Invalid side. Side must be 'top', 'bottom', 'left', or 'right'.\n")};
  0         0  
338 5 50       15 if ($from_side eq $to_side){croak("Cannot relate the same sides of boxes. Use different sides.\n")};
  0         0  
339 5 50       12 if (length $reason > 1){croak("Reasons must be a single character.\n")};
  0         0  
340              
341              
342 5         88 my $from_coords = $from->get_next_coord($from_side, $from_offset);
343 5         16 my $to_coords = $to->get_next_coord($to_side, $to_offset);
344              
345 5         10 my $orientation = undef;
346            
347 5 100 100     359 if ($from_side =~ m/^(lef|righ)t$/ && $to_side =~ m/^(lef|righ)t$/){$orientation = "H"}
  1 50 66     2  
  0 50 33     0  
    100 66        
    100 66        
    50 33        
348 0         0 elsif ($from_side =~ m/^(top|bottom)$/ && $to_side =~ m/^(top|bottom)$/){$orientation = "V"}
349 1         4 elsif ($from_side eq "top" && $to_side =~ m/^(lef|righ)t$/){$orientation = "TC"}
350 1         3 elsif ($from_side eq "bottom" && $to_side =~ m/^(lef|righ)t$/){$orientation = "BC"}
351 2         3 elsif ($from_side =~ m/^(lef|righ)t$/ && $to_side eq "bottom"){$orientation = "BC"}
352             elsif ($from_side =~ m/^(lef|righ)t$/ && $to_side eq "top"){$orientation = "TC"};
353 5         12 $from->parent->line(
354             "from" => $from_coords,
355             "to" => $to_coords,
356             "orientation" => $orientation,
357             "reason" => $reason
358             );
359            
360 5         39 return 1;
361            
362             };
363              
364             sub get_next_coord {
365 10     10   12 my $self = shift;
366 10         17 $i =0;
367 10   50     289 my $side = shift || return "SIDE";
368 10   100     34 my $offset = shift || "0";
369 10         43 my %map = ("top" => $top_links, "bottom" => $bottom_links,
370             "left" => $left_links, "right" => $right_links);
371              
372 10         14 my $side_num = $map{$side};
373 10 50       28 return "COUNT $side" if scalar $self->[$side_num] <= 0;
374            
375            
376 10 100       39 if ($side eq "top"){
    100          
    100          
    50          
377 2         7 return [$self->x_coord() + $self->_get_offset($self->top_links(), $offset), $self->y_coord()];
378            
379             }
380             elsif ($side eq "bottom"){
381 2         5 return [$self->x_coord() + $self->_get_offset($self->bottom_links(), $offset), $self->y_coord() + $self->real_height() - 1];
382             }
383             elsif ($side eq "left"){
384 3         8 return [$self->x_coord(), $self->y_coord() + $self->_get_offset($self->left_links(), $offset)];
385             }
386 0         0 elsif ($side eq "right"){
387 3         10 return [$self->x_coord() + $self->real_width() - 1, $self->y_coord() + $self->_get_offset($self->right_links(), $offset)];
388             }
389             else {return "ORIENT"};
390            
391             };
392              
393             sub _get_offset {
394 10     10   16 my $self = shift;
395 10   33     104 my $side = shift || croak("No side supplied to _get_offset.\n");
396 10         12 my $offset = shift;
397 10         13 my $real_offset = 0;
398            
399 10 100       29 if ($offset == 0){$real_offset = shift @{$side}; $real_offset++}
  1 50       2  
  1         2  
  1         2  
  0         0  
400 0         0 elsif ($offset == -1){$real_offset = pop @{$side};}
401             else {
402 9         12 my ($i, $found) = (0,0);
403 9         12 foreach $i (0.. $#{$side}){
  9         21  
404 37 100       89 if ($side->[$i] == $offset){
405 9         10 $found++;
406 9         14 $real_offset = $side->[$i] + 1;
407 9         10 splice(@{$side}, $i, 1);
  9         26  
408 9         15 last;
409             };
410             };
411 9 50       20 unless ($found){$real_offset = shift @{$side}; $real_offset++};
  0         0  
  0         0  
  0         0  
412              
413             };
414              
415 10         131 return $real_offset;
416             };
417              
418             sub new {
419 5     5   7 my $class = shift;
420 5         29 my $self = $class->init(@_);
421              
422 5         15 my %init = @_;
423            
424 5 50 33     23 $self->x_pad(defined $init{"x_pad"} && $init{"x_pad"} >= 0 ? $init{"x_pad"} : $def_x_pad);
425 5 100 66     25 $self->y_pad(defined $init{"y_pad"} && $init{"y_pad"} >= 0 ? $init{"y_pad"} : $def_y_pad);
426 5 50       14 $self->format_char(defined $init{"format_char"} ? $init{"format_char"} : undef);
427 5   50     22 $self->parent($init{"parent"} || undef);
428              
429 5 50 33     9 croak("Invalid width.\n") if $self->width() - 2 - $self->x_pad() * 2 < 1 && $self->width() > 0;
430 5 50 33     11 croak("Invalid height.\n") if $self->height() - 2 - $self->y_pad() * 2 < 1 && $self->height() > 0;
431            
432 5         12 $self->render();
433            
434 5         8 my @top_links = ();
435 5         7 my @bottom_links = ();
436 5         6 my @left_links = ();
437 5         6 my @right_links = ();
438            
439 5         11 foreach my $i (0..$self->real_width() - 2){push @top_links, $i};
  63         83  
440 5         11 foreach my $i (0..$self->real_width() - 2){push @bottom_links, $i};
  63         85  
441 5         11 foreach my $i (0..$self->real_height() - 2){push @left_links, $i};
  24         36  
442 5         11 foreach my $i (0..$self->real_height() - 2){push @right_links, $i};
  24         49  
443              
444 5         13 $self->top_links(\@top_links);
445 5         13 $self->bottom_links(\@bottom_links);
446 5         13 $self->left_links(\@left_links);
447 5         12 $self->right_links(\@right_links);
448              
449 5         18 return $self;
450              
451             };
452              
453             sub render {
454 20     20   23 my $self = shift;
455            
456 20 100       40 return $self->rendered() if $self->rendered();
457            
458 5         9 my $string = $self->string();
459 5         8 my $width = $self->width();
460 5         11 my $height = $self->height();
461 5         19 my $x_pad = $self->x_pad();
462 5         12 my $y_pad = $self->y_pad();
463 5         11 my $page_width = $self->parent->size->[0];
464 5         16 my $page_height = $self->parent->size->[1];
465            
466 5 50 33     24 my $box_width = ($width < $page_width || $page_width == 0 ? $width : $page_width );
467 5 50 33     673 my $box_height = ($height < $page_height || $page_height == 0 ? $height : $page_height);
468            
469 5         9 my $wrap_width = $box_width - 2 - $x_pad * 2;
470 5         7 my $wrap_height = $box_height - 2 - $y_pad * 2;
471            
472            
473              
474 5 50       348 $string =~ s/(.{1,$wrap_width}(?:\b|$)|\S{$wrap_width})\s*/$1\n$2/g unless $box_width == 0;
475 5         151 my @string = split(/\n/, $string);
476 5         11 foreach (@string){
477 11 50       66 if (length $_ + 2 * $x_pad < $wrap_width) {
478 11         20 $_ .= " " x ($wrap_width - (length $_));
479             };
480 11         403 s/^/"|" . " " x $x_pad/gme;
  11         50  
481 11         35 s/$/(" " x $x_pad) . "|"/gme;
  11         34  
482 11         34 $_ = [$_, 0];
483             };
484 5 50       14 @string = splice(@string, 0, $wrap_height) unless $box_height == 0;
485            
486 5         10 while ($y_pad-- > 0) {
487 4 50       18 push @string, ["|" . " " x ($box_width ? $box_width - 2 : (length $string) + $x_pad * 2) . "|", 0];
488 4 50       22 unshift @string, ["|" . " " x ($box_width ? $box_width - 2 : (length $string) + $x_pad * 2) . "|", 0];
489             };
490            
491 5         10 my $remaining_height = $box_height - @string - 2; #don't forget to drop 2 for the top and bottom lines!
492            
493 5         12 while ($remaining_height-- > 0) {
494 0 0       0 push @string, ["|" . " " x ($box_width ? $box_width - 2 : (length $string) + $x_pad * 2) . "|", 0];
495             };
496            
497 5 50       27 push @string, ["+" . "-" x ($box_width ? $box_width - 2 : (length $string) + $x_pad * 2) . "+", 0];
498 5 50       20 unshift @string, ["+" . "-" x ($box_width ? $box_width - 2 : (length $string) + $x_pad * 2) . "+", 0];
499            
500 5 50       19 $self->real_width($box_width ? $box_width : (length $string) + $x_pad * 2 + 2);
501 5         14 $self->real_height(scalar @string);
502            
503 5         12 return $self->rendered(\@string);
504            
505              
506             };
507              
508              
509              
510             package Text::Flowchart::Shape::Line;
511              
512 1     1   6 use Carp;
  1         2  
  1         1380  
513              
514              
515             @ISA = qw(Text::Flowchart::Shape);
516              
517             {
518             my $PROP_COUNT = $Text::Flowchart::Shape::PROP_COUNT;
519             foreach ($from, $to, $reason, $orientation, $xfrom, $xto, $yfrom, $yto, $xdistance, $ydistance,
520             $xleft, $xright, $ytop, $ybottom, $xmiddle, $ymiddle, $width, $height){
521             $_ = $PROP_COUNT++;
522             };
523            
524             };
525              
526 15     15   35 sub from {shift->accessor($from, @_)};
527 15     15   31 sub to {shift->accessor($to, @_)};
528 17     17   1861 sub reason {shift->accessor($reason, @_)};
529 11     11   23 sub orientation {shift->accessor($orientation, @_)};
530 98     98   758 sub xfrom {shift->accessor($xfrom, @_)};
531 95     95   336 sub xto {shift->accessor($xto, @_)};
532 99     99   186 sub yfrom {shift->accessor($yfrom, @_)};
533 96     96   240 sub yto {shift->accessor($yto, @_)};
534 53     53   104 sub xdistance {shift->accessor($xdistance, @_)};
535 37     37   74 sub ydistance {shift->accessor($ydistance, @_)};
536 14     14   29 sub xleft {shift->accessor($xleft, @_)};
537 8     8   24 sub xright {shift->accessor($xright, @_)};
538 13     13   25 sub ytop {shift->accessor($ytop, @_)};
539 7     7   17 sub ybottom {shift->accessor($ybottom, @_)};
540 6     6   14 sub xmiddle {shift->accessor($xmiddle, @_)};
541 5     5   13 sub ymiddle {shift->accessor($ymiddle, @_)};
542 25     25   101 sub width {shift->accessor($width, @_)};
543 15     15   34 sub height {shift->accessor($height, @_)};
544              
545             sub new {
546              
547 5     5   7 my $class = shift;
548 5         32 my $self = $class->init(@_);
549              
550 5 50       12 if ($class eq "Text::Flowchart::Shape::Line"){
551 0 0       0 if ($class eq "Text::Flowchart::Shape::Line::Horizontal"){
    0          
    0          
552 0         0 return Text::Flowcahrt::Shape::Line::Horizontal->new(@_);
553             }
554             elsif ($class eq "Text::Flowchart::Shape::Line::Vertical"){
555 0         0 return Text::Flowcahrt::Shape::Line::Vertical->new(@_);
556             }
557             elsif ($class eq "Text::Flowchart::Shape::Line::Corner"){
558 0         0 return Text::Flowcahrt::Shape::Line::Corner->new(@_);
559             };
560             }
561             else {
562              
563 5         19 my %init = @_;
564            
565            
566 5 50 33     21 if (ref $init{"from"} eq "ARRAY" && @{$init{"from"}} == 2){
  5         20  
567 5         22 $self->from($init{"from"});
568             }
569             else {
570 0         0 croak("Invalid from coordinates, should be [x,y]");
571             };
572            
573 5 50 33     83 if (ref $init{"to"} eq "ARRAY" && @{$init{"from"}} == 2){
  5         19  
574 5         24 $self->to($init{"to"});
575             }
576             else {
577 0         0 croak("Invalid to coordinates, should be [x,y]");
578             };
579            
580 5   100     31 $self->reason($init{"reason"} || undef);
581 5   33     32 $self->orientation($init{"orientation"} || croak("I require an orientation. 'HR', 'HL', 'VT', 'VB' please.\n"));
582 5   50     26 $self->parent($init{"parent"} || undef);
583            
584 5         11 $self->xfrom($self->from->[0]);
585 5         12 $self->yfrom($self->from->[1]);
586            
587 5         12 $self->xto($self->to->[0]);
588 5         19 $self->yto($self->to->[1]);
589            
590 5         12 $self->width(abs ($self->xfrom() - $self->xto()) + 1);
591 5         12 $self->height(abs ($self->yfrom() - $self->yto()) + 1);
592            
593 5 50 33     11 unless ($self->width() == 1 || $self->width() > 2){croak("Invalid width. Make your shape wider.\n")};
  0         0  
594            
595 5         9 $self->xdistance($self->width() - 2);
596 5         12 $self->ydistance($self->height() - 2);
597            
598 5         11 $self->xleft(int ($self->xdistance() / 2));
599 5         14 $self->ytop(int ($self->ydistance() / 2));
600            
601 5         12 $self->xright($self->xdistance() - $self->xleft() - 1);
602 5         13 $self->ybottom($self->ydistance() - $self->ytop() - 1);
603            
604            
605 5 100       19 $self->xmiddle(1 + ($self->offset() ? $self->xleft() : $self->xright()));
606 5 100       16 $self->ymiddle(1 + ($self->offset() ? $self->ytop() : $self->ybottom()));
607              
608 5         17 $self->render();
609            
610 5         22 return $self;
611            
612             };
613              
614             };
615              
616             sub offset {
617 55     55   62 my $self = shift;
618              
619 55   66     96 return (($self->xfrom() > $self->xto()) xor ($self->yto() > $self->yfrom())) ||
620             (($self->xfrom() < $self->xto()) xor ($self->yto() < $self->yfrom()));
621             };
622              
623             sub end_char {
624 10     10   12 my $self = shift;
625            
626 10         14 my $direction = shift;
627 10 100       44 if ($direction =~ /V/){
    50          
628 4 100       8 if ($self->reason()){
629 2 50 33     5 if (($self->yfrom() < $self->yto() && $direction eq "VT")
      33        
      33        
630             || ($self->yfrom() > $self->yto() && $direction eq "VB")){
631 0         0 return $self->reason()};
632             };
633            
634 4 100       8 if ($self->yfrom() < $self->yto()){return "V"}
  3         11  
  1         5  
635             else {return "^"};
636             }
637 0         0 elsif ($direction =~ /H/){
638 6 100       14 if ($self->reason()){
639 2 50 66     103 if (($self->xfrom() < $self->xto() && $direction eq "HL")
      33        
      66        
640             || ($self->xfrom() > $self->xto() && $direction eq "HR")){
641 2         6 return $self->reason()};
642             };
643            
644 4 50       9 if ($self->xfrom() < $self->xto()){return ">"}
  4         49  
  0         0  
645             else {return "<"};
646             }
647             else {croak("Invalid direction for end_char. Must be 'HR', 'HL', 'VT', or 'VB'.\n")};
648             };
649              
650             sub end {
651 16     16   24 my $self = shift;
652              
653 16 50       28 return "+" unless $self->parent->directed();
654              
655 16         18 my $arg = shift;
656 16         19 my $direction = shift;
657            
658 16 50 33     31 if ($self->xdistance >= 0 && $self->ydistance >= 0){
  0         0  
659              
660 16 100       35 if ($arg == 1) {return $self->offset() ? "+" : $self->end_char($direction)}
  6 100       12  
  6 100       13  
    100          
661 4         8 elsif ($arg == 2) {return $self->offset() ? $self->end_char($direction) : "+"}
662             else {return $self->end_char($direction)};
663             }
664             else {return $self->end_char($direction)};
665            
666             };
667              
668             package Text::Flowchart::Shape::Line::Horizontal;
669              
670 1     1   6 use Carp;
  1         1  
  1         304  
671              
672              
673             @ISA = qw(Text::Flowchart::Shape::Line);
674              
675             sub render {
676 4     4   5 my $self = shift;
677            
678 4 100       15 return $self->rendered() if $self->rendered();
679            
680            
681 1         2 my @string = ();
682            
683 1 50 33     3 if ($self->xdistance() >= 0 && $self->ydistance() >= 0){
    0          
684 1 50       7 push @string, [$self->end(2, "HL") . ("-" x $self->xleft()) . $self->end(1, "HR"), $self->offset() ? 0 : $self->xmiddle()];
685 1         5 my $yd2 = $self->ydistance();
686 1         5 while ($yd2-- > 0){
687 0         0 push @string, ["|", $self->xmiddle()];
688             };
689            
690 1 50       4 push @string, [$self->end(1, "HL") . ("-" x $self->xright()) . $self->end(2, "HR"), $self->offset() ? $self->xmiddle() : 0];
691              
692             }
693 0         0 elsif ($self->xdistance() > 0) {
694 0         0 push @string, [$self->end(0, "HL") . ("-" x $self->xdistance()) . $self->end(0, "HR"), 0];
695             }
696             else {croak("You're trying to draw a vertical line with a horizontal object. Use a Vertical line.\n")};
697              
698 1 50       5 $self->x_coord($self->xfrom() > $self->xto() ? $self->xto() : $self->xfrom());
699 1 50       4 $self->y_coord($self->yfrom() > $self->yto() ? $self->yto() : $self->yfrom());
700 1         4 return $self->rendered(\@string);
701             };
702              
703             package Text::Flowchart::Shape::Line::Vertical;
704              
705 1     1   3 use Carp;
  1         2  
  1         346  
706              
707              
708             @ISA = qw(Text::Flowchart::Shape::Line);
709              
710             sub render {
711 0     0   0 my $self = shift;
712            
713 0 0       0 return $self->rendered() if $self->rendered();
714            
715 0         0 my @string = ();
716            
717 0 0 0     0 if ($self->xdistance() >= 0 && $self->ydistance() >= 0){
    0          
718 0 0       0 push @string, [$self->end(0, "VT"), $self->offset() ? 0 : $self->xdistance() + 1];
719 0         0 my $yd2 = $self->ytop();
720 0         0 while ($yd2-- > 0){
721 0 0       0 push @string, ["|", $self->offset() ? 0 : $self->xdistance() + 1];
722             };
723            
724 0         0 push @string, ["+" . ("-" x $self->xdistance()) . "+", 0];
725            
726 0         0 $yd2 = $self->ybottom();
727 0         0 while ($yd2-- > 0){
728 0 0       0 push @string, ["|", $self->offset() ? $self->xdistance() + 1: 0];
729             };
730            
731 0 0       0 push @string, [$self->end(0, "VB"), $self->offset() ? $self->xdistance() + 1 : 0];
732              
733             }
734 0         0 elsif ($self->ydistance() > 0 ) {
735 0         0 push @string, [$self->end(0, "VT"), 0];
736 0         0 my $yd2 = $self->ydistance();
737 0         0 while ($yd2-- > 0){
738 0         0 push @string, ["|", 0];
739             };
740 0         0 push @string, [$self->end(0, "VB"), 0];
741             }
742             else {croak("You're trying to draw a horizontal line with a hertical object. Use a Vertical line.\n")};
743              
744 0 0       0 $self->x_coord($self->xfrom() > $self->xto() ? $self->xto() : $self->xfrom());
745 0 0       0 $self->y_coord($self->yfrom() > $self->yto() ? $self->yto() : $self->yfrom());
746 0         0 return $self->rendered(\@string);
747             };
748              
749             package Text::Flowchart::Shape::Line::Corner;
750              
751 1     1   5 use Carp;
  1         1  
  1         430  
752              
753              
754             @ISA = qw(Text::Flowchart::Shape::Line);
755              
756             sub render {
757 16     16   22 my $self = shift;
758            
759 16 100       36 return $self->rendered() if $self->rendered();
760            
761            
762 4         8 my @string = ();
763            
764 4 100       10 if ($self->orientation() eq "BC"){
    50          
765 2         4 my $yd2 = $self->ydistance();
766 2         8 while ($yd2-- > 0){
767 9 100       20 push @string, ["|", $self->offset() ? 0 : $self->xdistance() + 1];
768             };
769 2         6 push @string, [$self->end(1, "HL") . ("-" x $self->xdistance()) . $self->end(2, "HR"), 0];
770 2 100       9 unshift @string, [$self->end(0, "VT"), $self->offset() ? 0 : $self->xdistance() + 1];
771              
772             }
773 0         0 elsif ($self->orientation() eq "TC") {
774 2         6 my $yd2 = $self->ydistance();
775 2         8 while ($yd2-- > 0){
776 18 100       74 push @string, ["|", $self->offset() ? $self->xdistance() + 1: 0];
777             };
778 2         16 unshift @string, [$self->end(2, "HL") . ("-" x $self->xdistance()) . $self->end(1, "HR"), 0];
779 2 100       9 push @string, [$self->end(0, "VB"), $self->offset() ? $self->xdistance() + 1: 0];
780             }
781             else {croak("Invalid orientation for Line::Corner::render. Must be 'TC' or 'BC'.\n")}
782              
783              
784 4 100       13 $self->x_coord($self->xfrom() > $self->xto() ? $self->xto() : $self->xfrom());
785 4 100       12 $self->y_coord($self->yfrom() > $self->yto() ? $self->yto() : $self->yfrom());
786 4         12 return $self->rendered(\@string);
787             };
788              
789             1;
790              
791             __END__