package GridFiller::Result::Pango;
use Moose;
use namespace::autoclean;
use GridFiller::Constants ':directions';
use MooseX::Types::Moose qw(Int);
use Cairo;
use Pango;
use Carp;
use POSIX 'ceil';
extends 'GridFiller::Result';
with 'MooseX::Log::Log4perl';
has cell_size => (
isa => Int,
is => 'rw',
default => 20,
);
has _width => (
isa => Int,
is => 'ro',
lazy_build => 1,
clearer => '_reset_w',
);
sub _build__width {
my ($self) = @_;
return $self->cell_size * @{$self->source_grid->[0]};
}
has _height => (
isa => Int,
is => 'ro',
lazy_build => 1,
clearer => '_reset_h',
);
sub _build__height {
my ($self) = @_;
return $self->cell_size * @{$self->source_grid};
}
has _cairo_s => (
is => 'ro',
lazy_build => 1,
clearer => '_reset_s',
);
sub _build__cairo_s {
my ($self) = @_;
my $cs = Cairo::ImageSurface->create(
'argb32',
$self->_width,
$self->_height,
);
return $cs;
};
has _cairo_c => (
is => 'ro',
lazy_build => 1,
clearer => '_reset_c',
);
sub _build__cairo_c {
my ($self) = @_;
my $cr = Cairo::Context->create($self->_cairo_s);
$self->_put_squares($cr);
return $cr;
}
sub _put_squares {
my ($self,$cr) = @_;
$self->log->debug(sprintf('putting squares (%dx%d)',$self->_width,$self->_height));
my $size = $self->cell_size;
$cr->save;
$cr->rectangle(0,0,$self->_width,$self->_height);
$cr->set_source_rgb(1,1,1);
$cr->fill;
my $y=0;
for my $row (@{$self->source_grid}) {
my $x=0;
for my $cell (@$row) {
if ($cell eq '*') {
$cr->rectangle($x,$y,$size,$size);
$cr->set_source_rgb(0,0,0);
$cr->fill;
}
$x+=$size;
}
$y+=$size;
}
$cr->restore;
return;
}
sub layout_for_string {
my ($self,$string) = @_;
my $p = Pango::Cairo::create_layout($self->_cairo_c);
$p->set_text($string);
return $p;
}
sub length_closure {
my ($self) = @_;
return sub { $self->string_width($_[0]) }
}
sub string_extents {
my ($self,$string) = @_;
my $p = $self->layout_for_string($string);
my ($w,$h) = $p->get_pixel_size;
return
ceil($w / $self->cell_size),
ceil($h / $self->cell_size);
}
sub string_width {
my ($self,$string) = @_;
return +($self->string_extents($string))[0];
}
sub string_height {
my ($self,$string) = @_;
return +($self->string_extents($string))[1];
}
sub _center_adj {
my ($self,$p) = @_;
my ($w) = $p->get_pixel_size;
my $size = $self->cell_size;
my $rounded = ceil($w/$size)*$size;
return +($rounded-$w)/2;
}
my $PI=3.1415926;
sub place_word_at {
my ($self, $word, $x, $y, $dir) = @_;
$self->log->debug("Placing $word at ${x}:${y} ($dir)");
my $p = $self->layout_for_string($word);
my $size = $self->cell_size;
my $cr = $self->_cairo_c;
$x*=$size;$y*=$size;
my $adjustment = $self->_center_adj($p);
$cr->save;
if ($dir == $HORIZONTAL) {
$x+=$adjustment;
$cr->move_to($x,$y);
}
else {
$y+=$adjustment;
$cr->move_to($x+$size,$y);
$cr->rotate($PI/2);
}
Pango::Cairo::update_layout($cr,$p);
$cr->set_source_rgb(1,1,0);
Pango::Cairo::show_layout($cr,$p);
$cr->restore;
return;
}
sub as_png {
my ($self) = @_;
$self->_cairo_c->show_page;
my $buffer;
$self->_cairo_s->write_to_png_stream(sub{$buffer.=$_[1]});
return $buffer;
}
sub save_png {
my ($self,$filename) = @_;
$self->_cairo_c->show_page;
$self->_cairo_s->write_to_png($filename);
return;
}
sub to_string {}
after reset => sub {
my ($self) = @_;
$self->_reset_w;
$self->_reset_h;
$self->_reset_c;
$self->_reset_s;
};
1;