pixbufs.inc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. (* Pixbufs
  2. *
  3. * A GdkPixbuf represents an image, normally in RGB or RGBA format.
  4. * Pixbufs are normally used to load files from disk and perform
  5. * image scaling.
  6. *
  7. * This demo is not all that educational, but looks cool. It was written
  8. * by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows
  9. * off how to use GtkDrawingArea to do a simple animation.
  10. *
  11. * Look at the Image demo for additional pixbuf usage examples.
  12. *
  13. *)
  14. const
  15. FRAME_DELAY = 50;
  16. BACKGROUND_NAME = 'background.jpg';
  17. image_names : array [1..8] of pchar = (
  18. 'apple-red.png',
  19. 'gnome-applets.png',
  20. 'gnome-calendar.png',
  21. 'gnome-foot.png',
  22. 'gnome-gmush.png',
  23. 'gnome-gimp.png',
  24. 'gnome-gsame.png',
  25. 'gnu-keys.png');
  26. N_IMAGES = high(image_names);
  27. (* demo window *)
  28. var
  29. pixbufs_window : PGtkWidget;
  30. (* Current frame *)
  31. pixbufs_frame : PGdkPixbuf;
  32. (* Background image *)
  33. pixbufs_background : PGdkPixbuf;
  34. pixbufs_back_width,
  35. pixbufs_back_height : gint;
  36. (* Images *)
  37. images : array [1..N_IMAGES] of PGdkPixbuf;
  38. (* Widgets *)
  39. pixbufs_da : PGtkWidget;
  40. (* Loads the images for the demo and returns whether the operation succeeded *)
  41. function load_pixbufs (error : PPGError): gboolean;
  42. var
  43. i : gint;
  44. filename : pgchar;
  45. begin
  46. if pixbufs_background <> NULL then begin
  47. load_pixbufs := TRUE; (* already loaded earlier *)
  48. exit;
  49. end;
  50. (* demo_find_file() looks in the the current directory first,
  51. * so you can run gtk-demo without installing GTK, then looks
  52. * in the location where the file is installed.
  53. *)
  54. filename := demo_find_file (BACKGROUND_NAME, error);
  55. if filename = NULL then begin
  56. load_pixbufs := FALSE; (* note that "error" was filled in and returned *)
  57. exit;
  58. end;
  59. pixbufs_background := gdk_pixbuf_new_from_file (filename, error);
  60. g_free (filename);
  61. if pixbufs_background = NULL then begin
  62. load_pixbufs := FALSE; (* Note that "error" was filled with a GError *)
  63. exit;
  64. end;
  65. pixbufs_back_width := gdk_pixbuf_get_width (pixbufs_background);
  66. pixbufs_back_height := gdk_pixbuf_get_height (pixbufs_background);
  67. for i := 1 to N_IMAGES do
  68. begin
  69. filename := demo_find_file (image_names[i], error);
  70. if filename = NULL then begin
  71. load_pixbufs := FALSE; (* Note that "error" was filled with a GError *)
  72. exit
  73. end;
  74. images[i] := gdk_pixbuf_new_from_file (filename, error);
  75. g_free (filename);
  76. if images[i] = NULL then begin
  77. load_pixbufs := FALSE; (* Note that "error" was filled with a GError *)
  78. exit;
  79. end;
  80. end;
  81. load_pixbufs := TRUE;
  82. end;
  83. (* Expose callback for the drawing area *)
  84. function expose_cb (widget : PGtkWidget;
  85. event : PGdkEventExpose;
  86. data : gpointer): gint; cdecl;
  87. var
  88. pixels : pguchar;
  89. rowstride : gint;
  90. begin
  91. rowstride := gdk_pixbuf_get_rowstride (pixbufs_frame);
  92. pixels := gdk_pixbuf_get_pixels (pixbufs_frame) + rowstride * event^.area.y + event^.area.x * 3;
  93. gdk_draw_rgb_image_dithalign (widget^.window,
  94. widget^.style^.black_gc,
  95. event^.area.x, event^.area.y,
  96. event^.area.width, event^.area.height,
  97. GDK_RGB_DITHER_NORMAL,
  98. pixels, rowstride,
  99. event^.area.x, event^.area.y);
  100. expose_cb := 1;
  101. end;
  102. const
  103. CYCLE_LEN = 60;
  104. var
  105. pixbufs_frame_num : integer;
  106. (* Timeout handler to regenerate the frame *)
  107. function timeout (data : gpointer): gboolean; cdecl;
  108. var
  109. f : double;
  110. i : integer;
  111. xmid,
  112. ymid,
  113. radius : double;
  114. ang, r, k : double;
  115. alpha,
  116. xpos, ypos,
  117. iw, ih : integer;
  118. r1, r2,
  119. dest : TGdkRectangle;
  120. begin
  121. gdk_pixbuf_copy_area (pixbufs_background, 0, 0, pixbufs_back_width,
  122. pixbufs_back_height, pixbufs_frame, 0, 0);
  123. f := double(pixbufs_frame_num mod CYCLE_LEN) / CYCLE_LEN;
  124. xmid := pixbufs_back_width / 2.0;
  125. ymid := pixbufs_back_height / 2.0;
  126. radius := min (ymid, xmid) / 2.0;
  127. for i := 1 to N_IMAGES do
  128. begin
  129. ang := 2.0 * G_PI * double (i / N_IMAGES) - f * 2.0 * G_PI;
  130. iw := gdk_pixbuf_get_width (images[i]);
  131. ih := gdk_pixbuf_get_height (images[i]);
  132. r := radius + (radius / 3.0) * sin (f * 2.0 * G_PI);
  133. xpos := floor (xmid + r * cos (ang) - iw / 2.0 + 0.5);
  134. ypos := floor (ymid + r * sin (ang) - ih / 2.0 + 0.5);
  135. if (i and 1) <> 0 then k:= sin (f * 2.0 * G_PI)
  136. else k:= cos (f * 2.0 * G_PI);
  137. k := 2.0 * k * k;
  138. k := MAX (0.25, k);
  139. r1.x := xpos;
  140. r1.y := ypos;
  141. r1.width := round(iw * k);
  142. r1.height := round(ih * k);
  143. r2.x := 0;
  144. r2.y := 0;
  145. r2.width := pixbufs_back_width;
  146. r2.height := pixbufs_back_height;
  147. if gdk_rectangle_intersect (@r1, @r2, @dest) then begin
  148. if (i and 1) <> 0 then
  149. alpha := round (MAX (127, abs (255 * sin (f * 2.0 * G_PI))))
  150. else
  151. alpha := round (MAX (127, abs (255 * cos (f * 2.0 * G_PI))));
  152. gdk_pixbuf_composite (images[i],
  153. pixbufs_frame,
  154. dest.x, dest.y,
  155. dest.width, dest.height,
  156. xpos, ypos,
  157. k, k,
  158. GDK_INTERP_NEAREST,
  159. alpha);
  160. end;
  161. end;
  162. gtk_widget_queue_draw (pixbufs_da);
  163. inc(pixbufs_frame_num);
  164. exit (TRUE);
  165. end;
  166. var
  167. pixbufs_timeout_id : guint;
  168. procedure pixbufs_cleanup_callback (_object : PGtkObject;
  169. data : gpointer); cdecl;
  170. begin
  171. g_source_remove (pixbufs_timeout_id);
  172. pixbufs_timeout_id := 0;
  173. end;
  174. function do_pixbufs : PGtkWidget;
  175. var
  176. error : PGError;
  177. dialog : PGtkWidget;
  178. begin
  179. if pixbufs_window = NULL then
  180. begin
  181. pixbufs_window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
  182. gtk_window_set_title (GTK_WINDOW (pixbufs_window), 'Pixbufs');
  183. gtk_window_set_resizable (GTK_WINDOW (pixbufs_window), FALSE);
  184. g_signal_connect (pixbufs_window, 'destroy', G_CALLBACK (@gtk_widget_destroyed), @pixbufs_window);
  185. g_signal_connect (pixbufs_window, 'destroy', G_CALLBACK (@pixbufs_cleanup_callback), NULL);
  186. error := NULL;
  187. if not load_pixbufs (@error) then
  188. begin
  189. dialog := gtk_message_dialog_new (GTK_WINDOW (pixbufs_window),
  190. GTK_DIALOG_DESTROY_WITH_PARENT,
  191. GTK_MESSAGE_ERROR,
  192. GTK_BUTTONS_CLOSE,
  193. 'Failed to load an image: %s',
  194. [error^.message]);
  195. g_error_free (error);
  196. g_signal_connect (dialog, 'response',
  197. G_CALLBACK (@gtk_widget_destroy), NULL);
  198. gtk_widget_show (dialog);
  199. end else
  200. begin
  201. gtk_widget_set_size_request (pixbufs_window, pixbufs_back_width, pixbufs_back_height);
  202. pixbufs_frame := gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, pixbufs_back_width, pixbufs_back_height);
  203. pixbufs_da := gtk_drawing_area_new ();
  204. g_signal_connect (pixbufs_da, 'expose_event',
  205. G_CALLBACK (@expose_cb), NULL);
  206. gtk_container_add (GTK_CONTAINER (pixbufs_window), pixbufs_da);
  207. pixbufs_timeout_id := gtk_timeout_add (FRAME_DELAY, @timeout, NULL);
  208. end;
  209. end;
  210. if not GTK_WIDGET_VISIBLE (pixbufs_window) then
  211. gtk_widget_show_all (pixbufs_window)
  212. else begin
  213. gtk_widget_destroy (pixbufs_window);
  214. pixbufs_window := NULL;
  215. end;
  216. do_pixbufs := pixbufs_window;
  217. end;