demo-images.lua 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. return function(parent, dir)
  2. local coroutine = require 'coroutine'
  3. local lgi = require 'lgi'
  4. local bytes = require 'bytes'
  5. local GLib = lgi.GLib
  6. local Gio = lgi.Gio
  7. local Gtk = lgi.Gtk
  8. local GdkPixbuf = lgi.GdkPixbuf
  9. local window = Gtk.Window {
  10. title = 'Images',
  11. border_width = 8,
  12. Gtk.Box {
  13. id = 'vbox',
  14. orientation = 'VERTICAL',
  15. spacing = 8,
  16. border_width = 8,
  17. Gtk.Label {
  18. label = "<u>Image loaded from a file:</u>",
  19. use_markup = true,
  20. },
  21. Gtk.Frame {
  22. shadow_type = 'IN',
  23. halign = 'CENTER',
  24. valign = 'CENTER',
  25. Gtk.Image {
  26. file = dir:get_child('gtk-logo-rgb.gif'):get_path(),
  27. },
  28. },
  29. Gtk.Label {
  30. label = "<u>Animation loaded from a file:</u>",
  31. use_markup = true,
  32. },
  33. Gtk.Frame {
  34. shadow_type = 'IN',
  35. halign = 'CENTER',
  36. valign = 'CENTER',
  37. Gtk.Image {
  38. file = dir:get_child('floppybuddy.gif'):get_path(),
  39. },
  40. },
  41. Gtk.Label {
  42. label = "<u>Symbolic themed icon</u>",
  43. use_markup = true,
  44. },
  45. Gtk.Frame {
  46. shadow_type = 'IN',
  47. halign = 'CENTER',
  48. valign = 'CENTER',
  49. Gtk.Image {
  50. gicon = Gio.ThemedIcon.new_with_default_fallbacks(
  51. 'battery-caution-charging-symbolic'),
  52. icon_size = Gtk.IconSize.DIALOG,
  53. },
  54. },
  55. Gtk.Label {
  56. label = "<u>Progressive image loading</u>",
  57. use_markup = true,
  58. },
  59. Gtk.Frame {
  60. shadow_type = 'IN',
  61. halign = 'CENTER',
  62. valign = 'CENTER',
  63. Gtk.Image {
  64. id = 'progressive',
  65. },
  66. },
  67. Gtk.ToggleButton {
  68. id = 'sensitive',
  69. label = "_Insensitive",
  70. use_underline = true,
  71. },
  72. }
  73. }
  74. function window.child.sensitive:on_toggled()
  75. for _, child in ipairs(window.child.vbox.child) do
  76. if child ~= self then
  77. child.sensitive = not self.active
  78. end
  79. end
  80. end
  81. local function do_error(err)
  82. local dialog = Gtk.MessageDialog {
  83. transient_for = window,
  84. destroy_with_parent = true,
  85. text = "Failure reading image 'alphatest.png'",
  86. secondary_text = err,
  87. message_type = 'ERROR',
  88. buttons = 'CLOSE',
  89. on_response = Gtk.Widget.destroy,
  90. }
  91. dialog:show_all()
  92. end
  93. local abort_load, timer_id
  94. local load_coro = coroutine.create(function()
  95. while not abort_load do
  96. local stream, err = dir:get_child('alphatest.png'):read()
  97. if not stream then
  98. do_error(err)
  99. abort_load = true
  100. break
  101. end
  102. -- Create pixbuf loader and register callbacks.
  103. local loader = GdkPixbuf.PixbufLoader()
  104. function loader:on_area_prepared()
  105. local pixbuf = self:get_pixbuf()
  106. pixbuf:fill(0xaaaaaaff)
  107. window.child.progressive.pixbuf = pixbuf
  108. end
  109. function loader:on_area_updated()
  110. -- Let the image know that the pixbuf changed.
  111. window.child.progressive:queue_draw()
  112. end
  113. while not abort_load do
  114. -- Wait for the next timer tick.
  115. coroutine.yield(true)
  116. -- Load a chunk from the stream.
  117. local buffer = bytes.new(256)
  118. local read, err = stream:read(buffer)
  119. if read < 0 then
  120. do_error(err)
  121. abort_load = true
  122. end
  123. if read <= 0 then break end
  124. -- Send it to the pixbuf loader.
  125. if not loader:write(tostring(buffer):sub(1, read)) then
  126. do_error(err)
  127. abort_load = true
  128. end
  129. end
  130. loader:close()
  131. end
  132. -- Make sure that timeout is unregistered when the coroutine does
  133. -- not run any more.
  134. timer_id = nil
  135. return false
  136. end)
  137. timer_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, load_coro)
  138. -- Stop loading when the window is destroyed.
  139. function window:on_destroy()
  140. abort_load = true
  141. if timer_id then
  142. GLib.source_remove(timer_id)
  143. coroutine.resume(load_coro)
  144. end
  145. end
  146. window:show_all()
  147. return window
  148. end,
  149. "Images",
  150. table.concat {
  151. [[Gtk.Image is used to display an image; the image can be in ]],
  152. [[a number of formats. Typically, you load an image into a Gdk.Pixbuf, ]],
  153. [[then display the pixbuf.
  154. This demo code shows some of the more obscure cases, in the simple ]],
  155. [[case a call to Gtk.Image.new_from_file() is all you need.]],
  156. }