#!/usr/bin/perl -w
#
# Pixbufs
#
# A GdkPixbuf represents an image, normally in RGB or RGBA format.
# Pixbufs are normally used to load files from disk and perform
# image scaling.
#
# This demo is not all that educational, but looks cool. It was written
# by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows
# off how to use GtkDrawingArea to do a simple animation.
#
# Look at the Image demo for additional pixbuf usage examples.
#
#
package pixbufs;
use Glib qw(TRUE FALSE);
use Gtk2;
use strict;
chdir '../gtk-demo';
use constant FRAME_DELAY => 50;
use constant BACKGROUND_NAME => "background.jpg";
my @image_names = (
"apple-red.png",
"gnome-applets.png",
"gnome-calendar.png",
"gnome-foot.png",
"gnome-gmush.png",
"gnome-gimp.png",
"gnome-gsame.png",
"gnu-keys.png"
);
# demo window
my $window = undef;
# Current frame
my $frame;
# Background image
my $background;
my ($back_width, $back_height);
# Images
my @images;
# Widgets
my $da;
# Loads the images for the demo.
# croaks if anything goes wrong.
sub load_pixbufs {
return TRUE if $background; # already loaded earlier
# demo_find_file() looks in the the current directory first,
# so you can run gtk-demo without installing GTK, then looks
# in the location where the file is installed.
#
my $filename = main::demo_find_file (BACKGROUND_NAME);
$background = Gtk2::Gdk::Pixbuf->new_from_file ($filename);
$back_width = $background->get_width;
$back_height = $background->get_height;
foreach my $i (@image_names) {
push @images, Gtk2::Gdk::Pixbuf->new_from_file (
main::demo_find_file ($i));
}
return TRUE;
}
# Expose callback for the drawing area
sub expose_cb {
my ($widget, $event) = @_;
# the C code that this replaces used gdk_pixbuf_get_pixels and
# gdk_draw_rgb_image_dithalign, with pointer math to find the
# correct index in the image data; that doesn't work well with
# perl scalars, and besides, the GdkPixbuf method render_to_drawable
# exists for this very purpose.
$frame->render_to_drawable ($widget->window, $widget->style->black_gc,
$event->area->x, $event->area->y,
$event->area->x, $event->area->y,
$event->area->width, $event->area->height,
'normal',
$event->area->x, $event->area->y);
return TRUE;
}
use constant CYCLE_LEN => 60;
use constant G_PI => 3.141529;
use POSIX;
sub MAX { $_[0] > $_[1] ? $_[0] : $_[1] }
sub MIN { $_[0] < $_[1] ? $_[0] : $_[1] }
my $frame_num = 0;
# Timeout handler to regenerate the frame
sub timeout {
$background->copy_area (0, 0, $back_width, $back_height, $frame, 0, 0);
my $f = ($frame_num % CYCLE_LEN) / CYCLE_LEN;
my $xmid = $back_width / 2.0;
my $ymid = $back_height / 2.0;
my $radius = MIN ($xmid, $ymid) / 2.0;
for (my $i = 0; $i < @images; $i++) {
my $ang = 2.0 * G_PI * $i / @images - $f * 2.0 * G_PI;
my $iw = $images[$i]->get_width;
my $ih = $images[$i]->get_height;
my $r = $radius + ($radius / 3.0) * sin ($f * 2.0 * G_PI);
my $xpos = POSIX::floor ($xmid + $r * cos ($ang) - $iw / 2.0 + 0.5);
my $ypos = POSIX::floor ($ymid + $r * sin ($ang) - $ih / 2.0 + 0.5);
my $k = ($i & 1) ? sin ($f * 2.0 * G_PI) : cos ($f * 2.0 * G_PI);
$k = 2.0 * $k * $k;
$k = MAX (0.25, $k);
my $r1 = Gtk2::Gdk::Rectangle->new ($xpos, $ypos, $iw * $k, $ih * $k);
my $r2 = Gtk2::Gdk::Rectangle->new (0, 0, $back_width, $back_height);
my $dest = $r1->intersect ($r2);
if ($dest) {
$images[$i]->composite ($frame,
$dest->x, $dest->y,
$dest->width, $dest->height,
$xpos, $ypos,
$k, $k,
'nearest',
(($i & 1)
? MAX (127, abs (255 * sin ($f * 2.0 * G_PI)))
: MAX (127, abs (255 * cos ($f * 2.0 * G_PI)))));
}
}
$da->queue_draw;
$frame_num++;
return TRUE;
}
my $timeout_id;
sub cleanup_callback {
Glib::Source->remove ($timeout_id);
$timeout_id = 0;
}
sub do {
if (!$window) {
$window = Gtk2::Window->new;
$window->set_title ("Pixbufs");
$window->set_resizable (FALSE);
$window->signal_connect (destroy => sub {$window=undef; 1});
$window->signal_connect (destroy => \&cleanup_callback);
eval { load_pixbufs; };
if ($@) {
my $dialog = Gtk2::MessageDialog->new ($window,
'destroy-with-parent',
'error',
'close',
"Failed to load an image: $@");
$dialog->signal_connect (response => sub { $_[0]->destroy; 1 });
$dialog->show;
} else {
$window->set_size_request ($back_width, $back_height);
$frame = Gtk2::Gdk::Pixbuf->new ('rgb', FALSE, 8, $back_width, $back_height);
$da = Gtk2::DrawingArea->new;
$da->signal_connect (expose_event => \&expose_cb);
$window->add ($da);
$timeout_id = Glib::Timeout->add (FRAME_DELAY, \&timeout);
}
}
if (!$window->visible) {
$window->show_all;
} else {
$window->destroy;
$window = undef;
}
return $window;
}
1;
__END__
Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
full list)
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Library General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option) any
later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Library General Public License for more
details.
You should have received a copy of the GNU Library General Public License along
with this library; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307 USA.