fpc/packages/gtk2/examples/gtk_demo/pixbufs.inc
Michaël Van Canneyt 58037dfaaa * PChar -> PAnsiChar
2023-07-15 18:22:36 +02:00

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;