/usr/local/CPAN/Video-PlaybackMachine/Video/PlaybackMachine/FillProducer/TextFrame/TextTable.pm
package Video::PlaybackMachine::FillProducer::TextFrame::TextTable;
use strict;
use warnings;
sub new {
my $type = shift;
my %in = @_;
my $self = {
image => $in{image},
border => $in{border},
rows => [],
height => 0,
width => 0
};
bless $self, $type;
}
sub get_image {
return $_[0]->{'image'};
}
sub get_height {
return $_[0]->{'height'};
}
sub get_width {
return $_[0]->{'width'};
}
sub add_row {
my $self = shift;
my (@columns) = @_;
my $row =
Video::PlaybackMachine::FillProducer::TextFrame::Row->new(
$self->{'image'},
$self->{'border'},
@columns);
# Return undef if we're too long (vertically) for the screen
my $new_height = $self->{'height'} + $row->get_height() + $self->{'border'};
$new_height > $self->get_image()->get_height()
and return;
$self->{'height'} = $new_height;
# Update maximum width
$self->{'width'} = $row->get_width()
if $row->get_width() > $self->{'width'};
# Store the row
push(@{ $self->{'rows'} }, $row);
return 1;
}
sub get_start_ycoord {
my $self = shift;
return int(($self->get_image()->get_height() - $self->get_height()) / 2);
}
sub get_start_xcoord {
my $self = shift;
return int(($self->get_image()->get_width() - $self->get_width()) / 2);
}
sub draw {
my $self = shift;
my $x = $self->get_start_xcoord();
my $y = $self->get_start_ycoord();
foreach my $row (@{ $self->{'rows'} }) {
$row->draw($x, $y);
$y += $row->get_height();
}
}
package Video::PlaybackMachine::FillProducer::TextFrame::Row;
use strict;
use warnings;
sub new {
my $type = shift;
my ($image, $border, @columns) = @_;
my $self = {
image => $image,
border => $border,
columns => [
map { Video::PlaybackMachine::FillProducer::TextFrame::Column->new($image, $_); } @columns
],
};
bless $self, $type;
}
sub get_columns {
return @{ $_[0]->{'columns'} };
}
sub get_dimensions {
my $self = shift;
if (! defined $self->{'dimensions'} ) {
my $total_width = 0;
my $max_height = 0;
foreach my $column ( @{ $self->{'columns'} } ) {
my ($width, $height) = $column->get_dimensions( $self->{'image'}->get_width() - $total_width );
$total_width += ($width + $self->{'border'});
$max_height = $height if $height > $max_height;
}
$self->{'dimensions'} = [$total_width - $self->{'border'}, $max_height];
}
return @{ $self->{'dimensions'} };
}
sub get_width {
my $self = shift;
my ($width, undef) = $self->get_dimensions();
return $width;
}
sub get_height {
my $self = shift;
my (undef, $height) = $self->get_dimensions();
return $height;
}
sub draw {
my $self = shift;
my ($x, $y) = @_;
my $currx = $x;
foreach my $column ( $self->get_columns() ) {
my $width_left = $self->{'image'}->get_width() - $currx;
$column->draw($currx, $y, $width_left);
$currx += ($column->get_dimensions($width_left))[0];
$currx += $self->{'border'};
}
return 1;
}
package Video::PlaybackMachine::FillProducer::TextFrame::Column;
# TODO: Make 'wrap_width' a parameter to 'new'
use strict;
use warnings;
sub new {
my $type = shift;
my ($image, $text) = @_;
my $self = {
image => $image,
text => $text,
};
bless $self, $type;
}
sub draw {
my $self = shift;
my ($x, $y, $width) = @_;
my $y_curr = $y;
foreach my $line ( $self->get_lines($width) ) {
chomp($line);
my ($width, $height) = $self->{'image'}->get_text_size($line);
$self->{'image'}->draw_text($x, $y_curr, $line);
$y_curr += $height;
}
}
sub get_dimensions {
my $self = shift;
my ($wrap_width) = @_;
my ($width, $height) = $self->_wrap_lines($wrap_width);
return $width, $height;
}
sub get_lines {
my $self = shift;
my ($wrap_width) = @_;
my (undef, undef, @lines) = $self->_wrap_lines($wrap_width);
return @lines;
}
sub _wrap_lines {
my $self = shift;
my ($wrap_width) = @_;
my @lines = ();
my $total_height = 0;
my $max_width = 0;
foreach my $text ( split(/\n/, $self->{'text'}) ) {
my @atoms = split(/(\s+)/, $text);
my $curr_line = shift @atoms;
defined $curr_line or $curr_line = '';
my ($line_width, $line_height) = $self->{'image'}->get_text_size($curr_line);
$total_height += $line_height;
foreach my $atom (@atoms) {
my ($width, $height) = $self->{'image'}->get_text_size($atom);
# If the current atom makes the line wrap, do it
if ( ( $line_width + $width ) > $wrap_width ) {
push(@lines, $curr_line);
$curr_line = $atom;
$max_width = $line_width if $line_width > $max_width;
$line_width = $width;
$total_height += $height;
}
# Otherwise, append atom to current line
else {
$curr_line .= $atom;
$line_width += $width;
}
}
push(@lines, $curr_line);
$max_width = $line_width if $line_width > $max_width;
}
return $max_width, $total_height, @lines;
}
1;