GEmeTool/lib/GEmeTool/View/PokemonPCWindow.pm

235 lines
6.9 KiB
Perl

package GEmeTool::View::PokemonPCWindow;
use v5.16.3;
use strict;
use warnings;
use Cairo::GObject;
use Glib;
use Glib::IO;
use Path::Tiny;
use Math::Trig;
use Moo;
Glib::Object::Introspection->setup(
basename => 'Gtk',
version => '4.0',
package => 'Gtk4',
);
Glib::Object::Introspection->setup(
basename => 'Gdk',
version => '4.0',
package => 'Gdk',
);
has _save => (
is => 'ro',
required => 1,
);
my $BOX_X = 275;
my $BOX_Y = 50;
my $BOX_WIDTH = 312;
my $BOX_HEIGHT = 340;
has _cursor_position => ( is => 'rw' );
my $root = path(__FILE__)->parent->parent->parent->parent;
sub start {
my $self = shift;
my $gtk_window = Gtk4::Window->new;
my $controller_motion = Gtk4::EventControllerMotion->new;
$controller_motion->signal_connect(
motion => sub {
my ( $x, $y ) = @_[ 1, 2 ];
$self->_cursor_position( [ $x, $y ] );
}
);
my $canvas = Gtk4::DrawingArea->new;
$canvas->add_controller($controller_motion);
my $scale_factor_pc = 2.5;
my ($width, $height) = map { $_ * $scale_factor_pc } (256, 158);
$gtk_window->set_default_size( $width, $height );
$gtk_window->set_resizable(0);
$canvas->set_draw_func(
sub {
my $canvas = shift;
my $cairo = shift;
my $width = shift;
my $height = shift;
$self->draw_pc($cairo, $scale_factor_pc);
{
my $output_box = Cairo::ImageSurface->create( 'argb32', $BOX_WIDTH, $BOX_HEIGHT );
my $box_context = Cairo::Context->create($output_box);
$self->draw_box($box_context);
my $selected_pokemon = $self->get_selected_pokemon;
$self->draw_pokemon( $box_context, $selected_pokemon );
$self->draw_box_name($box_context);
$cairo->set_source_surface( $output_box, $BOX_X, $BOX_Y );
$cairo->paint;
}
$self->draw_cursor($cairo);
}
);
$gtk_window->set_child($canvas);
$gtk_window->present;
Glib::Timeout->add(
1000 / 15,
sub {
$canvas->queue_draw;
return 1;
}
);
}
sub draw_pc {
my $self = shift;
my $cairo = shift;
my $scale_factor = shift;
$cairo->scale( ($scale_factor) x 2 );
my $surface = Cairo::ImageSurface->create_from_png($root->child('resources/pc_background.png'));
$cairo->set_source_surface( $surface, 0, 0 );
$cairo->get_source()->set_filter('nearest');
$cairo->paint;
$cairo->scale( ( 1 / $scale_factor ) x 2 );
}
sub draw_cursor {
my $self = shift;
my $cairo = shift;
my $cursor_png = $root->child('resources/hand_cursor.png');
my $surface = Cairo::ImageSurface->create_from_png($cursor_png);
my $output_image = Cairo::ImageSurface->create( 'argb32', 32, 32 );
my $image_context = Cairo::Context->create($output_image);
my $cursor_position = $self->_cursor_position;
return if !defined $cursor_position;
my $scale_factor = 0.95 * 2;
$cairo->scale( ($scale_factor) x 2 );
my ( $x, $y ) = map { $_ / $scale_factor } @$cursor_position;
$x -= 10;
$y -= 20;
$image_context->set_source_surface( $surface, 0, 0 );
$image_context->get_source()->set_filter('nearest');
$image_context->paint;
my $p = 25;
$cairo->set_source_surface( $output_image, $x, $y, );
$cairo->get_source()->set_filter('nearest');
$cairo->paint;
$cairo->scale( ( 1 / $scale_factor ) x 2 );
}
sub draw_box_name {
my $self = shift;
my $cairo = shift;
my $save = $self->_save;
my $pc = $save->get_pc_system;
my $box = $pc->get_box(0);
my $name = Rsaves::translate_3rd_encoding( $box->name );
my $scale_factor = 0.95 * 2;
$cairo->scale( $scale_factor, $scale_factor );
$cairo->set_source_rgb( 0, 0, 0 );
$cairo->select_font_face( 'monospace', 'normal', 'normal' );
$cairo->set_font_size(20);
$cairo->move_to( 75 - ( length($name) * 5 ), 19 );
$cairo->show_text($name);
$cairo->scale( ( 1 / $scale_factor ) x 2 );
}
sub draw_pokemon {
my $self = shift;
my $cairo = shift;
my $selected_pokemon = shift;
my $save = $self->_save;
my $pc = $save->get_pc_system;
my $box = $pc->get_box(0);
my $scale_factor = 0.95 * 2;
$cairo->scale( $scale_factor, $scale_factor );
for ( my $i = 0 ; $i < 5 ; $i++ ) {
# ROW
for ( my $j = 0 ; $j < 6 ; $j++ ) {
# COLUMN
my $pokemon = $box->get_pokemon( $i * 6 + $j );
my $is_selected =
defined $selected_pokemon && $pokemon eq $selected_pokemon;
my $pokemon_image = $root->child( $pokemon->get_image );
my $p = 25;
my $x = $j * ( $p + 1 );
my $y = 20 + ( ( $p - 3 ) * $i );
if ($is_selected) {
$cairo->set_source_rgb( 1, 1, 0 );
$cairo->arc( $x + 5 + 11, $y + 10 + 11, 22/2, 0, pi*2 );
$cairo->fill;
}
my $surface = Cairo::ImageSurface->create_from_png($pokemon_image);
my $output_image = Cairo::ImageSurface->create( 'argb32', 32, 32 );
my $image_context = Cairo::Context->create($output_image);
$image_context->set_source_surface( $surface, 0, 0 );
$image_context->get_source()->set_filter('nearest');
$image_context->paint;
$cairo->set_source_surface( $output_image, $x, $y );
$cairo->get_source()->set_filter('nearest');
$cairo->paint;
}
}
$cairo->scale( ( 1 / $scale_factor ) x 2 );
}
sub get_selected_pokemon {
my $self = shift;
my $cursor_position = $self->_cursor_position;
return if !defined $cursor_position;
my ($x, $y) = @$cursor_position;
return if $x < $BOX_X;
return if $y < $BOX_Y;
$x -= $BOX_X;
$y -= $BOX_Y;
return if $x >= $BOX_WIDTH - 13;
return if $y >= $BOX_HEIGHT;
my $scale_factor = 0.95 * 2;
( $x, $y ) = map { $_ / $scale_factor } ($x, $y);
return if $y <= 20;
$y -= 20;
my $p = 25;
my $i = int( $y / ( $p - 3 ) );
my $j = int( $x / ( $p + 1 ) );
my $save = $self->_save;
my $pc = $save->get_pc_system;
my $box = $pc->get_box(0);
my $number = $i * 6 + $j;
return if $number > 29;
my $pokemon = $box->get_pokemon($number);
return $pokemon;
}
sub draw_box {
my $self = shift;
my $cairo = shift;
my $surface = Cairo::ImageSurface->create_from_png(
$root->child('resources/forest.png') );
$cairo->scale( 2, 2 );
$cairo->set_source_surface( $surface, 0, 0 );
$cairo->get_source()->set_filter('nearest');
$cairo->paint;
$cairo->scale( 1 / 2, 1 / 2 );
}
1;