| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Imager::DTP::Textbox; | 
| 2 | 2 |  |  | 2 |  | 12 | use strict; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 66 |  | 
| 3 | 2 |  |  | 2 |  | 10 | use Carp; | 
|  | 2 |  |  |  |  | 10 |  | 
|  | 2 |  |  |  |  | 185 |  | 
| 4 | 2 |  |  | 2 |  | 5198 | use Imager; | 
|  | 2 |  |  |  |  | 107971 |  | 
|  | 2 |  |  |  |  | 19 |  | 
| 5 | 2 |  |  | 2 |  | 158 | use vars qw($VERSION); | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 7530 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | $VERSION = '0.04'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | sub new { | 
| 10 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 11 | 0 |  |  |  |  |  | my %o = @_; | 
| 12 |  |  |  |  |  |  | # define properties | 
| 13 | 0 |  |  |  |  |  | my $p = { | 
| 14 |  |  |  |  |  |  | lines   => [], | 
| 15 |  |  |  |  |  |  | leading => 150, | 
| 16 |  |  |  |  |  |  | width   => 0, | 
| 17 |  |  |  |  |  |  | height  => 0, | 
| 18 |  |  |  |  |  |  | halign  => '', | 
| 19 |  |  |  |  |  |  | valign  => '', | 
| 20 |  |  |  |  |  |  | wrapWidth  => 0, | 
| 21 |  |  |  |  |  |  | wrapHeight => 0, | 
| 22 |  |  |  |  |  |  | isUpdated  => 0, # check flag for _calcWidthHeight needs | 
| 23 |  |  |  |  |  |  | }; | 
| 24 | 0 |  |  |  |  |  | $self = bless($p,$self); | 
| 25 |  |  |  |  |  |  | # set properties | 
| 26 | 0 |  |  |  |  |  | $self->setLeading(percent=>$o{leading}); | 
| 27 | 0 |  |  |  |  |  | $self->setAlign(valign=>$o{valign},halign=>$o{halign}); | 
| 28 | 0 |  |  |  |  |  | $self->setWrap(width=>$o{wrapWidth},height=>$o{wrapHeight}); | 
| 29 | 0 | 0 |  |  |  |  | if(defined($o{text})){ | 
| 30 | 0 |  |  |  |  |  | $self->setText(text=>$o{text},font=>$o{font}); | 
| 31 | 0 |  |  |  |  |  | $self->setWspace(pixel=>$o{wspace}); | 
| 32 |  |  |  |  |  |  | } | 
| 33 | 0 | 0 | 0 |  |  |  | if($o{xscale} || $o{yscale}){ | 
| 34 | 0 |  |  |  |  |  | $self->setLetterScale(x=>$o{xscale},y=>$o{yscale}); | 
| 35 |  |  |  |  |  |  | } | 
| 36 | 0 |  |  |  |  |  | return $self; | 
| 37 |  |  |  |  |  |  | } | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | sub draw { | 
| 40 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 41 | 0 |  |  |  |  |  | my %o = @_; | 
| 42 |  |  |  |  |  |  | # validation | 
| 43 | 0 | 0 | 0 |  |  |  | if($o{target} && ref($o{target}) !~ /^Imager(::.+)?$/){ | 
| 44 | 0 |  |  |  |  |  | confess "target: must be an Imager Object"; | 
| 45 |  |  |  |  |  |  | } | 
| 46 | 0 | 0 |  |  |  |  | $o{x} = 0 if(!$o{x}); | 
| 47 | 0 | 0 |  |  |  |  | $o{y} = 0 if(!$o{y}); | 
| 48 |  |  |  |  |  |  | # calculate width and height | 
| 49 | 0 |  |  |  |  |  | $self->_calcWidthHeight(); | 
| 50 |  |  |  |  |  |  | # calculate text wrap | 
| 51 | 0 |  |  |  |  |  | $self->_calcWrap(); | 
| 52 |  |  |  |  |  |  | # draw directly to target image | 
| 53 | 0 | 0 |  |  |  |  | if($o{target}){ | 
| 54 | 0 |  |  |  |  |  | my($x,$y) = $self->_draw_getStartPos(x=>$o{x},y=>$o{y}); | 
| 55 | 0 |  |  |  |  |  | $self->_draw_drawLines(target=>$o{target},x=>$x,y=>$y,debug=>$o{debug},others=>$o{others}); | 
| 56 | 0 |  |  |  |  |  | return 1; | 
| 57 |  |  |  |  |  |  | # or return drawn Imager object | 
| 58 |  |  |  |  |  |  | }else{ | 
| 59 | 0 | 0 |  |  |  |  | my $tmp = Imager->new(xsize=>$self->_getWidth(), | 
| 60 |  |  |  |  |  |  | ysize=>$self->_getHeight(),channels=>3) or die $Imager::ERRSTR; | 
| 61 | 0 | 0 |  |  |  |  | $o{bgcolor} = '$FFFFFF' if(!$o{bgcolor}); | 
| 62 | 0 |  |  |  |  |  | $tmp->box(filled=>1,color=>$o{bgcolor}); | 
| 63 | 0 |  |  |  |  |  | $self->_draw_drawLines(target=>$tmp,debug=>$o{debug},others=>$o{others}); | 
| 64 | 0 |  |  |  |  |  | return $tmp; | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | sub _draw_drawLines { | 
| 69 | 0 |  |  | 0 |  |  | confess "_draw_drawLines - this is an abstract method"; | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | sub _draw_getAlignPos { | 
| 73 | 0 |  |  | 0 |  |  | confess "_draw_getAlignPos - this is an abstract method"; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | sub _draw_getStartPos { | 
| 77 | 0 |  |  | 0 |  |  | confess "_draw_getStartPos - this is an abstract method"; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | sub _calcWidthHeight { | 
| 81 | 0 |  |  | 0 |  |  | confess "_calcWidthHeight - this is an abstract method"; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | sub _calcWrap { | 
| 85 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 86 |  |  |  |  |  |  | # letter wrapping | 
| 87 | 0 |  |  |  |  |  | $self->_calcWrap_LetterStack(); | 
| 88 |  |  |  |  |  |  | # line truncating | 
| 89 | 0 |  |  |  |  |  | $self->_calcWrap_LineStack(); | 
| 90 | 0 |  |  |  |  |  | return 1; | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | sub _calcWrap_LetterStack { | 
| 94 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 95 | 0 |  |  |  |  |  | my $wrapMax = $self->_calcWrap_LetterStack_getWrapMax(); | 
| 96 | 0 | 0 |  |  |  |  | return undef if(!$wrapMax); | 
| 97 | 0 |  |  |  |  |  | my $lines = $self->getLines(); | 
| 98 | 0 |  |  |  |  |  | my $li = 0; | 
| 99 | 0 |  |  |  |  |  | foreach my $line (@{$lines}){ | 
|  | 0 |  |  |  |  |  |  | 
| 100 | 0 |  |  |  |  |  | my $lineMax = $self->_calcWrap_LetterStack_getLineMax(line=>$line); | 
| 101 | 0 | 0 | 0 |  |  |  | if($wrapMax && $wrapMax < $lineMax){ | 
| 102 | 0 |  |  |  |  |  | my $wi = 0; | 
| 103 | 0 |  |  |  |  |  | my $nowMax = 0; | 
| 104 | 0 |  |  |  |  |  | my $exceeded = 0; | 
| 105 | 0 |  |  |  |  |  | my $letters = $line->getLetters(); | 
| 106 |  |  |  |  |  |  | # check exceedance | 
| 107 | 0 |  |  |  |  |  | while (1){ | 
| 108 | 0 |  |  |  |  |  | my $ltr = $letters->[$wi]; | 
| 109 | 0 |  |  |  |  |  | $nowMax += $self->_calcWrap_LetterStack_getLetterSize(letter=>$ltr); | 
| 110 | 0 | 0 |  |  |  |  | if($nowMax > $wrapMax){ | 
| 111 | 0 |  |  |  |  |  | $exceeded = 1; | 
| 112 | 0 |  |  |  |  |  | last; | 
| 113 |  |  |  |  |  |  | } | 
| 114 | 0 | 0 |  |  |  |  | last if($wi == $#{$letters}); | 
|  | 0 |  |  |  |  |  |  | 
| 115 | 0 | 0 |  |  |  |  | $nowMax += $line->getWspace() if($wi < $#{$letters}); | 
|  | 0 |  |  |  |  |  |  | 
| 116 | 0 |  |  |  |  |  | $wi++; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  | # cut off exceeded letters | 
| 119 | 0 | 0 |  |  |  |  | if($exceeded){ | 
| 120 | 0 |  |  |  |  |  | my @exceed = (); | 
| 121 |  |  |  |  |  |  | # line contains more than 1 letter & $wrapMax is less than 1 letter size | 
| 122 | 0 | 0 | 0 |  |  |  | if($wi == 0 && $#{$letters} > 0){ | 
|  | 0 | 0 | 0 |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 123 | 0 |  |  |  |  |  | @exceed = @{$letters}[1 .. $#{$letters}]; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | # line contains only 1 letter & $wrapMax is less than 1 letter size | 
| 125 |  |  |  |  |  |  | }elsif($wi == 0 && $#{$letters} == 0){ | 
| 126 | 0 |  |  |  |  |  | @exceed = (); | 
| 127 |  |  |  |  |  |  | # other than above (usual case) | 
| 128 |  |  |  |  |  |  | }else{ | 
| 129 |  |  |  |  |  |  | # grab some more letters if it's in a middle of an alphabet word | 
| 130 | 0 |  |  |  |  |  | $wi = $self->_calcWrap_LetterStack_eExceed(wi=>$wi, | 
| 131 |  |  |  |  |  |  | letters=>$letters); | 
| 132 | 0 |  |  |  |  |  | @exceed = @{$letters}[$wi .. $#{$letters}]; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  | # delete space at beginning of exceed letters | 
| 135 | 0 |  |  |  |  |  | $self->_calcWrap_LetterStack_CutFrontSpace(exceed=>\@exceed); | 
| 136 |  |  |  |  |  |  | # cut off exceeded letters | 
| 137 | 0 | 0 |  |  |  |  | my $to = ($wi > 0)? $wi-1 : 0; | 
| 138 | 0 |  |  |  |  |  | @{$letters} = @{$letters}[0 .. $to]; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | # create new line if needed | 
| 140 | 0 | 0 |  |  |  |  | if($li == $#{$lines}){ | 
|  | 0 |  |  |  |  |  |  | 
| 141 | 0 |  |  |  |  |  | my $newLine = $self->_getNewLineInstance(wspace=>$line->getWspace(),isWrap=>1); | 
| 142 | 0 |  |  |  |  |  | $newLine->{letters} = \@exceed; | 
| 143 | 0 |  |  |  |  |  | $newLine->_calcWidthHeight(); | 
| 144 | 0 |  |  |  |  |  | push(@{$lines},$newLine); | 
|  | 0 |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # un-shift exeeded letters to the later line | 
| 146 |  |  |  |  |  |  | }else{ | 
| 147 | 0 |  |  |  |  |  | my $laterLine = $lines->[$li+1]; | 
| 148 |  |  |  |  |  |  | # if the later line was a line created during calcWrap() | 
| 149 | 0 | 0 |  |  |  |  | if($laterLine->{isWrap} == 1){ | 
| 150 | 0 |  |  |  |  |  | unshift(@{$laterLine->{letters}},@exceed); | 
|  | 0 |  |  |  |  |  |  | 
| 151 | 0 |  |  |  |  |  | $laterLine->{isUpdated} = 0; # force re-calculation | 
| 152 | 0 |  |  |  |  |  | $laterLine->_calcWidthHeight(); | 
| 153 |  |  |  |  |  |  | # or else add new line in between this and later line | 
| 154 |  |  |  |  |  |  | }else{ | 
| 155 | 0 |  |  |  |  |  | my $newLine = $self->_getNewLineInstance(wspace=>$line->getWspace(),isWrap=>1); | 
| 156 | 0 |  |  |  |  |  | $newLine->{letters} = \@exceed; | 
| 157 | 0 |  |  |  |  |  | $newLine->_calcWidthHeight(); | 
| 158 | 0 |  |  |  |  |  | @{$lines} = (@{$lines}[0 .. $li], $newLine, @{$lines}[$li+1 .. $#{$lines}]); | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  | # re-calculate width and height of the current line | 
| 162 | 0 |  |  |  |  |  | $line->{isUpdated} = 0; # register for re-calculation | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  | } | 
| 165 | 0 |  |  |  |  |  | $li++; | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  | # re-calculate width and height | 
| 168 | 0 |  |  |  |  |  | $self->{isUpdated} = 0; | 
| 169 | 0 |  |  |  |  |  | $self->_calcWidthHeight(); | 
| 170 | 0 |  |  |  |  |  | return 1; | 
| 171 |  |  |  |  |  |  | } | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub _calcWrap_LetterStack_getWrapMax { | 
| 174 | 0 |  |  | 0 |  |  | confess "_calcWrap_LetterStack_getWrapMax - this is an abstract method"; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  | sub _calcWrap_LetterStack_getLineMax { | 
| 177 | 0 |  |  | 0 |  |  | confess "_calcWrap_LetterStack_getLineMax - this is an abstract method"; | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  | sub _calcWrap_LetterStack_getLetterSize { | 
| 180 | 0 |  |  | 0 |  |  | confess "_calcWrap_LetterStack_getLetterSize - this is an abstract method"; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | sub _calcWrap_LetterStack_eExceed { | 
| 184 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 185 | 0 |  |  |  |  |  | my %o = @_; | 
| 186 | 0 |  |  |  |  |  | my $pattern = qr/[a-zA-Z0-9'!?%$(),.]/; | 
| 187 |  |  |  |  |  |  | # return if exceeded letter was not a single-byte character | 
| 188 | 0 | 0 |  |  |  |  | return $o{wi} if($o{letters}->[$o{wi}]->getText() !~ /$pattern/); | 
| 189 | 0 |  |  |  |  |  | my $i; | 
| 190 | 0 |  |  |  |  |  | for($i=$o{wi};$i>=0;$i--){ | 
| 191 | 0 |  |  |  |  |  | my $t = $o{letters}->[$i]->getText(); | 
| 192 |  |  |  |  |  |  | # find a word breaking spot | 
| 193 | 0 | 0 | 0 |  |  |  | last if($t =~ /\s/ || $t !~ /$pattern/); | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | # if $wi spot is at the beggining of line, don't count as exceed, | 
| 196 |  |  |  |  |  |  | # infact, find the end of the word and count that as exceed point. | 
| 197 | 0 | 0 |  |  |  |  | if($i+1 == 0){ | 
| 198 | 0 |  |  |  |  |  | my $c; | 
| 199 | 0 |  |  |  |  |  | for($c=$o{wi};$c<=$#{$o{letters}};$c++){ | 
|  | 0 |  |  |  |  |  |  | 
| 200 | 0 |  |  |  |  |  | my $t = $o{letters}->[$c]->getText(); | 
| 201 |  |  |  |  |  |  | # find a word breaking spot | 
| 202 | 0 | 0 | 0 |  |  |  | last if($t =~ /\s/ || $t !~ /$pattern/); | 
| 203 |  |  |  |  |  |  | } | 
| 204 | 0 |  |  |  |  |  | return $c; | 
| 205 |  |  |  |  |  |  | # else return the spot where the word starts | 
| 206 |  |  |  |  |  |  | }else{ | 
| 207 | 0 |  |  |  |  |  | return $i+1; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | sub _calcWrap_LetterStack_CutFrontSpace { | 
| 212 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 213 | 0 |  |  |  |  |  | my %o = @_; | 
| 214 | 0 | 0 |  |  |  |  | return undef if(@{$o{exceed}} == 0); | 
|  | 0 |  |  |  |  |  |  | 
| 215 | 0 |  |  |  |  |  | my $firstLetter = $o{exceed}->[0]; | 
| 216 | 0 | 0 |  |  |  |  | if($firstLetter->getText() =~ /\s/){ | 
| 217 | 0 |  |  |  |  |  | shift(@{$o{exceed}}); | 
|  | 0 |  |  |  |  |  |  | 
| 218 | 0 |  |  |  |  |  | return 1; | 
| 219 |  |  |  |  |  |  | } | 
| 220 | 0 |  |  |  |  |  | return undef; | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | sub _calcWrap_LineStack { | 
| 224 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 225 | 0 |  |  |  |  |  | my $wrapMax = $self->_calcWrap_LineStack_getWrapMax(); | 
| 226 | 0 | 0 |  |  |  |  | return undef if(!$wrapMax); | 
| 227 | 0 |  |  |  |  |  | my $lines = $self->getLines(); | 
| 228 | 0 |  |  |  |  |  | my $li = 0; | 
| 229 | 0 |  |  |  |  |  | my $nowMax = 0; | 
| 230 | 0 |  |  |  |  |  | my $lineMax = $self->_getMaxLetterSize(); | 
| 231 | 0 |  |  |  |  |  | my $lineSpace = $self->_calcLineSpace(); | 
| 232 | 0 |  |  |  |  |  | my $exceed = 0; | 
| 233 | 0 |  |  |  |  |  | foreach my $line (@{$lines}){ | 
|  | 0 |  |  |  |  |  |  | 
| 234 | 0 |  |  |  |  |  | $nowMax += $lineMax; | 
| 235 | 0 | 0 |  |  |  |  | if($nowMax > $wrapMax){ | 
| 236 | 0 |  |  |  |  |  | $exceed = 1; | 
| 237 | 0 |  |  |  |  |  | last; | 
| 238 |  |  |  |  |  |  | } | 
| 239 | 0 | 0 |  |  |  |  | $nowMax += $lineSpace if($li < $#{$lines}); | 
|  | 0 |  |  |  |  |  |  | 
| 240 | 0 |  |  |  |  |  | $li++; | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  | # cut off exceeded lines | 
| 243 | 0 | 0 |  |  |  |  | if($exceed){ | 
| 244 | 0 | 0 |  |  |  |  | my $to = ($li == 0)? 0 : $li-1; | 
| 245 | 0 |  |  |  |  |  | @{$lines} = @{$lines}[0 .. $to]; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | # re-calculate width and height if needed | 
| 247 | 0 |  |  |  |  |  | $self->{isUpdated} = 0; | 
| 248 | 0 |  |  |  |  |  | $self->_calcWidthHeight(); | 
| 249 |  |  |  |  |  |  | } | 
| 250 | 0 |  |  |  |  |  | return 1; | 
| 251 |  |  |  |  |  |  | } | 
| 252 |  |  |  |  |  |  |  | 
| 253 |  |  |  |  |  |  | sub _calcWrap_LineStack_getWrapMax { | 
| 254 | 0 |  |  | 0 |  |  | confess "_calcWrap_LineStack_getWrapMax - this is an abstract method"; | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | sub _calcLineSpace { | 
| 258 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 259 | 0 |  |  |  |  |  | my $base = $self->_getMaxLetterSize(); | 
| 260 | 0 |  |  |  |  |  | return ($self->getLeading() / 100 - 1) * $base; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | sub setText { | 
| 264 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 265 | 0 |  |  |  |  |  | my %o = @_; | 
| 266 |  |  |  |  |  |  | # validation | 
| 267 | 0 | 0 | 0 |  |  |  | if(!defined($o{text}) || $o{text} eq ''){ | 
| 268 | 0 |  |  |  |  |  | confess "text: must not be empty or null."; | 
| 269 |  |  |  |  |  |  | } | 
| 270 | 0 |  |  |  |  |  | $o{text} =~ s/\r\n/\n/g; # replate CR+LF to LF | 
| 271 | 0 |  |  |  |  |  | $o{text} =~ s/\r/\n/g;   # replate CR to LF | 
| 272 |  |  |  |  |  |  | # get last line object | 
| 273 | 0 |  |  |  |  |  | my $lastLine; | 
| 274 | 0 | 0 |  |  |  |  | if(@{$self->{lines}} > 0){ | 
|  | 0 |  |  |  |  |  |  | 
| 275 | 0 |  |  |  |  |  | $lastLine   = pop(@{$self->{lines}}); | 
|  | 0 |  |  |  |  |  |  | 
| 276 | 0 |  |  |  |  |  | my $letters = $lastLine->getLetters(); | 
| 277 | 0 | 0 |  |  |  |  | $o{wspace}  = $lastLine->getWspace() if(!defined($o{wspace})); | 
| 278 | 0 | 0 | 0 |  |  |  | $o{font}    = $letters->[-1]{font} if(!defined($o{font}) && scalar @{$letters} > 0); | 
|  | 0 |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  | # validation for font object | 
| 281 | 0 | 0 |  |  |  |  | if(ref($o{font}) !~ /^Imager::Font(::.+)?$/){ | 
| 282 | 0 |  |  |  |  |  | confess "font: must define an Imager::Font Object"; | 
| 283 |  |  |  |  |  |  | } | 
| 284 |  |  |  |  |  |  | # clear current lines | 
| 285 | 0 | 0 |  |  |  |  | $self->{lines} = [] if(!$o{add}); | 
| 286 |  |  |  |  |  |  | # parse by line feeds | 
| 287 | 0 |  |  |  |  |  | my(@lineTexts,$t,$len); | 
| 288 | 0 |  |  |  |  |  | ($t) = ($o{text} =~ /^(\n+)/); # look for pre-\n's | 
| 289 | 0 | 0 |  |  |  |  | $len = ($t)? length($t) : 0; | 
| 290 | 0 | 0 |  |  |  |  | if($len > 0){ | 
| 291 | 0 |  |  |  |  |  | push(@lineTexts,'') for (1 .. $len); | 
| 292 |  |  |  |  |  |  | } | 
| 293 | 0 |  |  |  |  |  | ($t) = ($o{text} =~ /(\n+)$/); # look for post-\n's | 
| 294 | 0 | 0 |  |  |  |  | $len = ($t)? length($t) : 0; | 
| 295 | 0 |  |  |  |  |  | @lineTexts = split(/\n/,$o{text}); # split inner text by line feeds | 
| 296 | 0 | 0 |  |  |  |  | if($len > 0){ | 
| 297 | 0 |  |  |  |  |  | push(@lineTexts,'') for (1 .. $len); | 
| 298 |  |  |  |  |  |  | } | 
| 299 | 0 | 0 |  |  |  |  | @lineTexts = ('') if(scalar @lineTexts == 0); # to create a blank line | 
| 300 | 0 |  |  |  |  |  | my $i=0; | 
| 301 | 0 |  |  |  |  |  | foreach my $text (@lineTexts){ | 
| 302 | 0 | 0 | 0 |  |  |  | if($i == 0 && $lastLine && $o{add}){ | 
|  |  |  | 0 |  |  |  |  | 
| 303 |  |  |  |  |  |  | # add new texts to the end of last line | 
| 304 | 0 |  |  |  |  |  | $lastLine->setText(text=>$text,font=>$o{font},add=>1); | 
| 305 | 0 |  |  |  |  |  | push(@{$self->{lines}},$lastLine); | 
|  | 0 |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | }else{ | 
| 307 |  |  |  |  |  |  | # create new Line instance if a clean blank line is needed | 
| 308 | 0 |  |  |  |  |  | my $newLine = $self->_getNewLineInstance(wspace=>$o{wspace}); | 
| 309 | 0 |  |  |  |  |  | $newLine->setText(text=>$text,font=>$o{font}); | 
| 310 | 0 |  |  |  |  |  | push(@{$self->{lines}},$newLine); | 
|  | 0 |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | } | 
| 312 | 0 |  |  |  |  |  | $i++; | 
| 313 |  |  |  |  |  |  | } | 
| 314 | 0 |  |  |  |  |  | $self->{isUpdated} = 0; | 
| 315 | 0 |  |  |  |  |  | return 1; | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | sub setWrap { | 
| 319 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 320 | 0 |  |  |  |  |  | my %o = @_; | 
| 321 |  |  |  |  |  |  | # validation | 
| 322 | 0 | 0 | 0 |  |  |  | if($o{width} && $o{width} !~ /^\d+$/){ | 
| 323 | 0 |  |  |  |  |  | confess "width: must be an integer ($o{width})"; | 
| 324 |  |  |  |  |  |  | } | 
| 325 | 0 | 0 | 0 |  |  |  | if($o{height} && $o{height} !~ /^\d+$/){ | 
| 326 | 0 |  |  |  |  |  | confess "height: must be an integer ($o{height})"; | 
| 327 |  |  |  |  |  |  | } | 
| 328 | 0 | 0 |  |  |  |  | $self->{wrapWidth}  = $o{width} if($o{width}); | 
| 329 | 0 | 0 |  |  |  |  | $self->{wrapHeight} = $o{height} if($o{height}); | 
| 330 | 0 |  |  |  |  |  | $self->{isUpdated} = 0; | 
| 331 | 0 |  |  |  |  |  | return 1; | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | sub setAlign { | 
| 335 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 336 | 0 |  |  |  |  |  | my %o = @_; | 
| 337 | 0 | 0 | 0 |  |  |  | if($o{halign} && $o{halign} !~ /^(left|center|right)$/){ | 
| 338 | 0 |  |  |  |  |  | confess "halign: must be either of left/center/right ($o{h})"; | 
| 339 |  |  |  |  |  |  | } | 
| 340 | 0 | 0 | 0 |  |  |  | if($o{valign} && $o{valign} !~ /^(top|center|bottom)$/){ | 
| 341 | 0 |  |  |  |  |  | confess "valign: must be either of top/center/bottom ($o{v})"; | 
| 342 |  |  |  |  |  |  | } | 
| 343 | 0 |  |  |  |  |  | $self->_setAlign_setDefault(%o); | 
| 344 | 0 | 0 |  |  |  |  | $self->{halign} = $o{halign} if($o{halign}); | 
| 345 | 0 | 0 |  |  |  |  | $self->{valign} = $o{valign} if($o{valign}); | 
| 346 | 0 |  |  |  |  |  | return 1; | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | sub setLeading { | 
| 350 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 351 | 0 |  |  |  |  |  | my %o = @_; | 
| 352 | 0 | 0 | 0 |  |  |  | if($o{percent} && $o{percent} !~ /^\d+$/){ | 
| 353 | 0 |  |  |  |  |  | confess "percent: must be a percentage numeral ($o{value})"; | 
| 354 |  |  |  |  |  |  | } | 
| 355 | 0 | 0 |  |  |  |  | $self->{leading} = $o{percent} if($o{percent}); | 
| 356 | 0 |  |  |  |  |  | $self->{isUpdated} = 0; | 
| 357 | 0 |  |  |  |  |  | return 1; | 
| 358 |  |  |  |  |  |  | } | 
| 359 |  |  |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | sub setWspace { | 
| 361 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 362 | 0 |  |  |  |  |  | my %o = @_; | 
| 363 | 0 |  |  |  |  |  | foreach my $line (@{$self->getLines()}){ | 
|  | 0 |  |  |  |  |  |  | 
| 364 | 0 |  |  |  |  |  | $line->setWspace(@_); | 
| 365 |  |  |  |  |  |  | } | 
| 366 | 0 |  |  |  |  |  | return 1; | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | sub setLetterScale { | 
| 370 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 371 | 0 |  |  |  |  |  | my %o = @_; | 
| 372 | 0 |  |  |  |  |  | foreach my $line (@{$self->getLines()}){ | 
|  | 0 |  |  |  |  |  |  | 
| 373 | 0 |  |  |  |  |  | $line->setLetterScale(@_); | 
| 374 |  |  |  |  |  |  | } | 
| 375 | 0 |  |  |  |  |  | return 1; | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | sub getWidth { | 
| 379 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 380 | 0 |  |  |  |  |  | $self->_calcWidthHeight(); | 
| 381 | 0 |  |  |  |  |  | $self->_calcWrap(); | 
| 382 | 0 |  |  |  |  |  | return $self->_getWidth(); | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  | sub getHeight { | 
| 385 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 386 | 0 |  |  |  |  |  | $self->_calcWidthHeight(); | 
| 387 | 0 |  |  |  |  |  | $self->_calcWrap(); | 
| 388 | 0 |  |  |  |  |  | return $self->_getHeight(); | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  | sub getLines { | 
| 391 | 0 |  |  | 0 | 1 |  | return shift->{lines}; | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  | sub getLeading { | 
| 394 | 0 |  |  | 0 | 1 |  | return shift->{leading}; | 
| 395 |  |  |  |  |  |  | } | 
| 396 |  |  |  |  |  |  | sub getHalign { | 
| 397 | 0 |  |  | 0 | 1 |  | return shift->{halign}; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  | sub getValign { | 
| 400 | 0 |  |  | 0 | 1 |  | return shift->{valign}; | 
| 401 |  |  |  |  |  |  | } | 
| 402 |  |  |  |  |  |  | sub getWrapWidth { | 
| 403 | 0 |  |  | 0 | 1 |  | return shift->{wrapWidth}; | 
| 404 |  |  |  |  |  |  | } | 
| 405 |  |  |  |  |  |  | sub getWrapHeight { | 
| 406 | 0 |  |  | 0 | 1 |  | return shift->{wrapHeight}; | 
| 407 |  |  |  |  |  |  | } | 
| 408 |  |  |  |  |  |  | sub _getWidth { | 
| 409 | 0 |  |  | 0 |  |  | return shift->{width}; | 
| 410 |  |  |  |  |  |  | } | 
| 411 |  |  |  |  |  |  | sub _getHeight { | 
| 412 | 0 |  |  | 0 |  |  | return shift->{height}; | 
| 413 |  |  |  |  |  |  | } | 
| 414 |  |  |  |  |  |  | sub _getMaxLetterSize { | 
| 415 | 0 |  |  | 0 |  |  | confess "_getMaxLetterSize - this is an abstract method"; | 
| 416 |  |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | 1; | 
| 419 |  |  |  |  |  |  | __END__ |