# Copyright (c) 2017 Ruby-GNOME2 Project Team
# This program is licenced under the same licence as Ruby-GNOME2.
#
=begin
= Images
GtkImage is used to display an image; the image can be in a number of formats.
Typically, you load an image into a GdkPixbuf, then display the pixbuf.
This demo code shows some of the more obscure cases, in the simple
case a call to gtk_image_new_from_file() is all you need.
If you want to put image data in your program as a C variable,
use the make-inline-pixbuf program that comes with GTK+.
This way you won't need to depend on loading external files, your
application binary can be self-contained.
=end
require "thread"
class ImagesDemo
def initialize(main_window)
@window = Gtk::Window.new(:toplevel)
@window.screen = main_window.screen
@window.title = "Images"
@window.signal_connect "destroy" do
GLib::Source.remove(@load_timeout) if @load_timeout
@pixbuf_loader.close
end
@vbox = Gtk::Box.new(:vertical, 8)
@vbox.margin = 16
@window.add(@vbox)
frame = generate_frame("Image loaded from a file ")
image = Gtk::Image.new(:icon_name => "gtk3-demo", :size => :dialog)
frame.add(image)
# Animation
frame = generate_frame("Animation loaded from a file")
image = Gtk::Image.new(:resource => "/images/floppybuddy.gif")
frame.add(image)
# Symbolic icon
frame = generate_frame("Symbolic themed icon")
gicon = Gio::ThemedIcon.new("battery-caution-charging-symbolic")
image = Gtk::Image.new(:icon => gicon, :size => :dialog)
frame.add(image)
# Progressive
frame = generate_frame("Progressive image loading")
# Create an empty image for now; the progressive loader
# will create the pixbuf and fill it in.
image = Gtk::Image.new
frame.add(image)
start_progressive_loading(image)
# Sensitivity control
button = Gtk::ToggleButton.new(:label => "_Insensitive",
:use_underline => true)
@vbox.pack_start(button)
button.signal_connect "toggled" do |toggle|
@vbox.children.each do |child|
child.sensitive = !toggle.active? if child.class != Gtk::ToggleButton
end
end
end
def run
if !@window.visible?
@window.show_all
else
@window.destroy
end
@window
end
private
def start_progressive_loading(image)
# This is obviously totally contrived (we slow down loading
# on purpose to show how incremental loading works).
# The real purpose of incremental loading is the case where
# you are reading data from a slow source such as the network.
# The timeout simply simulates a slow data source by inserting
# pauses in the reading process.
image_stream = nil
pixbuf_loader = nil
@load_timeout = GLib::Timeout.add(150) do
if image_stream
begin
buf = image_stream.read(256)
rescue => error
buf = ""
show_dialog_on_error("Failure reading image file 'alphatest.png': \
#{error.message}")
end
if buf.empty?
# Errors can happen on close, e.g. if the image
# file was truncated we'll know on close that
# it was incomplete.
begin
image_stream.close
rescue => error
show_dialog_on_error("Failed to load image: #{error.message}")
end
begin
pixbuf_loader.close
rescue => error
show_dialog_on_error("Failed to load image: #{error.message}")
end
GLib::Source::REMOVE
else
begin
pixbuf_loader.write(buf)
rescue => error
show_dialog_on_error("Failed to load image: #{error.message}")
end
GLib::Source::CONTINUE
end
else
begin
image_stream = Gio::Resources.open_stream("/images/alphatest.png")
rescue => error
show_dialog_on_error(error.message)
end
pixbuf_loader.close if pixbuf_loader
pixbuf_loader = GdkPixbuf::PixbufLoader.new
pixbuf_loader.signal_connect "area-prepared" do |loader|
pixbuf = loader.pixbuf
pixbuf.fill(0xaaaaaaff)
image.from_pixbuf = pixbuf
end
pixbuf_loader.signal_connect "area-updated" do
# progressive_updated_callback
# We know the pixbuf inside the GtkImage has changed, but the image
# itself doesn't know this; so give it a hint by setting the pixbuf
# again. Queuing a redraw used to be sufficient, but nowadays
# GtkImage uses GtkIconHelper which caches the pixbuf state and will
# just redraw from the cache.
pixbuf = image.pixbuf
image.from_pixbuf = pixbuf
end
GLib::Source::CONTINUE
end
end
source = GLib::MainContext.default.find_source(@load_timeout)
source.name = "[gtk+] progressive_timeout"
end
def show_dialog_on_error(message)
dialog = Gtk::MessageDialog.new(:parent => @window,
:flags => :destroy_with_parent,
:type => :error, :buttons => :close,
:message => message)
dialog.modal = true
dialog.present
dialog.signal_connect("response") { |w| w.destroy }
GLib::Source.remove(@load_timeout)
@load_timeout = nil
false
end
def generate_frame(title)
label = Gtk::Label.new
label.markup = title
@vbox.pack_start(label)
frame = Gtk::Frame.new
frame.shadow_type = :in
frame.halign = :center
frame.valign = :center
@vbox.pack_start(frame)
frame
end
end