Tickit-Widget-Scroller
view release on metacpan or search on metacpan
lib/Tickit/Widget/Scroller/Item/Text.pm view on Meta::CPAN
sub BUILDARGS ( $class, $text, %opts ) { return ( text => $text, %opts ) }
field $_indent :param = undef;
field $_margin_left = 0;
field $_margin_right = 0;
field @_chunks;
field $_pen :param = undef;
field $_width; # width for which the @_lineruns are valid
field @_lineruns;
ADJUST :params (
:$margin_left = undef,
:$margin_right = undef,
:$margin = undef,
:$text = undef,
) {
$margin_left //= $margin;
$margin_right //= $margin;
$_margin_left = $margin_left if defined $margin_left;
$_margin_right = $margin_right if defined $margin_right;
@_chunks = $self->_build_chunks_for( $text );
}
=head1 METHODS
=cut
=head2 chunks
@chunks = $item->chunks;
Returns the chunks of text displayed by this item. Each chunk is represented
by an ARRAY reference of three fields, giving the text string, its width in
columns, and various options
[ $text, $width, %opts ]
Recognised options are:
=over 8
=item pen => Tickit::Pen
Pen to render the chunk with.
=item linebreak => BOOL
If true, force a linebreak after this chunk; the next one starts on the
following line.
=back
=cut
method _build_chunks_for ( $text )
{
my @lines = split m/\n/, $text, -1;
@lines or @lines = ( "" ); # if blank
my $lastline = pop @lines;
return ( map { [ $_, textwidth( $_ ), linebreak => 1 ] } @lines ),
[ $lastline, textwidth( $lastline ) ];
}
method chunks { @_chunks }
method height_for_width ( $width )
{
# Just pretend the width doesn't include the margins
$width -= ( $_margin_left + $_margin_right );
$_width = $width;
my @chunks = $self->chunks;
undef @_lineruns;
push @_lineruns, my $thisline = [];
my $line_remaining = $width;
while( @chunks ) {
my $chunk = shift @chunks;
my ( $text, $textwidth, %opts ) = @$chunk;
if( $textwidth <= $line_remaining ) {
push @$thisline, [ $text =~ s/\xA0/ /gr, $textwidth, $opts{pen} ];
$line_remaining -= $textwidth;
}
else {
# Split this chunk at most $line_remaining chars
my $eol_ch = cols2chars $text, $line_remaining;
if( $eol_ch < length $text && substr( $text, $eol_ch, 1 ) =~ m/[\S\xA0]/ ) {
# TODO: This surely must be possible without substr()ing a temporary
if( substr( $text, 0, $eol_ch ) =~ m/[\S\xA0]+$/ and
( $-[0] > 0 or @$thisline ) ) {
$eol_ch = $-[0];
}
}
my $partial_text = substr( $text, 0, $eol_ch );
my $partial_chunk = [ $partial_text =~ s/\xA0/ /gr, textwidth( $partial_text ), $opts{pen} ];
push @$thisline, $partial_chunk;
my $bol_ch = pos $text = $eol_ch;
$text =~ m/\G\s+/g and $bol_ch = $+[0];
my $remaining_text = substr( $text, $bol_ch );
my $remaining_chunk = [ $remaining_text, textwidth( $remaining_text ), %opts ];
unshift @chunks, $remaining_chunk;
$line_remaining = 0;
}
if( ( $line_remaining == 0 or $opts{linebreak} ) and @chunks ) {
push @_lineruns, $thisline = [];
$line_remaining = $width - ( $_indent || 0 );
}
}
( run in 0.907 second using v1.01-cache-2.11-cpan-5511b514fd6 )