#!/usr/bin/perl

use warnings;
use strict;
use Cairo;
use Glib qw(TRUE FALSE);
use Gtk3 -init;

my $button_x = 0;
my $button_y = 0;
my $button_down = 0;
my $whole_window = {x => 0, y => 0, width => 500, height => 500};
my $offset_x = 0;
my $offset_y = 0;
my $zoom = 1;

system("convert -geometry 1000x1000 rose: test.png");
my $image = Cairo::ImageSurface->create_from_png("test.png");
my $image_rect = {width => $image->get_width, height => $image->get_height};
my $window = Gtk3::Window->new('toplevel');
$window->set_size_request ($whole_window->{width}, $whole_window->{height});

$window->signal_connect('delete-event' => sub{Gtk3->main_quit});
my $canvas = Gtk3::DrawingArea->new;
$window->add($canvas);
$canvas->signal_connect(draw => \&_draw);
$canvas->signal_connect('button-press-event' => \&_button_pressed);
$canvas->signal_connect('button-release-event' => \&_button_released);
$canvas->signal_connect('motion-notify-event' => \&_motion);
$canvas->signal_connect('scroll-event' => \&_scroll);
$canvas->set_app_paintable(TRUE);
$canvas->add_events(
    Glib::Object::Introspection->convert_sv_to_flags ( 'Gtk3::Gdk::EventMask', 'exposure-mask') |
        Glib::Object::Introspection->convert_sv_to_flags ( 'Gtk3::Gdk::EventMask', 'button-press-mask') |
            Glib::Object::Introspection->convert_sv_to_flags ( 'Gtk3::Gdk::EventMask', 'button-release-mask') |
                Glib::Object::Introspection->convert_sv_to_flags ( 'Gtk3::Gdk::EventMask', 'pointer-motion-mask') |
                    Glib::Object::Introspection->convert_sv_to_flags ( 'Gtk3::Gdk::EventMask', 'scroll-mask') );

$window->show_all;
Gtk3->main;
unlink 'test.png';

sub _button_pressed {
    my ($widget, $event) = @_;
    # left mouse button
    if ($event->button != 1) { return FALSE }

    ($button_x, $button_y) = ($event->x, $event->y);
    $button_down = TRUE;
    return TRUE;
}

sub _button_released {
    my ($widget, $event) = @_;
    $button_down = FALSE;
}

sub _motion {
    my ($widget, $event) = @_;
    if (not $button_down) { return FALSE }

    $offset_x += $event->x - $button_x;
    $offset_y += $event->y - $button_y;
    ($button_x, $button_y) = ($event->x, $event->y);

    if ($offset_x > 0) { $offset_x = 0 }
    elsif ($image_rect->{width} + $offset_x < $whole_window->{width}) { $offset_x = $whole_window->{width} - $image_rect->{width} }
    if ($offset_y > 0) { $offset_y = 0 }
    elsif ($image_rect->{height} + $offset_y < $whole_window->{height}) { $offset_y = $whole_window->{height} - $image_rect->{height} }

    my $win = $widget->get_window();
    $win->invalidate_rect($whole_window, FALSE)
}

sub _scroll {
    my ($widget, $event) = @_;
    if ($event->direction eq 'up') {
        $zoom *= 2;
    }
    else {
        $zoom /= 2;
    }
    my $win = $widget->get_window();
    $win->invalidate_rect($whole_window, FALSE);
}

sub _draw {
    my ($widget, $context) = @_;
    $context->scale($zoom, $zoom);

    # Create pixbuf
    $context->set_source_surface($image, $offset_x, $offset_y);
    $context->paint;
    return TRUE;
}

