File Coverage

lib/App/Asciio/stripes/section_wirl_arrow.pm
Criterion Covered Total %
statement 137 425 32.2
branch 46 128 35.9
condition 16 57 28.0
subroutine 13 38 34.2
pod 0 31 0.0
total 212 679 31.2


line stmt bran cond sub pod time code
1              
2             package App::Asciio::stripes::section_wirl_arrow ;
3 2     2   1676 use base App::Asciio::stripes::stripes ;
  2         8  
  2         1455  
4              
5 2     2   18 use strict;
  2         5  
  2         61  
6 2     2   10 use warnings;
  2         6  
  2         110  
7              
8 2     2   12 use List::Util qw(min max) ;
  2         4  
  2         189  
9 2     2   14 use Readonly ;
  2         5  
  2         105  
10 2     2   13 use Clone ;
  2         4  
  2         80  
11              
12 2     2   1513 use App::Asciio::stripes::wirl_arrow ;
  2         8  
  2         15554  
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly my $DEFAULT_ARROW_TYPE =>
17             [
18             ['origin', '', '*', '', '', '', 1],
19             ['up', '|', '|', '', '', '^', 1],
20             ['down', '|', '|', '', '', 'v', 1],
21             ['left', '-', '-', '', '', '<', 1],
22             ['up-left', '|', '|', '.', '-', '<', 1],
23             ['left-up', '-', '-', '\'', '|', '^', 1],
24             ['down-left', '|', '|', '\'', '-', '<', 1],
25             ['left-down', '-', '-', '.', '|', 'v', 1],
26             ['right', '-', '-', '', '', '>', 1],
27             ['up-right', '|', '|', '.', '-', '>', 1],
28             ['right-up', '-', '-', '\'', '|', '^', 1],
29             ['down-right', '|', '|', '\'', '-', '>', 1],
30             ['right-down', '-', '-', '.', '|', 'v', 1],
31             ['45', '/', '/', '', '', '^', 1],
32             ['135', '\\', '\\', '', '', 'v', 1],
33             ['225', '/', '/', '', '', 'v', 1],
34             ['315', '\\', '\\', '', '', '^', 1],
35             ] ;
36              
37             # constants for connector overlays
38             Readonly my $body_index => 2 ;
39             Readonly my $connection_index => 3 ;
40              
41             Readonly my $up_index=> 1 ;
42             Readonly my $left_index=> 3 ;
43             Readonly my $leftup_index => 5 ;
44             Readonly my $leftdown_index => 7 ;
45             Readonly my $rightup_index => 10 ;
46             Readonly my $rightdown_index => 12 ;
47              
48             #-----------------------------------------------------------------------------
49              
50             sub new
51             {
52 96     96 0 866 my ($class, $element_definition) = @_ ;
53              
54 96         266 my $self = bless {}, __PACKAGE__ ;
55              
56             $self->setup
57             (
58             $element_definition->{ARROW_TYPE} || Clone::clone($DEFAULT_ARROW_TYPE),
59             $element_definition->{POINTS},
60             $element_definition->{DIRECTION},
61             $element_definition->{ALLOW_DIAGONAL_LINES},
62             $element_definition->{EDITABLE},
63             $element_definition->{NOT_CONNECTABLE_START},
64             $element_definition->{NOT_CONNECTABLE_END},
65 96   33     784 ) ;
66              
67 96         496 return $self ;
68             }
69              
70             #-----------------------------------------------------------------------------
71              
72             sub setup
73             {
74 96     96 0 13034 my ($self, $arrow_type, $points, $direction, $allow_diagonal_lines, $editable, $not_connectable_start, $not_connectable_end) = @_ ;
75              
76 96 50 33     915 if('ARRAY' eq ref $points && @{$points} > 0)
  96         337  
77             {
78 96         169 delete $self->{CACHE} ;
79            
80 96         246 my ($start_x, $start_y, $arrows) = (0, 0, []) ;
81            
82 96         153 my $points_offsets ;
83 96         139 my $arrow_index = 0 ; # must have a numeric index or 'undo' won't work
84            
85 96         187 for my $point (@{$points})
  96         210  
86             {
87 192         278 my ($x, $y, $point_direction) = @{$point} ;
  192         442  
88            
89 192   33     1487 my $arrow = new App::Asciio::stripes::wirl_arrow
90             ({
91             ARROW_TYPE => $arrow_type,
92             END_X => $x - $start_x,
93             END_Y => $y - $start_y,
94             DIRECTION => $point_direction || $direction,
95             ALLOW_DIAGONAL_LINES => $allow_diagonal_lines,
96             EDITABLE => $editable,
97             }) ;
98            
99 192         813 $points_offsets->[$arrow_index++] = [$start_x, $start_y] ;
100            
101 192         268 push @{$arrows}, $arrow ;
  192         305  
102 192         496 ($start_x, $start_y) = ($x, $y) ;
103             }
104            
105             $self->set
106             (
107 96         324 POINTS_OFFSETS => $points_offsets,
108             ARROWS => $arrows,
109            
110             # keep data to allow section insertion later
111             ARROW_TYPE => $arrow_type,
112             DIRECTION => $direction,
113             ALLOW_DIAGONAL_LINES => $allow_diagonal_lines,
114             EDITABLE => $editable,
115             NOT_CONNECTABLE_START => $not_connectable_start,
116             NOT_CONNECTABLE_END => $not_connectable_end,
117             ) ;
118            
119 96         268 my ($width, $height) = $self->get_width_and_height() ;
120 96         261 $self->set
121             (
122             WIDTH => $width,
123             HEIGHT => $height,
124             ) ;
125             }
126             else
127             {
128 0         0 die "Bad 'section wirl arrow' defintion! Expecting points array." ;
129             }
130             }
131              
132             #-----------------------------------------------------------------------------
133              
134             my %diagonal_direction_to_overlay_character =
135             (
136             (map {$_ => q{\\}} qw( down-right right-down up-left left-up)),
137             (map {$_ => q{/}} qw( down-left left-down up-right right-up)),
138             ) ;
139              
140             my %diagonal_non_diagonal_to_overlay_character =
141             (
142             (map {$_ => q{.}} qw( down-right right-down up-left left-up)),
143             (map {$_ => q{'}} qw( down-left left-down up-right right-up)),
144             ) ;
145              
146             sub get_stripes
147             {
148 96     96 0 155 my ($self) = @_ ;
149              
150 96         236 my $stripes = $self->{CACHE}{STRIPES} ;
151              
152 96 50       194 unless (defined $stripes)
153             {
154 96         144 my @stripes ;
155            
156 96         133 my $arrow_index = 0 ;
157 96         122 for my $arrow(@{$self->{ARROWS}})
  96         230  
158             {
159             push @stripes,
160             map
161             {
162             {
163             TEXT => $_->{TEXT},
164             WIDTH => $_->{WIDTH},
165             HEIGHT => $_->{HEIGHT} ,
166             X_OFFSET => $_->{X_OFFSET} + $self->{POINTS_OFFSETS}[$arrow_index][0],
167 461         2380 Y_OFFSET => $_->{Y_OFFSET} + $self->{POINTS_OFFSETS}[$arrow_index][1],
168             }
169 192         241 } @{$arrow->get_stripes()} ;
  192         574  
170            
171 192         396 $arrow_index++ ;
172             }
173            
174             # handle connections
175 96         568 my ($previous_direction) = ($self->{ARROWS}[0]{DIRECTION} =~ /^([^-]+)/) ;
176            
177 96         144 my $previous_was_diagonal ;
178            
179 96         121 $arrow_index = 0 ;
180 96         116 for my $arrow(@{$self->{ARROWS}})
  96         186  
181             {
182 192 50       227 last if @{$self->{ARROWS}} == 1 ;
  192         438  
183            
184 192         274 my ($connection, $d1, $d2) ;
185            
186 192 100       773 if($arrow->{DIRECTION} =~ /^([^-]+)-([^-]+)$/)
187             {
188 109         403 ($d1, $d2) = ($1, $2) ;
189             }
190             else
191             {
192 83         160 $d1 = $arrow->{DIRECTION};
193             }
194            
195 192 100 100     605 if($self->{ALLOW_DIAGONAL_LINES} && $arrow->{WIDTH} == $arrow->{HEIGHT})
196             {
197             # this section is diagonal
198 64 100 66     272 if
      100        
199             (
200             $previous_was_diagonal
201             &&
202             (
203             $previous_was_diagonal eq $arrow->{DIRECTION}
204             ||
205             (defined $d2 && $previous_was_diagonal eq "$d2-$d1")
206             )
207             )
208             {
209             # two diagonals going in the same direction
210 4         18 $connection = $diagonal_direction_to_overlay_character{$arrow->{DIRECTION}} ;
211             }
212             else
213             {
214             # previous non diagonal or two diagonals not going in the same direction
215 60 100 66     363 $connection = ($d1 eq 'up' || (defined $d2 && $d2 eq 'up')) ? q{'} : q{.} ;
216             }
217            
218 64         114 $previous_was_diagonal = $arrow->{DIRECTION} ;
219             }
220             else
221             {
222             # straight or angled arrow
223 128 100       205 if(defined $previous_was_diagonal)
224             {
225 16 100       93 if($arrow->{DIRECTION} =~ /^down/)
    100          
226             {
227 4         8 $connection = q{.} ;
228             }
229             elsif($arrow->{DIRECTION} =~ /^up/)
230             {
231 4         8 $connection = q{'} ;
232             }
233             else
234             {
235 8 100       29 $connection = $previous_was_diagonal =~ /down/ ? q{'} : q{.} ;
236             }
237             }
238             else
239             {
240 112 100       230 if($previous_direction ne $d1)
241             {
242 36 100       99 if($d1 eq 'down')
    100          
    100          
    50          
243             {
244 8 100       21 if($previous_direction eq 'right')
    50          
245             {
246 4         14 $connection = $self->{ARROW_TYPE}[$rightdown_index][$connection_index] ;
247             }
248             elsif($previous_direction eq 'left')
249             {
250 4         9 $connection = $self->{ARROW_TYPE}[$leftdown_index][$connection_index] ;
251             }
252             else
253             {
254 0         0 $connection = $self->{ARROW_TYPE}[$up_index][$connection_index] ;
255             }
256             }
257             elsif($d1 eq 'up')
258             {
259 10 100       27 if($previous_direction eq 'right')
    50          
260             {
261 5         25 $connection = $self->{ARROW_TYPE}[$rightup_index][$connection_index] ;
262             }
263             elsif($previous_direction eq 'left')
264             {
265 5         15 $connection = $self->{ARROW_TYPE}[$leftup_index][$connection_index] ;
266             }
267             else
268             {
269 0         0 $connection = $self->{ARROW_TYPE}[$up_index][$connection_index] ;
270             }
271             }
272             elsif($previous_direction eq 'down')
273             {
274 9 100       20 if($d1 eq 'left')
275             {
276 4         19 $connection = $self->{ARROW_TYPE}[$rightup_index][$connection_index] ;
277             }
278             else
279             {
280 5         12 $connection = $self->{ARROW_TYPE}[$leftup_index][$connection_index] ;
281             }
282             }
283             elsif($previous_direction eq 'up')
284             {
285 9 100       16 if($d1 eq 'left')
286             {
287 4         20 $connection = $self->{ARROW_TYPE}[$rightdown_index][$connection_index] ;
288             }
289             else
290             {
291 5         10 $connection = $self->{ARROW_TYPE}[$leftdown_index][$connection_index] ;
292             }
293             }
294             else
295             {
296 0         0 $connection = $self->{ARROW_TYPE}[$left_index][$body_index] ;
297             }
298             }
299             }
300            
301 128 100       470 $previous_direction = defined $d2 ? $d2 : $d1 ;
302 128         190 $previous_was_diagonal = undef ;
303             }
304            
305 192 100 100     568 if($arrow_index != 0 && defined $connection) # first character of the first section is always right
306             {
307             # overlay the first character of this arrow
308             push @stripes,
309             {
310             TEXT => $connection,
311             WIDTH => 1,
312             HEIGHT => 1,
313             X_OFFSET => $self->{POINTS_OFFSETS}[$arrow_index][0],
314 84         515 Y_OFFSET => $self->{POINTS_OFFSETS}[$arrow_index][1],
315             } ;
316             }
317            
318 192         363 $arrow_index++ ;
319             }
320            
321 96         361 $stripes = $self->{CACHE}{STRIPES} = \@stripes ;
322             }
323              
324 96         316 return $stripes ;
325             }
326              
327             #-----------------------------------------------------------------------------
328              
329             sub get_selection_action
330             {
331 0     0 0 0 my ($self, $x, $y) = @_ ;
332              
333 0         0 my $action = 'move' ;
334              
335 0         0 my $arrow_index = 0 ;
336 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
337             {
338 0         0 my ($start_connector, $end_connector) = $arrow->get_connector_points() ;
339            
340 0         0 $start_connector->{X} += $self->{POINTS_OFFSETS}[$arrow_index][0] ;
341 0         0 $start_connector->{Y} += $self->{POINTS_OFFSETS}[$arrow_index][1] ;
342            
343 0 0 0     0 if($x == $start_connector->{X} && $y == $start_connector->{Y})
344             {
345 0         0 $action = 'resize' ;
346 0         0 last ;
347             }
348            
349 0         0 $end_connector->{X} += $self->{POINTS_OFFSETS}[$arrow_index][0] ;
350 0         0 $end_connector->{Y} += $self->{POINTS_OFFSETS}[$arrow_index][1] ;
351            
352 0 0 0     0 if($x == $end_connector->{X} && $y == $end_connector->{Y})
353             {
354 0         0 $action = 'resize' ;
355 0         0 last ;
356             }
357            
358 0         0 $arrow_index++ ;
359             }
360              
361 0         0 return $action ;
362             }
363              
364             #-----------------------------------------------------------------------------
365              
366             sub allow_connection
367             {
368 0     0 0 0 my ($self, $which, $connect) = @_ ;
369              
370 0 0       0 if($which eq 'start')
371             {
372 0         0 $self->{NOT_CONNECTABLE_START} = !$connect ;
373             }
374             else
375             {
376 0         0 $self->{NOT_CONNECTABLE_END} = !$connect ;
377             }
378             }
379              
380             #-----------------------------------------------------------------------------
381              
382             sub is_connection_allowed
383             {
384 0     0 0 0 my ($self, $which) = @_ ;
385              
386 0 0       0 if($which eq 'start')
387             {
388 0         0 return(! $self->{NOT_CONNECTABLE_START}) ;
389             }
390             else
391             {
392 0         0 return(! $self->{NOT_CONNECTABLE_END}) ;
393             }
394             }
395              
396             #-----------------------------------------------------------------------------
397              
398             sub are_diagonals_allowed
399             {
400 0     0 0 0 my ($self, $allow) = @_ ;
401 0         0 return $self->{ALLOW_DIAGONAL_LINES} ;
402             }
403              
404             #-----------------------------------------------------------------------------
405              
406             sub allow_diagonals
407             {
408 0     0 0 0 my ($self, $allow) = @_ ;
409 0         0 $self->{ALLOW_DIAGONAL_LINES} = $allow ;
410              
411 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
412             {
413 0         0 $arrow->{ALLOW_DIAGONAL_LINES} = $allow ;
414             }
415             }
416              
417             #-----------------------------------------------------------------------------
418              
419             sub get_connector_points
420             {
421 96     96 0 163 my ($self) = @_ ;
422              
423 96         210 my (@all_connector_points) = $self->get_all_points() ;
424 96         129 my (@connector_points) ;
425              
426 96 50       266 push @connector_points, $all_connector_points[0] unless $self->{NOT_CONNECTABLE_START} ;
427 96 50       245 push @connector_points, $all_connector_points[-1] unless $self->{NOT_CONNECTABLE_END} ;
428              
429 96         344 return(@connector_points) ;
430             }
431              
432             #-----------------------------------------------------------------------------
433              
434             sub get_extra_points
435             {
436 0     0 0 0 my ($self) = @_ ;
437              
438 0         0 my(@all_connector_points) = $self->get_all_points() ;
439              
440 0 0       0 shift @all_connector_points unless $self->{NOT_CONNECTABLE_START} ;
441 0 0       0 pop @all_connector_points unless $self->{NOT_CONNECTABLE_END} ;
442              
443 0         0 return(@all_connector_points) ;
444             }
445              
446             #-----------------------------------------------------------------------------
447              
448             sub get_all_points
449             {
450 96     96 0 153 my ($self) = @_ ;
451              
452 96         137 my(@connector_points) ;
453              
454 96         166 my $arrow_index = 0 ;
455              
456 96         129 for my $arrow(@{$self->{ARROWS}})
  96         201  
457             {
458 192         408 my ($start_connector, $end_connector) = $arrow->get_connector_points() ;
459            
460 192 100       534 if($arrow == $self->{ARROWS}[0])
461             {
462 96         201 $start_connector->{X} += $self->{POINTS_OFFSETS}[$arrow_index][0] ;
463 96         165 $start_connector->{Y} += $self->{POINTS_OFFSETS}[$arrow_index][1] ;
464 96         243 $start_connector->{NAME} .= "section_$arrow_index" ;
465            
466 96         165 push @connector_points, $start_connector ;
467             }
468            
469 192         328 $end_connector->{X} += $self->{POINTS_OFFSETS}[$arrow_index][0] ;
470 192         292 $end_connector->{Y} += $self->{POINTS_OFFSETS}[$arrow_index][1] ;
471 192         343 $end_connector->{NAME} .= "section_$arrow_index" ;
472            
473 192         259 push @connector_points, $end_connector ;
474 192         418 $arrow_index++ ;
475             }
476              
477 96         314 return(@connector_points) ;
478             }
479              
480             #-----------------------------------------------------------------------------
481              
482             sub get_named_connection
483             {
484 0     0 0 0 my ($self, $name) = @_ ;
485              
486 0         0 my $connection ;
487              
488 0         0 my $arrow_index = 0 ;
489              
490 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
491             {
492 0         0 my ($start_connector, $end_connector) = $arrow->get_connector_points() ;
493            
494 0 0       0 if($arrow == $self->{ARROWS}[0])
495             {
496 0         0 $start_connector->{NAME} .= "section_$arrow_index" ;
497            
498 0 0       0 if($name eq $start_connector->{NAME})
499             {
500 0         0 $start_connector->{X} += $self->{POINTS_OFFSETS}[$arrow_index][0] ;
501 0         0 $start_connector->{Y} += $self->{POINTS_OFFSETS}[$arrow_index][1] ;
502 0         0 $connection = $start_connector ;
503            
504 0         0 for my $arrow_type (@{$arrow->{ARROW_TYPE}})
  0         0  
505             {
506 0 0 0     0 $connection->{CHAR} = $arrow_type->[1] and last if $arrow->{DIRECTION} eq $arrow_type->[0] ;
507             }
508            
509 0         0 last ;
510             }
511             }
512            
513 0         0 $end_connector->{NAME} .= "section_$arrow_index" ;
514            
515 0 0       0 if($name eq $end_connector->{NAME})
516             {
517 0         0 $end_connector->{X} += $self->{POINTS_OFFSETS}[$arrow_index][0] ;
518 0         0 $end_connector->{Y} += $self->{POINTS_OFFSETS}[$arrow_index][1] ;
519 0         0 $connection = $end_connector ;
520            
521 0         0 for my $arrow_type (@{$arrow->{ARROW_TYPE}})
  0         0  
522             {
523 0 0 0     0 $connection->{CHAR} = $arrow_type->[5] and last if $arrow->{DIRECTION} eq $arrow_type->[0] ;
524             }
525            
526 0         0 last ;
527             }
528            
529 0         0 $arrow_index++ ;
530             }
531              
532 0         0 return $connection ;
533             }
534              
535             #-----------------------------------------------------------------------------
536              
537             sub move_connector
538             {
539 0     0 0 0 my ($self, $connector_name, $x_offset, $y_offset, $hint) = @_ ;
540              
541 0         0 my $connection = $self->get_named_connection($connector_name) ;
542              
543 0         0 (my $no_section_connetor_name = $connector_name) =~ s/section_.*// ;
544              
545 0 0       0 if($connection)
546             {
547 0         0 delete $self->{CACHE} ;
548            
549             my ($x_offset, $y_offset, $width, $height, undef) =
550             $self->resize
551             (
552             $connection->{X},
553             $connection->{Y},
554             $connection->{X} + $x_offset,
555 0         0 $connection->{Y} + $y_offset,
556             $hint,
557             #~ [$no_section_connetor_name, $connector_name],
558             [$connector_name, $no_section_connetor_name],
559             ) ;
560            
561             return
562             (
563 0         0 $x_offset, $y_offset, $width, $height,
564             $self->get_named_connection($connector_name)
565             ) ;
566             }
567             else
568             {
569 0         0 die "unknown connector '$connector_name'!\n" ;
570             }
571             }
572              
573             #-----------------------------------------------------------------------------
574              
575             sub resize
576             {
577 0     0 0 0 my ($self, $reference_x, $reference_y, $new_x, $new_y, $hint, $connector_name_array) = @_ ;
578              
579 0         0 Readonly my $MULTI_WIRL_CONNECTOR_NAME_INDEX => 0 ;
580 0         0 Readonly my $WIRL_CONNECTOR_NAME_INDEX => 1 ;
581              
582 0         0 delete $self->{CACHE} ;
583              
584 0         0 my ($start_element, $start_element_index, $end_element, $end_element_index) ;
585              
586             # find elements connected by the connector
587 0 0       0 if(defined $connector_name_array)
588             {
589 0         0 ($start_element, $start_element_index, $end_element, $end_element_index, $connector_name_array) =
590             $self->find_elements_for_connector_named($connector_name_array) ;
591             }
592             else
593             {
594 0         0 ($start_element, $start_element_index, $end_element, $end_element_index, $connector_name_array) =
595             $self->find_elements_for_connector_at($reference_x, $reference_y) ;
596             }
597              
598 0         0 my ($start_x_offset, $start_y_offset) = (0, 0) ;
599 0 0       0 if(defined $start_element)
600             {
601 0         0 my $is_start ;
602 0 0       0 if(defined $connector_name_array)
603             {
604 0 0 0     0 if
605             (
606             $connector_name_array->[$WIRL_CONNECTOR_NAME_INDEX] eq 'start'
607             || $connector_name_array->[$MULTI_WIRL_CONNECTOR_NAME_INDEX] eq 'startsection_0'
608             )
609             {
610 0         0 $is_start++ ;
611             }
612             }
613             else
614             {
615 0 0 0     0 if($reference_x == 0 && $reference_y == 0)
616             {
617 0         0 $is_start++ ;
618             }
619             }
620            
621 0 0       0 if($is_start)
622             {
623             #~ print "Moving start connector\n" ;
624            
625 0         0 ($start_x_offset, $start_y_offset) =
626             $start_element->resize
627             (
628             0, 0,
629             $new_x, $new_y,
630             $hint,
631             $connector_name_array->[$WIRL_CONNECTOR_NAME_INDEX]
632             ) ;
633            
634 0         0 my $arrow_index = 0 ;
635 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
636             {
637             # offsets all other wirl_arrow start offsets
638 0 0       0 if($arrow == $start_element)
639             {
640             }
641             else
642             {
643 0         0 $self->{POINTS_OFFSETS}[$arrow_index][0] -= $start_x_offset ;
644 0         0 $self->{POINTS_OFFSETS}[$arrow_index][1] -= $start_y_offset ;
645             }
646            
647 0         0 $arrow_index++ ;
648             }
649             }
650             else
651             {
652 0         0 my $start_element_x_offset = $self->{POINTS_OFFSETS}[$start_element_index][0] ;
653 0         0 my $start_element_y_offset = $self->{POINTS_OFFSETS}[$start_element_index][1] ;
654            
655 0         0 my ($x_offset, $y_offset) =
656             $start_element ->resize
657             (
658             $reference_x - $start_element_x_offset,
659             $reference_y - $start_element_y_offset,
660             $new_x - $start_element_x_offset,
661             $new_y - $start_element_y_offset,
662             $hint,
663             $connector_name_array->[$WIRL_CONNECTOR_NAME_INDEX]
664             ) ;
665            
666 0         0 $self->{POINTS_OFFSETS}[$start_element_index][0] += $x_offset ;
667 0         0 $self->{POINTS_OFFSETS}[$start_element_index][1] += $y_offset ;
668            
669 0 0       0 if(defined $end_element)
670             {
671 0         0 my ($x_offset, $y_offset) = $end_element->resize(0, 0, $new_x - $reference_x, $new_y - $reference_y) ;
672 0         0 $self->{POINTS_OFFSETS}[$end_element_index][0] += $x_offset ;
673 0         0 $self->{POINTS_OFFSETS}[$end_element_index][1] += $y_offset ;
674             }
675             }
676             }
677              
678 0         0 my ($width, $height) = $self->get_width_and_height() ;
679 0         0 $self->set(WIDTH => $width, HEIGHT => $height) ;
680              
681 0         0 return($start_x_offset, $start_y_offset, $width, $height, $connector_name_array) ;
682             }
683              
684             sub find_elements_for_connector_at
685             {
686 0     0 0 0 my ($self, $reference_x, $reference_y) = @_ ;
687              
688 0         0 my ($start_element, $start_element_index, $end_element, $end_element_index, $connector_name, $wirl_connector_name) ;
689              
690 0         0 my $arrow_index = 0 ;
691 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
692             {
693 0         0 my ($start_connector, $end_connector) = $arrow->get_connector_points() ;
694            
695 0 0 0     0 if($reference_x == 0 && $reference_y == 0)
696             {
697 0         0 ($start_element, $start_element_index) = ($arrow, $arrow_index) ;
698 0         0 $wirl_connector_name = $start_connector->{NAME} ;
699 0         0 $connector_name = $wirl_connector_name . "section_$arrow_index" ;
700 0         0 last ;
701             }
702            
703 0 0       0 if(defined $start_element)
704             {
705 0         0 ($end_element, $end_element_index) = ($arrow, $arrow_index) ;
706 0         0 last ;
707             }
708            
709 0 0 0     0 if
710             (
711             $reference_x == $end_connector->{X} + $self->{POINTS_OFFSETS}[$arrow_index][0]
712             && $reference_y == $end_connector->{Y} + $self->{POINTS_OFFSETS}[$arrow_index][1]
713             )
714             {
715 0         0 ($start_element, $start_element_index) = ($arrow, $arrow_index) ;
716 0         0 $wirl_connector_name = $end_connector->{NAME} ;
717 0         0 $connector_name = $wirl_connector_name . "section_$arrow_index" ;
718             }
719            
720 0         0 $arrow_index++ ;
721             }
722              
723 0         0 return($start_element, $start_element_index, $end_element, $end_element_index, [$connector_name, $wirl_connector_name])
724             }
725              
726             sub find_elements_for_connector_named
727             {
728 0     0 0 0 my ($self, $connector_name_array) = @_ ;
729              
730 0         0 my ($connector_name, $wirl_connector_name) = @{$connector_name_array} ;
  0         0  
731              
732 0         0 my ($start_element, $start_element_index, $end_element, $end_element_index) ;
733              
734 0         0 my $arrow_index = 0 ;
735 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
736             {
737 0         0 my ($start_connector, $end_connector) = $arrow->get_connector_points() ;
738            
739 0 0       0 if($connector_name eq $start_connector->{NAME} . "section_$arrow_index" )
740             {
741 0         0 ($start_element, $start_element_index) = ($arrow, $arrow_index) ;
742 0         0 last ;
743             }
744            
745 0 0       0 if(defined $start_element)
746             {
747 0         0 ($end_element, $end_element_index) = ($arrow, $arrow_index) ;
748 0         0 last ;
749             }
750            
751 0 0       0 if($connector_name eq $end_connector->{NAME} . "section_$arrow_index")
752             {
753 0         0 ($start_element, $start_element_index) = ($arrow, $arrow_index) ;
754             }
755            
756 0         0 $arrow_index++ ;
757             }
758              
759 0         0 return($start_element, $start_element_index, $end_element, $end_element_index, $connector_name_array) ;
760             }
761              
762             #-----------------------------------------------------------------------------
763              
764 0     0 0 0 sub get_number_of_sections { my ($self) = @_ ; return scalar(@{$self->{ARROWS}}) ; }
  0         0  
  0         0  
765              
766             #-----------------------------------------------------------------------------
767              
768             sub get_section_direction
769             {
770 0     0 0 0 my ($self, $section_index) = @_ ;
771              
772 0 0       0 if(exists($self->{ARROWS}[$section_index]))
773             {
774 0         0 return $self->{ARROWS}[$section_index]->get_direction() ;
775             }
776             else
777             {
778 0         0 return ;
779             }
780             }
781              
782             #-----------------------------------------------------------------------------
783              
784             sub insert_section
785             {
786 0     0 0 0 my ($self, $x_offset, $y_offset) = @_ ;
787              
788 0         0 delete $self->{CACHE} ;
789              
790 0         0 my $index = 0 ;
791              
792 0         0 for my $arrow (@{$self->{ARROWS}})
  0         0  
793             {
794 0 0       0 if
795             (
796             $self->is_over_element
797             (
798             $arrow,
799             $x_offset, $y_offset, 0,
800 0         0 @{$self->{POINTS_OFFSETS}[$index]}
801             )
802             )
803             {
804 0         0 my ($original_arrow_end_x, $original_arrow_end_y) = ($arrow->{END_X}, $arrow->{END_Y}) ;
805            
806             my $first_section = new App::Asciio::stripes::wirl_arrow
807             ({
808             END_X => $x_offset - $self->{POINTS_OFFSETS}[$index][0],
809             END_Y => $y_offset - $self->{POINTS_OFFSETS}[$index][1],
810             ARROW_TYPE => $arrow->{ARROW_TYPE},
811             DIRECTION => $arrow->{DIRECTION},
812             ALLOW_DIAGONAL_LINES => $arrow->{ALLOW_DIAGONAL_LINES},
813             EDITABLE => $arrow->{EDITABLE},
814 0         0 }) ;
815            
816 0         0 $self->{ARROWS}[$index] = $first_section ;
817            
818             my $new_section = new App::Asciio::stripes::wirl_arrow
819             ({
820             END_X => ($self->{POINTS_OFFSETS}[$index][0] + $original_arrow_end_x) - $x_offset,
821             END_Y => ($self->{POINTS_OFFSETS}[$index][1] + $original_arrow_end_y) - $y_offset,
822             ARROW_TYPE => $arrow->{ARROW_TYPE},
823             DIRECTION => $arrow->{DIRECTION},
824             ALLOW_DIAGONAL_LINES => $arrow->{ALLOW_DIAGONAL_LINES},
825             EDITABLE => $arrow->{EDITABLE},
826 0         0 }) ;
827            
828 0         0 splice @{$self->{ARROWS}}, $index + 1, 0, $new_section ;
  0         0  
829 0         0 splice @{$self->{POINTS_OFFSETS}}, $index + 1, 0, [$x_offset, $y_offset] ;
  0         0  
830            
831 0         0 last ;
832             }
833            
834 0         0 $index++ ;
835             }
836             }
837              
838             #-----------------------------------------------------------------------------
839              
840             sub prepend_section
841             {
842 0     0 0 0 my ($self, $extend_x, $extend_y) = @_ ;
843              
844 0         0 delete $self->{CACHE} ;
845              
846             my $arrow = new App::Asciio::stripes::wirl_arrow
847             ({
848             END_X => -$extend_x,
849             END_Y => -$extend_y,
850             ARROW_TYPE => $self->{ARROW_TYPE},
851             DIRECTION => $self->{DIRECTION},
852             ALLOW_DIAGONAL_LINES => $self->{ALLOW_DIAGONAL_LINES},
853             EDITABLE => $self->{EDITABLE},
854 0         0 }) ;
855              
856 0         0 my $arrow_index = 0 ;
857 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
858             {
859 0         0 $self->{POINTS_OFFSETS}[$arrow_index][0] += -$extend_x ;
860 0         0 $self->{POINTS_OFFSETS}[$arrow_index][1] += -$extend_y ;
861            
862 0         0 $arrow_index++ ;
863             }
864              
865 0         0 unshift @{$self->{POINTS_OFFSETS}}, [0, 0] ;
  0         0  
866 0         0 unshift @{$self->{ARROWS}}, $arrow ;
  0         0  
867              
868 0         0 my ($width, $height) = $self->get_width_and_height() ;
869 0         0 $self->set(WIDTH => $width, HEIGHT => $height,) ;
870             }
871              
872             #-----------------------------------------------------------------------------
873              
874             sub append_section
875             {
876 0     0 0 0 my ($self, $extend_x, $extend_y) = @_ ;
877              
878 0         0 delete $self->{CACHE} ;
879              
880 0         0 my $last_point = $self->get_points()->[-1] ;
881              
882             my $arrow = new App::Asciio::stripes::wirl_arrow
883             ({
884             END_X => $extend_x - $last_point->[0],
885             END_Y => $extend_y - $last_point->[1],
886             ARROW_TYPE => $self->{ARROW_TYPE},
887             DIRECTION => $self->{DIRECTION},
888             ALLOW_DIAGONAL_LINES => $self->{ALLOW_DIAGONAL_LINES},
889             EDITABLE => $self->{EDITABLE},
890 0         0 }) ;
891              
892 0         0 my ($start_x, $start_y) = @{$self->{POINTS_OFFSETS}[-1]} ;
  0         0  
893 0         0 my ($start_connector, $end_connector) = $self->{ARROWS}[-1]->get_connector_points() ;
894              
895 0         0 $start_x += $end_connector->{X} ;
896 0         0 $start_y += $end_connector->{Y} ;
897              
898 0         0 push @{$self->{POINTS_OFFSETS}}, [$start_x, $start_y] ;
  0         0  
899 0         0 push @{$self->{ARROWS}}, $arrow ;
  0         0  
900              
901 0         0 my ($width, $height) = $self->get_width_and_height() ;
902 0         0 $self->set(WIDTH => $width, HEIGHT => $height,) ;
903             }
904              
905             #-----------------------------------------------------------------------------
906              
907             sub remove_last_section
908             {
909 0     0 0 0 my ($self) = @_ ;
910              
911 0 0       0 return if @{$self->{ARROWS}} == 1 ;
  0         0  
912              
913 0         0 delete $self->{CACHE} ;
914              
915 0         0 pop @{$self->{POINTS_OFFSETS}} ;
  0         0  
916 0         0 pop @{$self->{ARROWS}} ;
  0         0  
917              
918 0         0 my ($width, $height) = $self->get_width_and_height() ;
919 0         0 $self->set(WIDTH => $width, HEIGHT => $height,) ;
920             }
921              
922             #-----------------------------------------------------------------------------
923              
924             sub remove_first_section
925             {
926 0     0 0 0 my ($self) = @_ ;
927              
928 0 0       0 return(0, 0) if @{$self->{ARROWS}} == 1 ;
  0         0  
929              
930 0         0 delete $self->{CACHE} ;
931              
932 0         0 my $second_arrow_x_offset = $self->{POINTS_OFFSETS}[1][0] ;
933 0         0 my $second_arrow_y_offset = $self->{POINTS_OFFSETS}[1][1] ;
934              
935 0         0 shift @{$self->{POINTS_OFFSETS}} ;
  0         0  
936 0         0 shift @{$self->{ARROWS}} ;
  0         0  
937              
938 0         0 my $arrow_index = 0 ;
939 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
940             {
941 0         0 $self->{POINTS_OFFSETS}[$arrow_index][0] -= $second_arrow_x_offset ;
942 0         0 $self->{POINTS_OFFSETS}[$arrow_index][1] -= $second_arrow_y_offset ;
943            
944 0         0 $arrow_index++ ;
945             }
946              
947 0         0 my ($width, $height) = $self->get_width_and_height() ;
948 0         0 $self->set(WIDTH => $width, HEIGHT => $height,) ;
949              
950 0         0 return($second_arrow_x_offset, $second_arrow_y_offset) ;
951             }
952              
953             #-----------------------------------------------------------------------------
954              
955             sub change_section_direction
956             {
957 0     0 0 0 my ($self, $x, $y) = @_ ;
958              
959 0         0 delete $self->{CACHE} ;
960              
961 0 0       0 if(1 == @{$self->{ARROWS}})
  0         0  
962             {
963 0         0 my $direction = $self->{ARROWS}[0]->get_direction() ;
964            
965 0 0       0 if($direction =~ /(.*)-(.*)/)
966             {
967 0         0 $self->{ARROWS}[0]->resize(0, 0, 0, 0, "$2-$1") ;
968             }
969             }
970             else
971             {
972 0         0 my $index = 0 ;
973            
974 0         0 for my $arrow(@{$self->{ARROWS}})
  0         0  
975             {
976 0 0       0 if
977             (
978             $self->is_over_element
979             (
980             $arrow,
981             $x, $y, 0,
982 0         0 @{$self->{POINTS_OFFSETS}[$index]}
983             )
984             )
985             {
986 0         0 my $direction = $arrow->get_direction() ;
987            
988 0 0       0 if($direction =~ /(.*)-(.*)/)
989             {
990 0         0 $arrow->resize(0, 0, 0, 0, "$2-$1") ;
991             }
992            
993 0         0 last ;
994             }
995            
996 0         0 $index++ ;
997             }
998             }
999             }
1000              
1001             #-----------------------------------------------------------------------------
1002              
1003             sub change_last_section_direction
1004             {
1005 0     0 0 0 my ($self, $x, $y) = @_ ;
1006              
1007 0         0 delete $self->{CACHE} ;
1008              
1009 0         0 my $direction = $self->{ARROWS}[-1]->get_direction() ;
1010              
1011 0 0       0 if($direction =~ /(.*)-(.*)/)
1012             {
1013 0         0 $self->{ARROWS}[-1]->resize(0, 0, 0, 0, "$2-$1") ;
1014             }
1015             }
1016              
1017             #-----------------------------------------------------------------------------
1018              
1019             sub is_over_element
1020             {
1021 0     0 0 0 my ($self, $element, $x, $y, $field, $element_offset_x, $element_offset_y, ) = @_ ;
1022              
1023 0   0     0 $field ||= 0 ;
1024 0         0 my $is_under = 0 ;
1025              
1026 0         0 for my $strip (@{$element->get_stripes()})
  0         0  
1027             {
1028 0         0 my $stripe_x = $element_offset_x + $strip->{X_OFFSET} ;
1029 0         0 my $stripe_y = $element_offset_y + $strip->{Y_OFFSET} ;
1030            
1031 0 0 0     0 if
      0        
      0        
1032             (
1033             $stripe_x - $field <= $x && $x < $stripe_x + $strip->{WIDTH} + $field
1034             && $stripe_y - $field <= $y && $y < $stripe_y + $strip->{HEIGHT} + $field
1035             )
1036             {
1037 0         0 $is_under++ ;
1038 0         0 last ;
1039             }
1040             }
1041              
1042 0         0 return($is_under) ;
1043             }
1044              
1045             #-----------------------------------------------------------------------------
1046              
1047             sub get_width_and_height
1048             {
1049 96     96 0 172 my ($self) = @_ ;
1050              
1051 96         218 my ($smallest_x, $biggest_x, $smallest_y, $biggest_y) = (0, 0, 0, 0) ;
1052              
1053 96         137 my $arrow_index = 0 ;
1054 96         116 for my $start_point (@{$self->{POINTS_OFFSETS}})
  96         322  
1055             {
1056 192         284 my ($x, $y) = @{$start_point} ;
  192         333  
1057            
1058 192         566 my ($start_connector, $end_connector) = $self->{ARROWS}[$arrow_index]->get_connector_points() ;
1059 192         321 $x += $end_connector->{X} ;
1060 192         263 $y += $end_connector->{Y} ;
1061            
1062 192         453 $smallest_x = min($smallest_x, $x) ;
1063 192         322 $smallest_y = min($smallest_y, $y) ;
1064 192         344 $biggest_x = max($biggest_x, $x) ;
1065 192         289 $biggest_y = max($biggest_y, $y) ;
1066            
1067 192         596 $arrow_index++ ;
1068             }
1069              
1070 96         281 $self->{EXTENTS} = [$smallest_x, $smallest_y, $biggest_x + 1, $biggest_y + 1] ;
1071              
1072 96         241 return(($biggest_x - $smallest_x) + 1, ($biggest_y - $smallest_y) + 1) ;
1073             }
1074              
1075             #-----------------------------------------------------------------------------
1076              
1077 0     0 0   sub get_arrow_type { my ($self) = @_ ; return($self->{ARROW_TYPE}) ; }
  0            
1078              
1079             #-----------------------------------------------------------------------------
1080              
1081             sub set_arrow_type
1082             {
1083 0     0 0   my ($self, $arrow_type) = @_ ;
1084              
1085 0           delete $self->{CACHE} ;
1086 0           $self->setup($arrow_type, $self->get_points(), $self->{DIRECTION}, $self->{ALLOW_DIAGONAL_LINES}, $self->{EDITABLE}) ;
1087             }
1088              
1089             #-----------------------------------------------------------------------------
1090              
1091             sub get_points
1092             {
1093 0     0 0   my ($self) = @_ ;
1094              
1095 0           my @points ;
1096 0           my $arrow_index = 0 ;
1097              
1098 0           for my $point_offset (@{$self->{POINTS_OFFSETS}})
  0            
1099             {
1100 0           my ($x_offset, $y_offset) = @{$point_offset} ;
  0            
1101             my ($start_connector, $end_connector, $direction)
1102             = (
1103             $self->{ARROWS}[$arrow_index]->get_connector_points(),
1104 0           $self->{ARROWS}[$arrow_index]->get_direction()
1105             ) ;
1106            
1107 0           push @points, [$x_offset + $end_connector->{X}, $y_offset + $end_connector->{Y}, $direction] ;
1108            
1109 0           $arrow_index++ ;
1110             }
1111              
1112 0           return \@points ;
1113             }
1114              
1115             #-----------------------------------------------------------------------------
1116              
1117             sub edit
1118             {
1119 0     0 0   my ($self) = @_ ;
1120              
1121 0 0         return unless $self->{EDITABLE} ;
1122              
1123 0           delete $self->{CACHE} ;
1124              
1125 0           $self->display_arrow_edit_dialog() ;
1126             }
1127              
1128             #-----------------------------------------------------------------------------
1129              
1130             1 ;
1131