mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-25 03:19:21 +02:00
294 lines
7.6 KiB
PHP
294 lines
7.6 KiB
PHP
(* 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.
|
|
*
|
|
*)
|
|
|
|
|
|
const
|
|
FRAME_DELAY = 50;
|
|
|
|
BACKGROUND_NAME = 'background.jpg';
|
|
|
|
image_names : array [1..8] of PAnsiChar = (
|
|
'apple-red.png',
|
|
'gnome-applets.png',
|
|
'gnome-calendar.png',
|
|
'gnome-foot.png',
|
|
'gnome-gmush.png',
|
|
'gnome-gimp.png',
|
|
'gnome-gsame.png',
|
|
'gnu-keys.png');
|
|
|
|
N_IMAGES = high(image_names);
|
|
|
|
(* demo window *)
|
|
var
|
|
pixbufs_window : PGtkWidget;
|
|
|
|
(* Current frame *)
|
|
pixbufs_frame : PGdkPixbuf;
|
|
|
|
(* Background image *)
|
|
pixbufs_background : PGdkPixbuf;
|
|
|
|
pixbufs_back_width,
|
|
pixbufs_back_height : gint;
|
|
|
|
|
|
(* Images *)
|
|
images : array [1..N_IMAGES] of PGdkPixbuf;
|
|
|
|
(* Widgets *)
|
|
pixbufs_da : PGtkWidget;
|
|
|
|
(* Loads the images for the demo and returns whether the operation succeeded *)
|
|
function load_pixbufs (error : PPGError): gboolean;
|
|
var
|
|
i : gint;
|
|
filename : pgchar;
|
|
|
|
begin
|
|
|
|
if pixbufs_background <> NULL then begin
|
|
load_pixbufs := TRUE; (* already loaded earlier *)
|
|
exit;
|
|
end;
|
|
|
|
(* 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.
|
|
*)
|
|
|
|
filename := demo_find_file (BACKGROUND_NAME, error);
|
|
if filename = NULL then begin
|
|
load_pixbufs := FALSE; (* note that "error" was filled in and returned *)
|
|
exit;
|
|
end;
|
|
|
|
pixbufs_background := gdk_pixbuf_new_from_file (filename, error);
|
|
g_free (filename);
|
|
|
|
if pixbufs_background = NULL then begin
|
|
load_pixbufs := FALSE; (* Note that "error" was filled with a GError *)
|
|
exit;
|
|
end;
|
|
|
|
pixbufs_back_width := gdk_pixbuf_get_width (pixbufs_background);
|
|
pixbufs_back_height := gdk_pixbuf_get_height (pixbufs_background);
|
|
|
|
for i := 1 to N_IMAGES do
|
|
begin
|
|
filename := demo_find_file (image_names[i], error);
|
|
|
|
if filename = NULL then begin
|
|
load_pixbufs := FALSE; (* Note that "error" was filled with a GError *)
|
|
exit
|
|
end;
|
|
|
|
images[i] := gdk_pixbuf_new_from_file (filename, error);
|
|
g_free (filename);
|
|
|
|
if images[i] = NULL then begin
|
|
load_pixbufs := FALSE; (* Note that "error" was filled with a GError *)
|
|
exit;
|
|
end;
|
|
|
|
end;
|
|
|
|
load_pixbufs := TRUE;
|
|
end;
|
|
|
|
(* Expose callback for the drawing area *)
|
|
function expose_cb (widget : PGtkWidget;
|
|
event : PGdkEventExpose;
|
|
data : gpointer): gint; cdecl;
|
|
var
|
|
pixels : pguchar;
|
|
rowstride : gint;
|
|
|
|
begin
|
|
rowstride := gdk_pixbuf_get_rowstride (pixbufs_frame);
|
|
|
|
pixels := gdk_pixbuf_get_pixels (pixbufs_frame) + rowstride * event^.area.y + event^.area.x * 3;
|
|
|
|
gdk_draw_rgb_image_dithalign (widget^.window,
|
|
widget^.style^.black_gc,
|
|
event^.area.x, event^.area.y,
|
|
event^.area.width, event^.area.height,
|
|
GDK_RGB_DITHER_NORMAL,
|
|
pixels, rowstride,
|
|
event^.area.x, event^.area.y);
|
|
|
|
expose_cb := 1;
|
|
end;
|
|
|
|
const
|
|
CYCLE_LEN = 60;
|
|
|
|
var
|
|
pixbufs_frame_num : integer;
|
|
|
|
|
|
(* Timeout handler to regenerate the frame *)
|
|
function timeout (data : gpointer): gboolean; cdecl;
|
|
var
|
|
f : double;
|
|
i : integer;
|
|
xmid,
|
|
ymid,
|
|
radius : double;
|
|
|
|
ang, r, k : double;
|
|
|
|
alpha,
|
|
xpos, ypos,
|
|
iw, ih : integer;
|
|
|
|
r1, r2,
|
|
dest : TGdkRectangle;
|
|
|
|
|
|
begin
|
|
gdk_pixbuf_copy_area (pixbufs_background, 0, 0, pixbufs_back_width,
|
|
pixbufs_back_height, pixbufs_frame, 0, 0);
|
|
|
|
f := double(pixbufs_frame_num mod CYCLE_LEN) / CYCLE_LEN;
|
|
|
|
xmid := pixbufs_back_width / 2.0;
|
|
ymid := pixbufs_back_height / 2.0;
|
|
|
|
|
|
radius := min (ymid, xmid) / 2.0;
|
|
|
|
for i := 1 to N_IMAGES do
|
|
begin
|
|
ang := 2.0 * G_PI * double (i / N_IMAGES) - f * 2.0 * G_PI;
|
|
|
|
iw := gdk_pixbuf_get_width (images[i]);
|
|
ih := gdk_pixbuf_get_height (images[i]);
|
|
|
|
r := radius + (radius / 3.0) * sin (f * 2.0 * G_PI);
|
|
|
|
xpos := floor (xmid + r * cos (ang) - iw / 2.0 + 0.5);
|
|
ypos := floor (ymid + r * sin (ang) - ih / 2.0 + 0.5);
|
|
|
|
if (i and 1) <> 0 then k:= sin (f * 2.0 * G_PI)
|
|
else k:= cos (f * 2.0 * G_PI);
|
|
|
|
k := 2.0 * k * k;
|
|
k := MAX (0.25, k);
|
|
|
|
r1.x := xpos;
|
|
r1.y := ypos;
|
|
r1.width := round(iw * k);
|
|
r1.height := round(ih * k);
|
|
|
|
r2.x := 0;
|
|
r2.y := 0;
|
|
r2.width := pixbufs_back_width;
|
|
r2.height := pixbufs_back_height;
|
|
|
|
if gdk_rectangle_intersect (@r1, @r2, @dest) then begin
|
|
if (i and 1) <> 0 then
|
|
alpha := round (MAX (127, abs (255 * sin (f * 2.0 * G_PI))))
|
|
else
|
|
alpha := round (MAX (127, abs (255 * cos (f * 2.0 * G_PI))));
|
|
|
|
gdk_pixbuf_composite (images[i],
|
|
pixbufs_frame,
|
|
dest.x, dest.y,
|
|
dest.width, dest.height,
|
|
xpos, ypos,
|
|
k, k,
|
|
GDK_INTERP_NEAREST,
|
|
alpha);
|
|
end;
|
|
end;
|
|
|
|
gtk_widget_queue_draw (pixbufs_da);
|
|
|
|
inc(pixbufs_frame_num);
|
|
exit (TRUE);
|
|
end;
|
|
|
|
var
|
|
pixbufs_timeout_id : guint;
|
|
|
|
procedure pixbufs_cleanup_callback (_object : PGtkObject;
|
|
data : gpointer); cdecl;
|
|
begin
|
|
g_source_remove (pixbufs_timeout_id);
|
|
pixbufs_timeout_id := 0;
|
|
end;
|
|
|
|
|
|
|
|
function do_pixbufs : PGtkWidget;
|
|
var
|
|
error : PGError;
|
|
dialog : PGtkWidget;
|
|
|
|
begin
|
|
if pixbufs_window = NULL then
|
|
begin
|
|
|
|
pixbufs_window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_title (GTK_WINDOW (pixbufs_window), 'Pixbufs');
|
|
gtk_window_set_resizable (GTK_WINDOW (pixbufs_window), FALSE);
|
|
|
|
g_signal_connect (pixbufs_window, 'destroy', G_CALLBACK (@gtk_widget_destroyed), @pixbufs_window);
|
|
g_signal_connect (pixbufs_window, 'destroy', G_CALLBACK (@pixbufs_cleanup_callback), NULL);
|
|
|
|
|
|
error := NULL;
|
|
if not load_pixbufs (@error) then
|
|
begin
|
|
dialog := gtk_message_dialog_new (GTK_WINDOW (pixbufs_window),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_CLOSE,
|
|
'Failed to load an image: %s',
|
|
[error^.message]);
|
|
|
|
g_error_free (error);
|
|
|
|
g_signal_connect (dialog, 'response',
|
|
G_CALLBACK (@gtk_widget_destroy), NULL);
|
|
|
|
gtk_widget_show (dialog);
|
|
end else
|
|
begin
|
|
gtk_widget_set_size_request (pixbufs_window, pixbufs_back_width, pixbufs_back_height);
|
|
|
|
pixbufs_frame := gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, pixbufs_back_width, pixbufs_back_height);
|
|
|
|
pixbufs_da := gtk_drawing_area_new ();
|
|
|
|
g_signal_connect (pixbufs_da, 'expose_event',
|
|
G_CALLBACK (@expose_cb), NULL);
|
|
|
|
gtk_container_add (GTK_CONTAINER (pixbufs_window), pixbufs_da);
|
|
|
|
pixbufs_timeout_id := gtk_timeout_add (FRAME_DELAY, @timeout, NULL);
|
|
end;
|
|
end;
|
|
|
|
if not GTK_WIDGET_VISIBLE (pixbufs_window) then
|
|
gtk_widget_show_all (pixbufs_window)
|
|
else begin
|
|
gtk_widget_destroy (pixbufs_window);
|
|
pixbufs_window := NULL;
|
|
end;
|
|
|
|
do_pixbufs := pixbufs_window;
|
|
end;
|