としぁ氏、この度はご解凍、誠におめでとうございます。思えば苦節4年、硬く閉ざされた世界であっても、Twitter氏との仲を温め、この度のご解凍に至られたことは、誠に感慨深いことでございます。今後もウワァアアアアファボッタアアアアアアされることを切に願っております。
今日は以下のプルリクについて紹介させて頂きます。想定読者はRubyでGTK3を使いたい方になります。
gi: add support for implementing virtual functions in Ruby #1386
gi: fix a bug that virtual functions of grandparent class can’t be implemented #1433
PRのモチベーションとしては、GTK3で導入されたカスタムウィジット・カスタムコンテナをRubyでも使いたいというものになります。カスタムウィジットを使うと、例えばmikutterの MiraclePainter
のような独自の描画機構を持ったウィジットが作れます。実際にPRで導入された機能は MiraclePainter
で使われています。
以下のRubyコードはカスタムウィジットの実装例になります。
require 'gtk3'
Gtk.init
class MyWidget < Gtk::Widget
type_register
def initialize
super
self.has_window = true
self.redraw_on_allocate = true
style_context.add_class 'mywidget'
end
def virtual_do_get_request_mode
Gtk::SizeRequestMode::HEIGHT_FOR_WIDTH
end
def virtual_do_get_preferred_width
[100, 300]
end
def virtual_do_get_preferred_height
get_preferred_height_for_width(preferred_width[0])
end
def virtual_do_get_preferred_height_for_width(width)
min = 100
h = width.zero? ? min : 9000 / width
[min, h]
end
def signal_do_size_allocate(allocation)
self.allocation = allocation
x, y, w, h = allocation.x, allocation.y, allocation.width, allocation.height
realized? and window.move_resize x, y, w, h
end
def signal_do_realize
x, y, w, h = allocation.x, allocation.y, allocation.width, allocation.height
attr = Gdk::WindowAttr.new w, h, :input_output, :child
attr.x = x
attr.y = y
attr.visual = visual
attr.event_mask = events | Gdk::EventMask::EXPOSURE_MASK
attr.wclass = :input_output
wat = Gdk::WindowAttributesType
mask = wat::X | wat::Y | wat::VISUAL
self.window = Gdk::Window.new parent_window, attr, mask
register_window window
self.realized = true
end
def signal_do_unrealize
unregister_window window
window.destroy
self.realized = false
end
def singla_do_map
super
window.show
end
def signal_do_unmap
super
window.hide
end
def signal_do_draw(cr)
x, y, w, h = allocation.x, allocation.y, allocation.width, allocation.height
Gtk.render_frame style_context, cr, x, y, w, h
Gtk.render_background style_context, cr, x, y, w, h
end
end
provider = Gtk::CssProvider.new
provider.load_from_data <<EOF
.mywidget { border: 1px solid red; }
EOF
screen = Gdk::Screen.default
Gtk::StyleContext.add_provider_for_screen screen, provider, :application
mywidget = MyWidget.new
box = Gtk::Box.new :vertical
box.add mywidget
box.show_all
window = Gtk::Window.new
window.add box
window.set_size_request 300, 300
window.present
Gtk.main
カスタムウィジットの実装では、ウィジェットのサイズを返す関数が必要です。 GtkWidget
にサイズを計算するためのいくつかの仮想関数が定義されているため、カスタムウィジットのクラス MyWidget
でそれらをオーバーライドします。 virtual_do_XXX
というのがオーバーライドの定義になります。
オーバーライドすべき関数の詳細は以下にまとまっています。
また、GTK3でのウィジットのサイズ計算方式height-for-widthについても知っておいた方が良いでしょう。
以上になります。