images.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. (* Images
  2. *
  3. * GtkImage is used to display an image; the image can be in a number of formats.
  4. * Typically, you load an image into a GdkPixbuf, then display the pixbuf.
  5. *
  6. * This demo code shows some of the more obscure cases, in the simple
  7. * case a call to gtk_image_new_from_file() is all you need.
  8. *
  9. * If you want to put image data in your program as a C variable,
  10. * use the make-inline-pixbuf program that comes with GTK+.
  11. * This way you won't need to depend on loading external files, your
  12. * application binary can be self-contained.
  13. *)
  14. var
  15. image_window : PGtkWidget;
  16. image_pixbuf_loader : PGdkPixbufLoader;
  17. image_load_timeout : guint;
  18. image_stream : file;
  19. type
  20. TBuffer256 = array [0..255] of byte;
  21. procedure progressive_prepared_callback (loader : PGdkPixbufLoader;
  22. data : gpointer); cdecl;
  23. var
  24. pixbuf : PGdkPixbuf;
  25. image : PGtkWidget;
  26. begin
  27. image := PGtkWidget (data);
  28. pixbuf := gdk_pixbuf_loader_get_pixbuf (loader);
  29. (* Avoid displaying random memory contents, since the pixbuf
  30. * isn't filled in yet.
  31. *)
  32. gdk_pixbuf_fill (pixbuf, $aaaaaaff);
  33. gtk_image_set_from_pixbuf (pGtkImage (image), pixbuf);
  34. end;
  35. procedure progressive_updated_callback (loader : PGdkPixbufLoader;
  36. x, y,
  37. width,
  38. height : gint;
  39. data : gpointer); cdecl;
  40. var
  41. image : PGtkWidget;
  42. begin
  43. image := PGtkWidget (data);
  44. (* We know the pixbuf inside the GtkImage has changed, but the image
  45. * itself doesn't know this; so queue a redraw. If we wanted to be
  46. * really efficient, we could use a drawing area or something
  47. * instead of a GtkImage, so we could control the exact position of
  48. * the pixbuf on the display, then we could queue a draw for only
  49. * the updated area of the image.
  50. *)
  51. gtk_widget_queue_draw (image);
  52. end;
  53. function progressive_timeout (data : gpointer): gboolean; cdecl;
  54. var
  55. image : PGtkWidget;
  56. buf : TBuffer256;
  57. bytes_read : integer;
  58. error : PGError;
  59. dialog : PGtkWidget;
  60. error_msg,
  61. filename : pgchar;
  62. begin
  63. image := PGtkWidget (data);
  64. (* This shows off fully-paranoid error handling, so looks scary.
  65. * You could factor out the error handling code into a nice separate
  66. * function to make things nicer.
  67. *)
  68. if file_is_valid (image_stream) then // is there a better way???
  69. begin
  70. error := NULL;
  71. blockread (image_stream, buf, sizeof(buf), bytes_read);
  72. if not gdk_pixbuf_loader_write (image_pixbuf_loader,
  73. @buf[0], bytes_read, @error) then
  74. begin
  75. dialog := gtk_message_dialog_new (GTK_WINDOW (image_window),
  76. GTK_DIALOG_DESTROY_WITH_PARENT,
  77. GTK_MESSAGE_ERROR,
  78. GTK_BUTTONS_CLOSE,
  79. 'Failed to load image: %s',
  80. [error^.message]);
  81. g_error_free (error);
  82. g_signal_connect (dialog, 'response',
  83. G_CALLBACK (@gtk_widget_destroy), NULL);
  84. close (image_stream);
  85. gtk_widget_show (dialog);
  86. image_load_timeout := 0;
  87. exit (FALSE); (* uninstall the timeout *)
  88. end; {of not gdk_pixbuf_loader_write}
  89. if eof (image_stream) then
  90. begin
  91. close (image_stream);
  92. (* Errors can happen on close, e.g. if the image
  93. * file was truncated we'll know on close that
  94. * it was incomplete.
  95. *)
  96. error := NULL;
  97. if not gdk_pixbuf_loader_close (image_pixbuf_loader, @error) then
  98. begin
  99. dialog := gtk_message_dialog_new (GTK_WINDOW (image_window),
  100. GTK_DIALOG_DESTROY_WITH_PARENT,
  101. GTK_MESSAGE_ERROR,
  102. GTK_BUTTONS_CLOSE,
  103. 'Failed to load image: %s',
  104. [error^.message]);
  105. g_error_free (error);
  106. g_signal_connect (dialog, 'response',
  107. G_CALLBACK (@gtk_widget_destroy), NULL);
  108. gtk_widget_show (dialog);
  109. g_object_unref (G_OBJECT (image_pixbuf_loader));
  110. image_pixbuf_loader := NULL;
  111. image_load_timeout := 0;
  112. exit(FALSE); (* uninstall the timeout *)
  113. end; {of not gdk_pixbuf_loader_close}
  114. g_object_unref (G_OBJECT (image_pixbuf_loader));
  115. image_pixbuf_loader := NULL;
  116. end; {of eof}
  117. end {of image_stream}
  118. else begin
  119. error_msg := NULL;
  120. (* demo_find_file() looks in the the current directory first,
  121. * so you can run gtk-demo without installing GTK, then looks
  122. * in the location where the file is installed.
  123. *)
  124. filename := demo_find_file ('alphatest.png', @error);
  125. if error <> NULL then
  126. begin
  127. error_msg := g_strdup (error^.message);
  128. g_error_free (error);
  129. end else
  130. begin
  131. {$I-}
  132. assign (image_stream, filename);
  133. reset (image_stream, 1);
  134. {$I+}
  135. if IOResult <> 0 then
  136. error_msg := g_strdup_printf ('Error while opening file "%s"',
  137. [filename]);
  138. g_free (filename);
  139. end;
  140. if not file_is_valid (image_stream) then
  141. begin
  142. dialog := gtk_message_dialog_new (GTK_WINDOW (image_window),
  143. GTK_DIALOG_DESTROY_WITH_PARENT,
  144. GTK_MESSAGE_ERROR,
  145. GTK_BUTTONS_CLOSE,
  146. '%s', [error_msg]);
  147. g_free (error_msg);
  148. g_signal_connect (dialog, 'response',
  149. G_CALLBACK (@gtk_widget_destroy), NULL);
  150. gtk_widget_show (dialog);
  151. image_load_timeout := 0;
  152. exit (FALSE); (* uninstall the timeout *)
  153. end;
  154. if image_pixbuf_loader <> NULL then
  155. begin
  156. gdk_pixbuf_loader_close (image_pixbuf_loader, NULL);
  157. g_object_unref (G_OBJECT (image_pixbuf_loader));
  158. image_pixbuf_loader := NULL;
  159. end;
  160. image_pixbuf_loader := gdk_pixbuf_loader_new ();
  161. g_signal_connect (G_OBJECT (image_pixbuf_loader), 'area_prepared',
  162. G_CALLBACK (@progressive_prepared_callback), image);
  163. g_signal_connect (G_OBJECT (image_pixbuf_loader), 'area_updated',
  164. G_CALLBACK (@progressive_updated_callback), image);
  165. end; {of else image_stream}
  166. (* leave timeout installed *)
  167. exit (TRUE);
  168. end;
  169. procedure start_progressive_loading (image : PGtkWidget); cdecl;
  170. begin
  171. (* This is obviously totally contrived (we slow down loading
  172. * on purpose to show how incremental loading works).
  173. * The real purpose of incremental loading is the case where
  174. * you are reading data from a slow source such as the network.
  175. * The timeout simply simulates a slow data source by inserting
  176. * pauses in the reading process.
  177. *)
  178. image_load_timeout := g_timeout_add (150,
  179. @progressive_timeout,
  180. image);
  181. end;
  182. procedure images_cleanup_callback (theobject : PGtkObject;
  183. data : gpointer); cdecl;
  184. begin
  185. if image_load_timeout <> 0 then
  186. begin
  187. g_source_remove (image_load_timeout);
  188. image_load_timeout := 0;
  189. end;
  190. if image_pixbuf_loader <> NULL then
  191. begin
  192. gdk_pixbuf_loader_close (image_pixbuf_loader, NULL);
  193. g_object_unref (G_OBJECT (image_pixbuf_loader));
  194. image_pixbuf_loader := NULL;
  195. end;
  196. if file_is_valid (image_stream) then
  197. close (image_stream);
  198. end;
  199. procedure toggle_sensitivity_callback (togglebutton : PGtkWidget;
  200. user_data : gpointer);cdecl;
  201. var
  202. container : PGtkContainer;
  203. list,
  204. tmp : PGList;
  205. begin
  206. container := PGtkContainer (user_data);
  207. list := gtk_container_get_children (container);
  208. tmp := list;
  209. while tmp <> NULL do
  210. begin
  211. (* don't disable our toggle *)
  212. if pGtkWidget (tmp^.data) <> togglebutton then
  213. gtk_widget_set_sensitive (pGtkWidget (tmp^.data),
  214. not gtk_toggle_button_get_active (pGtkToggleButton (togglebutton)));
  215. tmp := tmp^.next;
  216. end;
  217. g_list_free (list);
  218. end;
  219. function do_images : PGtkWidget;
  220. var
  221. frame,
  222. vbox,
  223. image,
  224. thelabel,
  225. align,
  226. dialog,
  227. button : PGtkWidget;
  228. pixbuf : PGdkPixbuf;
  229. error : PGError;
  230. filename : pgchar;
  231. begin
  232. error := NULL;
  233. if image_window = NULL then
  234. begin
  235. image_window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
  236. gtk_window_set_title (GTK_WINDOW (image_window), 'Images');
  237. g_signal_connect (image_window, 'destroy',
  238. G_CALLBACK (@gtk_widget_destroyed), @image_window);
  239. g_signal_connect (image_window, 'destroy',
  240. G_CALLBACK (@images_cleanup_callback), NULL);
  241. gtk_container_set_border_width (GTK_CONTAINER (image_window), 8);
  242. vbox := gtk_vbox_new (FALSE, 8);
  243. gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  244. gtk_container_add (GTK_CONTAINER (image_window), vbox);
  245. thelabel := gtk_label_new (NULL);
  246. gtk_label_set_markup (GTK_LABEL (thelabel),
  247. '<u>Image loaded from a file</u>');
  248. gtk_box_pack_start (GTK_BOX (vbox), thelabel, FALSE, FALSE, 0);
  249. frame := gtk_frame_new (NULL);
  250. gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  251. (* The alignment keeps the frame from growing when users resize
  252. * the window
  253. *)
  254. align := gtk_alignment_new (0.5, 0.5, 0, 0);
  255. gtk_container_add (GTK_CONTAINER (align), frame);
  256. gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
  257. (* demo_find_file() looks in the the current directory first,
  258. * so you can run gtk-demo without installing GTK, then looks
  259. * in the location where the file is installed.
  260. *)
  261. pixbuf := NULL;
  262. filename := demo_find_file ('gtk-logo-rgb.gif', @error);
  263. if filename <> NULL then
  264. begin
  265. pixbuf := gdk_pixbuf_new_from_file (filename, @error);
  266. g_free (filename);
  267. end;
  268. if error <> NULL then
  269. begin
  270. (* This code shows off error handling. You can just use
  271. * gtk_image_new_from_file() instead if you don't want to report
  272. * errors to the user. If the file doesn't load when using
  273. * gtk_image_new_from_file(), a "missing image" icon will
  274. * be displayed instead.
  275. *)
  276. dialog := gtk_message_dialog_new (GTK_WINDOW (image_window),
  277. GTK_DIALOG_DESTROY_WITH_PARENT,
  278. GTK_MESSAGE_ERROR,
  279. GTK_BUTTONS_CLOSE,
  280. 'Unable to open image file "gtk-logo-rgb.gif": %s',
  281. [error^.message]);
  282. g_error_free (error);
  283. g_signal_connect (dialog, 'response',
  284. G_CALLBACK (@gtk_widget_destroy), NULL);
  285. gtk_widget_show (dialog);
  286. end;
  287. image := gtk_image_new_from_pixbuf (pixbuf);
  288. gtk_container_add (GTK_CONTAINER (frame), image);
  289. (* Animation *)
  290. thelabel := gtk_label_new (NULL);
  291. gtk_label_set_markup (GTK_LABEL (thelabel),
  292. '<u>Animation loaded from a file</u>');
  293. gtk_box_pack_start (GTK_BOX (vbox), thelabel, FALSE, FALSE, 0);
  294. frame := gtk_frame_new (NULL);
  295. gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  296. (* The alignment keeps the frame from growing when users resize
  297. * the window
  298. *)
  299. align := gtk_alignment_new (0.5, 0.5, 0, 0);
  300. gtk_container_add (GTK_CONTAINER (align), frame);
  301. gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
  302. filename := demo_find_file ('floppybuddy.gif', NULL);
  303. image := gtk_image_new_from_file (filename);
  304. g_free (filename);
  305. gtk_container_add (GTK_CONTAINER (frame), image);
  306. (* Progressive *)
  307. thelabel := gtk_label_new (NULL);
  308. gtk_label_set_markup (GTK_LABEL (thelabel),
  309. '<u>Progressive image loading</u>');
  310. gtk_box_pack_start (GTK_BOX (vbox), thelabel, FALSE, FALSE, 0);
  311. frame := gtk_frame_new (NULL);
  312. gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  313. (* The alignment keeps the frame from growing when users resize
  314. * the window
  315. *)
  316. align := gtk_alignment_new (0.5, 0.5, 0, 0);
  317. gtk_container_add (GTK_CONTAINER (align), frame);
  318. gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
  319. (* Create an empty image for now; the progressive loader
  320. * will create the pixbuf and fill it in.
  321. *)
  322. image := gtk_image_new_from_pixbuf (NULL);
  323. gtk_container_add (GTK_CONTAINER (frame), image);
  324. start_progressive_loading (image);
  325. (* Sensitivity control *)
  326. button := gtk_toggle_button_new_with_mnemonic ('_Insensitive');
  327. gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  328. g_signal_connect (G_OBJECT (button), 'toggled',
  329. G_CALLBACK (@toggle_sensitivity_callback),
  330. vbox);
  331. end;
  332. if not GTK_WIDGET_VISIBLE (image_window) then
  333. gtk_widget_show_all (image_window)
  334. else
  335. begin
  336. gtk_widget_destroy (image_window);
  337. image_window := NULL;
  338. end;
  339. do_images := image_window;
  340. end;