gtk3 3.0.7-x64-mingw32 → 3.0.8-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/gtk3/extconf.rb +1 -0
- data/ext/gtk3/rb-gtk3-tree-view.c +4 -0
- data/ext/gtk3/rb-gtk3.c +245 -60
- data/lib/2.2/gtk3.so +0 -0
- data/lib/2.3/gtk3.so +0 -0
- data/lib/gtk3/box.rb +22 -0
- data/lib/gtk3/builder.rb +50 -29
- data/lib/gtk3/deprecated.rb +7 -0
- data/lib/gtk3/entry-buffer.rb +28 -0
- data/lib/gtk3/list-store.rb +2 -20
- data/lib/gtk3/loader.rb +6 -0
- data/lib/gtk3/menu-item.rb +8 -7
- data/lib/gtk3/tree-iter.rb +25 -1
- data/lib/gtk3/tree-model.rb +41 -0
- data/lib/gtk3/tree-store.rb +7 -6
- data/lib/gtk3/widget.rb +18 -1
- data/sample/gtk-demo/TODO +45 -39
- data/sample/gtk-demo/assistant.rb +123 -0
- data/sample/gtk-demo/builder.rb +75 -38
- data/sample/gtk-demo/button_box.rb +100 -0
- data/sample/gtk-demo/colorsel.rb +49 -65
- data/sample/gtk-demo/css_accordion.rb +33 -55
- data/sample/gtk-demo/css_basics.rb +55 -80
- data/sample/gtk-demo/css_multiplebgs.rb +112 -0
- data/sample/gtk-demo/css_pixbufs.rb +84 -0
- data/sample/gtk-demo/css_shadows.rb +101 -0
- data/sample/gtk-demo/cursors.rb +114 -0
- data/sample/gtk-demo/dialog.rb +105 -115
- data/sample/gtk-demo/entry_buffer.rb +44 -0
- data/sample/gtk-demo/entry_completion.rb +40 -52
- data/sample/gtk-demo/expander.rb +60 -26
- data/sample/gtk-demo/filtermodel.rb +119 -0
- data/sample/gtk-demo/font_features.rb +117 -0
- data/sample/gtk-demo/headerbar.rb +57 -0
- data/sample/gtk-demo/iconview_edit.rb +79 -0
- data/sample/gtk-demo/infobar.rb +75 -59
- data/sample/gtk-demo/links.rb +53 -40
- data/sample/gtk-demo/main.rb +353 -43
- data/sample/gtk-demo/main.ui +9 -9
- data/sample/gtk-demo/markup.rb +46 -0
- data/sample/gtk-demo/menus.rb +111 -162
- data/sample/gtk-demo/modelbutton.rb +47 -0
- data/sample/gtk-demo/overlay.rb +61 -0
- data/sample/gtk-demo/overlay2.rb +75 -0
- data/sample/gtk-demo/panes.rb +114 -133
- data/sample/gtk-demo/pickers.rb +70 -0
- data/sample/gtk-demo/popover.rb +110 -0
- data/sample/gtk-demo/printing.rb +68 -83
- data/sample/gtk-demo/revealer.rb +53 -0
- data/sample/gtk-demo/scale.rb +26 -0
- data/sample/gtk-demo/search_entry2.rb +107 -0
- data/sample/gtk-demo/sidebar.rb +68 -0
- data/sample/gtk-demo/sizegroup.rb +93 -105
- data/sample/gtk-demo/spinner.rb +53 -50
- data/sample/gtk-demo/stack.rb +28 -0
- data/sample/gtk-demo/test_mod.rb +22 -0
- data/sample/gtk-demo/textmask.rb +61 -0
- data/sample/gtk-demo/theming_style_classes.rb +16 -12
- data/sample/misc/app-menu.ui +19 -0
- data/sample/misc/button-menu.ui +19 -0
- data/sample/misc/icons-theme-viewer.rb +65 -0
- data/sample/misc/menu.rb +3 -3
- data/sample/misc/menus_from_resources.gresource.xml +8 -0
- data/sample/misc/menus_from_resources.rb +91 -0
- data/sample/misc/statusicon.rb +1 -1
- data/sample/misc/toolbar-menu.ui +23 -0
- data/sample/misc/treestore.rb +63 -0
- data/sample/tutorial/README.md +368 -6
- data/test/test-gtk-box.rb +13 -0
- data/test/test-gtk-builder.rb +1 -1
- data/test/test-gtk-clipboard.rb +124 -0
- data/test/test-gtk-container.rb +3 -3
- data/test/test-gtk-entry-buffer.rb +32 -0
- data/test/test-gtk-list-store.rb +30 -12
- data/test/test-gtk-menu.rb +32 -0
- data/test/test-gtk-tree-iter.rb +61 -5
- data/test/test-gtk-tree-path.rb +26 -1
- data/test/test-gtk-tree-sortable.rb +35 -0
- data/test/test-gtk-tree-store.rb +34 -0
- data/test/test-gtk-widget.rb +33 -2
- metadata +57 -22
- data/lib/2.0/gtk3.so +0 -0
- data/lib/2.1/gtk3.so +0 -0
- data/sample/gtk-demo/button-box.rb +0 -82
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (c) 2015 Ruby-GNOME2 Project Team
|
2
|
+
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
|
+
#
|
4
|
+
=begin
|
5
|
+
= Header Bar
|
6
|
+
|
7
|
+
GtkHeaderBar is a container that is suitable for implementing
|
8
|
+
window titlebars. One of its features is that it can position
|
9
|
+
a title (and optional subtitle) centered with regard to the
|
10
|
+
full width, regardless of variable-width content at the left
|
11
|
+
or right.
|
12
|
+
|
13
|
+
It is commonly used with gtk_window_set_titlebar()
|
14
|
+
=end
|
15
|
+
module HeaderbarDemo
|
16
|
+
def self.run_demo(main_window)
|
17
|
+
window = Gtk::Window.new(:toplevel)
|
18
|
+
window.screen = main_window.screen
|
19
|
+
window.set_default_size(600, 400)
|
20
|
+
|
21
|
+
header = Gtk::HeaderBar.new
|
22
|
+
header.set_show_close_button(true)
|
23
|
+
header.set_title("Welcome to Facebook - Log in, sign up or learn more")
|
24
|
+
header.set_has_subtitle(false)
|
25
|
+
|
26
|
+
button = Gtk::Button.new()
|
27
|
+
|
28
|
+
icon = Gio::ThemedIcon.new("mail-send-receive-symbolic")
|
29
|
+
image = Gtk::Image.new(:icon => icon, :size => :button)
|
30
|
+
|
31
|
+
button.add(image)
|
32
|
+
header.pack_end(button)
|
33
|
+
|
34
|
+
box = Gtk::Box.new(:horizontal, 0)
|
35
|
+
box.style_context.add_class("linked")
|
36
|
+
|
37
|
+
button = Gtk::Button.new
|
38
|
+
image = Gtk::Image.new(:icon_name => "pan-start-symbolic", :size => :button)
|
39
|
+
button.add(image)
|
40
|
+
box.add(button)
|
41
|
+
|
42
|
+
button = Gtk::Button.new
|
43
|
+
image = Gtk::Image.new(:icon_name => "pan-end-symbolic", :size => :button)
|
44
|
+
button.add(image)
|
45
|
+
box.add(button)
|
46
|
+
|
47
|
+
header.pack_start(box)
|
48
|
+
window.set_titlebar(header)
|
49
|
+
window.add(Gtk::TextView.new())
|
50
|
+
|
51
|
+
if !window.visible?
|
52
|
+
window.show_all
|
53
|
+
else
|
54
|
+
window.destroy
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright (c) 2015 Ruby-GNOME2 Project Team
|
2
|
+
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
|
+
#
|
4
|
+
=begin
|
5
|
+
= Icon View/Editing and Drag-and-Drop
|
6
|
+
|
7
|
+
The GtkIconView widget supports Editing and Drag-and-Drop.
|
8
|
+
This example also demonstrates using the generic GtkCellLayout
|
9
|
+
interface to set up cell renderers in an icon view.
|
10
|
+
=end
|
11
|
+
module IconviewEditDemo
|
12
|
+
COL_TEXT = 0
|
13
|
+
NUM_COLS = 1
|
14
|
+
def self.run_demo(main_window)
|
15
|
+
window = Gtk::Window.new(:toplevel)
|
16
|
+
window.screen = main_window.screen
|
17
|
+
window.set_title("Editing and Drag-and-drop")
|
18
|
+
|
19
|
+
store = create_store
|
20
|
+
fill_store(store)
|
21
|
+
|
22
|
+
icon_view = Gtk::IconView.new(:model => store)
|
23
|
+
icon_view.set_selection_mode(:single)
|
24
|
+
icon_view.set_item_orientation(:horizontal)
|
25
|
+
icon_view.set_columns(2)
|
26
|
+
icon_view.set_reorderable(true)
|
27
|
+
|
28
|
+
renderer = Gtk::CellRendererPixbuf.new
|
29
|
+
icon_view.pack_start(renderer, true)
|
30
|
+
|
31
|
+
icon_view.set_cell_data_func(renderer) do |_layout, cell_renderer, model, iter|
|
32
|
+
text = model.get_value(iter, COL_TEXT)
|
33
|
+
if text
|
34
|
+
color = Gdk::RGBA.parse(text)
|
35
|
+
pixel = nil
|
36
|
+
if color
|
37
|
+
pixel = (color.red * 255).to_i << 24 |
|
38
|
+
(color.green * 255).to_i << 16 |
|
39
|
+
(color.blue * 255).to_i << 8 |
|
40
|
+
(color.alpha * 255).to_i
|
41
|
+
end
|
42
|
+
pixbuf = Gdk::Pixbuf.new(Gdk::Pixbuf::COLORSPACE_RGB, true, 8, 24, 24)
|
43
|
+
pixbuf.fill!(pixel) if pixel
|
44
|
+
cell_renderer.set_property("pixbuf", pixbuf)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
renderer = Gtk::CellRendererText.new
|
49
|
+
icon_view.pack_start(renderer, true)
|
50
|
+
renderer.set_property("editable", true)
|
51
|
+
renderer.signal_connect("edited") do |_cell, path_string, text|
|
52
|
+
model = icon_view.model
|
53
|
+
path = Gtk::TreePath.new(path_string)
|
54
|
+
iter = model.get_iter(path)
|
55
|
+
iter[COL_TEXT] = text
|
56
|
+
end
|
57
|
+
|
58
|
+
icon_view.set_attributes(renderer, "text" => COL_TEXT)
|
59
|
+
window.add(icon_view)
|
60
|
+
|
61
|
+
if !window.visible?
|
62
|
+
window.show_all
|
63
|
+
else
|
64
|
+
window.destroy
|
65
|
+
end
|
66
|
+
window
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.create_store
|
70
|
+
store = Gtk::ListStore.new(String)
|
71
|
+
store
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.fill_store(store)
|
75
|
+
%w(Red Green Blue Yellow).each do |color|
|
76
|
+
store.append.set_values([color])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/sample/gtk-demo/infobar.rb
CHANGED
@@ -1,78 +1,94 @@
|
|
1
|
-
# Copyright (c)
|
1
|
+
# Copyright (c) 2015 Ruby-GNOME2 Project Team
|
2
2
|
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
3
|
#
|
4
4
|
=begin
|
5
|
-
=
|
5
|
+
= Info Bars
|
6
6
|
|
7
|
-
Info bar widgets are used to report important messages to the user.
|
7
|
+
Info bar widgets are used to report important messages to the user.
|
8
8
|
=end
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
module InfobarDemo
|
10
|
+
def self.run_demo(main_window)
|
11
|
+
actions = Gtk::Box.new(:horizontal, 0)
|
12
|
+
|
13
|
+
window = Gtk::Window.new(:toplevel)
|
14
|
+
window.screen = main_window.screen
|
15
|
+
window.set_title("Info Bars")
|
16
|
+
window.set_border_width(8)
|
17
|
+
|
18
|
+
vbox = Gtk::Box.new(:vertical, 0)
|
19
|
+
window.add(vbox)
|
20
|
+
|
21
|
+
generate_simple_infobar_and_button("info", vbox, actions)
|
22
|
+
generate_simple_infobar_and_button("warning", vbox, actions)
|
23
|
+
|
24
|
+
bar = Gtk::InfoBar.new
|
25
|
+
bar.add_button("_OK", Gtk::ResponseType::OK)
|
26
|
+
bar.set_show_close_button(true)
|
27
|
+
bar.signal_connect "response" do |info_bar, response_id|
|
28
|
+
info_bar.hide if response_id == Gtk::ResponseType::CLOSE
|
29
|
+
dialog = Gtk::MessageDialog.new(:parent => info_bar.toplevel,
|
30
|
+
:flags => [:modal, :destroy_with_parent],
|
31
|
+
:type => :info,
|
32
|
+
:buttons => :ok,
|
33
|
+
:message => "You clicked a button on an info bar")
|
34
|
+
dialog.secondary_text = "Your response has id #{response_id}"
|
35
|
+
dialog.signal_connect("response") { |widget| widget.destroy }
|
36
|
+
dialog.show_all
|
37
|
+
end
|
17
38
|
|
39
|
+
vbox.pack_start(bar,
|
40
|
+
:expand => false,
|
41
|
+
:fill => false,
|
42
|
+
:padding => 0)
|
18
43
|
|
19
|
-
|
20
|
-
|
44
|
+
bar.set_message_type(:question)
|
45
|
+
label = Gtk::Label.new("This is an info bar with message type Gtk::MessageType::QUESTION")
|
46
|
+
label.set_line_wrap(true)
|
47
|
+
label.set_xalign(0)
|
21
48
|
|
22
|
-
|
23
|
-
vbox.pack_start bar, :expand => false, :fill => false, :padding => 0
|
24
|
-
bar.message_type = :info
|
25
|
-
label = Gtk::Label.new 'This is an info bar with message type GTK_MESSAGE_INFO'
|
26
|
-
bar.content_area.pack_start label, :expand => false, :fill => false, :padding => 0
|
49
|
+
bar.content_area.pack_start(label, :expand => false, :fill => false, :padding => 0)
|
27
50
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
bar.content_area.pack_start label, :expand => false, :fill => false, :padding => 0
|
51
|
+
button = Gtk::ToggleButton.new(:label => "Question")
|
52
|
+
button.bind_property("active", bar, "visible", :bidirectional)
|
53
|
+
actions.add(button)
|
54
|
+
button.set_active(false)
|
33
55
|
|
34
|
-
|
35
|
-
|
36
|
-
vbox.pack_start bar, :expand => false, :fill => false, :padding => 0
|
37
|
-
bar.message_type = :question
|
38
|
-
label = Gtk::Label.new 'This is an info bar with message type GTK_MESSAGE_QUESTION'
|
39
|
-
bar.content_area.pack_start label, :expand => false, :fill => false, :padding => 0
|
56
|
+
generate_simple_infobar_and_button("error", vbox, actions)
|
57
|
+
generate_simple_infobar_and_button("other", vbox, actions)
|
40
58
|
|
41
|
-
|
42
|
-
|
43
|
-
bar.message_type = :error
|
44
|
-
label = Gtk::Label.new 'This is an info bar with message type GTK_MESSAGE_ERROR'
|
45
|
-
bar.content_area.pack_start label, :expand => false, :fill => false, :padding => 0
|
59
|
+
frame = Gtk::Frame.new("Info bars")
|
60
|
+
vbox.pack_start(frame, :expand => false, :fill => false, :padding => 8)
|
46
61
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
label = Gtk::Label.new 'This is an info bar with message type GTK_MESSAGE_OTHER'
|
51
|
-
bar.content_area.pack_start label, :expand => false, :fill => false, :padding => 0
|
62
|
+
vbox2 = Gtk::Box.new(:vertical, 8)
|
63
|
+
vbox2.set_border_width(8)
|
64
|
+
frame.add(vbox2)
|
52
65
|
|
66
|
+
label = Gtk::Label.new("An example of different info bars")
|
67
|
+
vbox2.pack_start(label, :expand => false, :fill => false, :padding => 0)
|
68
|
+
actions.show_all
|
69
|
+
vbox2.pack_start(actions, :expand => false, :fill => false, :padding => 0)
|
53
70
|
|
54
|
-
|
55
|
-
|
71
|
+
if !window.visible?
|
72
|
+
window.show_all
|
73
|
+
else
|
74
|
+
window.destroy
|
75
|
+
end
|
76
|
+
window
|
77
|
+
end
|
56
78
|
|
57
|
-
|
58
|
-
|
59
|
-
|
79
|
+
def self.generate_simple_infobar_and_button(message_type, bar_parent, button_parent)
|
80
|
+
bar = Gtk::InfoBar.new
|
81
|
+
bar_parent.pack_start(bar, :expand => false, :fill => false, :padding => 0)
|
82
|
+
bar.set_message_type(message_type.to_sym)
|
60
83
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
84
|
+
label = Gtk::Label.new("This is an info bar with message type Gtk::MessageType::#{message_type.upcase}")
|
85
|
+
label.set_line_wrap(true)
|
86
|
+
label.set_xalign(0)
|
65
87
|
|
66
|
-
|
67
|
-
dialog = Gtk::MessageDialog.new :parent => self,
|
68
|
-
:flags => [:modal, :destroy_with_parent],
|
69
|
-
:type => :info,
|
70
|
-
:buttons_type => :ok,
|
71
|
-
:message => 'You clicked a button on an info bar'
|
88
|
+
bar.content_area.pack_start(label, :expand => false, :fill => false, :padding => 0)
|
72
89
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
90
|
+
button = Gtk::ToggleButton.new(:label => "Message")
|
91
|
+
button.bind_property("active", bar, "visible", :bidirectional)
|
92
|
+
button_parent.add(button)
|
77
93
|
end
|
78
|
-
end
|
94
|
+
end
|
data/sample/gtk-demo/links.rb
CHANGED
@@ -1,53 +1,66 @@
|
|
1
|
-
# Copyright (c)
|
1
|
+
# Copyright (c) 2015 Ruby-GNOME2 Project Team
|
2
2
|
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
3
|
#
|
4
4
|
=begin
|
5
5
|
= Links
|
6
6
|
|
7
|
-
GtkLabel can show hyperlinks. The default action is to call
|
7
|
+
GtkLabel can show hyperlinks. The default action is to call
|
8
|
+
gtk_show_uri() on their URI, but it is possible to override
|
9
|
+
this with a custom handler.
|
8
10
|
=end
|
9
|
-
|
11
|
+
module LinksDemo
|
12
|
+
def self.run_demo(main_window)
|
13
|
+
window = Gtk::Window.new(:toplevel)
|
14
|
+
window.screen = main_window.screen
|
15
|
+
window.set_title("Links")
|
16
|
+
window.set_border_width(12)
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
label = Gtk::Label.new(<<-MESSAGE)
|
19
|
+
Some <a href="http://en.wikipedia.org/wiki/Text"
|
20
|
+
title="plain text">text</a> may be marked up
|
21
|
+
as hyperlinks, which can be clicked
|
22
|
+
or activated via <a href="keynav">keynav</a>
|
23
|
+
and they work fine with other markup, like when
|
24
|
+
searching on <a href="http://www.google.com/">
|
25
|
+
<span color="#0266C8">G</span><span color="#F90101">o</span>
|
26
|
+
<span color="#F2B50F">o</span><span color="#0266C8">g</span>
|
27
|
+
<span color="#00933B">l</span><span color="#F90101">e</span>
|
28
|
+
</a>.
|
29
|
+
MESSAGE
|
30
|
+
label.set_use_markup(true)
|
15
31
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
label.signal_connect "activate-link" do |_widget, uri|
|
33
|
+
if uri == "keynav"
|
34
|
+
parent = label.toplevel
|
35
|
+
dialog = Gtk::MessageDialog.new(:parent => parent,
|
36
|
+
:flags => :destroy_with_parent,
|
37
|
+
:type => :info,
|
38
|
+
:buttons => :ok,
|
39
|
+
:message => <<-MESSAGE)
|
40
|
+
The term <i>keynav</i> is a shorthand for
|
41
|
+
keyboard navigation and refers to the process of using
|
42
|
+
a program (exclusively) via keyboard input.
|
43
|
+
MESSAGE
|
44
|
+
dialog.set_use_markup(true)
|
45
|
+
dialog.set_modal(true)
|
46
|
+
dialog.present
|
47
|
+
dialog.signal_connect "response" do
|
48
|
+
dialog.destroy
|
49
|
+
end
|
50
|
+
true
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
34
54
|
end
|
35
55
|
|
36
|
-
|
37
|
-
|
38
|
-
dialog = Gtk::MessageDialog.new :parent => self,
|
39
|
-
:flags => :destroy_with_parent,
|
40
|
-
:type => :info,
|
41
|
-
:buttons_type => :ok
|
56
|
+
window.add(label)
|
57
|
+
label.show
|
42
58
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
dialog.signal_connect(:response) {dialog.destroy}
|
48
|
-
return true
|
49
|
-
end
|
50
|
-
false
|
59
|
+
if !window.visible?
|
60
|
+
window.show_all
|
61
|
+
else
|
62
|
+
window.destroy
|
51
63
|
end
|
64
|
+
window
|
52
65
|
end
|
53
|
-
end
|
66
|
+
end
|
data/sample/gtk-demo/main.rb
CHANGED
@@ -21,6 +21,7 @@ require "optparse"
|
|
21
21
|
require "fileutils"
|
22
22
|
|
23
23
|
current_path = File.expand_path(File.dirname(__FILE__))
|
24
|
+
|
24
25
|
gresource_bin = "#{current_path}/demo.gresource"
|
25
26
|
gresource_xml = "#{current_path}/demo.gresource.xml"
|
26
27
|
|
@@ -42,24 +43,205 @@ Gio::Resources.register(resource)
|
|
42
43
|
|
43
44
|
ENV["GSETTINGS_SCHEMA_DIR"] = current_path
|
44
45
|
|
46
|
+
TITLE_COLUMN = 0
|
47
|
+
FILENAME_COLUMN = 1
|
48
|
+
STYLE_COLUMN = 2
|
49
|
+
|
50
|
+
def script_info(path)
|
51
|
+
title = depend = nil
|
52
|
+
file = File.open(path)
|
53
|
+
file.each do |ln|
|
54
|
+
if !title && ln =~ /^=\s+(.*)$/
|
55
|
+
title = Regexp.last_match(1)
|
56
|
+
if title =~ /^(.*)\((.+?)\)$/
|
57
|
+
title = Regexp.last_match(1)
|
58
|
+
depend = Regexp.last_match(2)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
break if title
|
63
|
+
end
|
64
|
+
|
65
|
+
[title, depend]
|
66
|
+
end
|
67
|
+
|
68
|
+
def generate_index
|
69
|
+
# Target scripts
|
70
|
+
scripts = Dir.glob(File.join(File.dirname(__FILE__), "*.rb"))
|
71
|
+
# Generate index tree
|
72
|
+
children = {}
|
73
|
+
index = []
|
74
|
+
|
75
|
+
scripts.each do |script|
|
76
|
+
next if ["common.rb", "main.rb"].include?(File.basename(script))
|
77
|
+
title, depend = script_info(script)
|
78
|
+
|
79
|
+
next if depend && !Gtk.const_defined?(depend)
|
80
|
+
|
81
|
+
if title =~ %r{^(.+?)/(.+)$}
|
82
|
+
parent = Regexp.last_match(1)
|
83
|
+
child = Regexp.last_match(2)
|
84
|
+
|
85
|
+
unless children[parent]
|
86
|
+
children[parent] = []
|
87
|
+
index += [[parent, nil, []]]
|
88
|
+
end
|
89
|
+
children[parent] += [[child, script]]
|
90
|
+
else
|
91
|
+
index += [[title, script]]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Sort children
|
96
|
+
children.each_key do |parent|
|
97
|
+
children[parent].sort! do |a, b|
|
98
|
+
a[0] <=> b[0]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Expand children
|
103
|
+
index.collect! do |row|
|
104
|
+
row[2] = children[row[0]] if row[2]
|
105
|
+
|
106
|
+
row
|
107
|
+
end
|
108
|
+
|
109
|
+
index.sort! do |a, b|
|
110
|
+
a[0] <=> b[0]
|
111
|
+
end
|
112
|
+
|
113
|
+
index
|
114
|
+
end
|
115
|
+
|
116
|
+
def append_children(model, source, parent = nil)
|
117
|
+
source.each do |title, filename, children|
|
118
|
+
iter = model.append(parent)
|
119
|
+
iter[TITLE_COLUMN] = title
|
120
|
+
iter[FILENAME_COLUMN] = filename
|
121
|
+
iter[STYLE_COLUMN] = Pango::FontDescription::STYLE_NORMAL
|
122
|
+
|
123
|
+
append_children(model, children, iter) if children
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_demo_name_from_filename(filename)
|
128
|
+
File.basename(filename, ".rb").tr("-", "_")
|
129
|
+
end
|
130
|
+
|
131
|
+
def get_module_name_from_filename(filename)
|
132
|
+
pattern = get_demo_name_from_filename(filename)
|
133
|
+
module_name = pattern.split("_").map(&:capitalize).join
|
134
|
+
module_name << "Demo"
|
135
|
+
end
|
136
|
+
|
137
|
+
def list_demos(source, is_child = false)
|
138
|
+
source.each do |title, filename, children|
|
139
|
+
if is_child
|
140
|
+
printf("%-30.30s", "\t" + title)
|
141
|
+
printf("%-30.30s", get_demo_name_from_filename(filename))
|
142
|
+
puts ""
|
143
|
+
elsif filename
|
144
|
+
printf("%-38.38s", title)
|
145
|
+
printf("%-30.30s", get_demo_name_from_filename(filename))
|
146
|
+
puts ""
|
147
|
+
else
|
148
|
+
puts "#{title} : "
|
149
|
+
end
|
150
|
+
|
151
|
+
list_demos(children, true) if children
|
152
|
+
end
|
153
|
+
end
|
45
154
|
|
155
|
+
def find_demo_filename_from_name(source, name)
|
156
|
+
demo_filename = nil
|
157
|
+
source.each do |_title, filename, children|
|
158
|
+
if filename && name == get_demo_name_from_filename(filename)
|
159
|
+
demo_filename = filename
|
160
|
+
end
|
161
|
+
break if demo_filename
|
162
|
+
(demo_filename = find_demo_filename_from_name(children, name)) if children
|
163
|
+
end
|
164
|
+
demo_filename
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_demo_filename_from_name(name)
|
168
|
+
index = generate_index
|
169
|
+
filename = find_demo_filename_from_name(index, name)
|
170
|
+
puts "Demo not found" unless filename
|
171
|
+
|
172
|
+
filename
|
173
|
+
end
|
174
|
+
|
175
|
+
def run_demo_from_file(filename, window)
|
176
|
+
module_name = get_module_name_from_filename(filename)
|
177
|
+
|
178
|
+
unless Module.const_defined?(module_name) == true
|
179
|
+
require filename
|
180
|
+
end
|
181
|
+
|
182
|
+
module_object = Module.const_get(module_name)
|
183
|
+
demo = module_object.send(:run_demo, window)
|
184
|
+
|
185
|
+
if demo && demo.class == Gtk::Window
|
186
|
+
demo.set_transient_for(window)
|
187
|
+
demo.modal = true
|
188
|
+
end
|
189
|
+
demo
|
190
|
+
end
|
46
191
|
|
47
192
|
class Demo < Gtk::Application
|
48
193
|
def initialize
|
49
194
|
super("org.gtk.Demo", [:non_unique, :handles_command_line])
|
50
195
|
|
196
|
+
action = Gio::SimpleAction.new("quit")
|
197
|
+
action.signal_connect "activate" do |_action, _parameter|
|
198
|
+
quit
|
199
|
+
end
|
200
|
+
add_action(action)
|
201
|
+
|
202
|
+
action = Gio::SimpleAction.new("about")
|
203
|
+
action.signal_connect "activate" do |_action, _parameter|
|
204
|
+
Gtk::AboutDialog.show(active_window,
|
205
|
+
"program_name" => "GTK+ Demo",
|
206
|
+
"version" => Gtk::Version::STRING,
|
207
|
+
"copyright" => "(C) 1997-2013 The GTK+ Team",
|
208
|
+
"license_type" => Gtk::License::LGPL_2_1,
|
209
|
+
"website" => "http://www.gtk.org",
|
210
|
+
"comments" => "Program to demonstrate GTK+ widgets",
|
211
|
+
"authors" => ["The GTK+ Team"],
|
212
|
+
"logo_icon_name" => "gtk3-demo",
|
213
|
+
"title" => "About GTK+ Demo"
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
217
|
+
add_action(action)
|
51
218
|
@options = {}
|
52
219
|
@exit_status = 0
|
53
220
|
|
54
221
|
signal_connect "startup" do |application|
|
55
|
-
puts "startup"
|
56
222
|
@builder = Gtk::Builder.new(:resource => "/ui/main.ui")
|
57
223
|
appmenu = @builder["appmenu"]
|
58
224
|
application.set_app_menu(appmenu)
|
225
|
+
|
226
|
+
@info_buffer = Gtk::TextBuffer.new
|
227
|
+
@source_buffer = Gtk::TextBuffer.new
|
228
|
+
|
229
|
+
@info_buffer.create_tag("title",
|
230
|
+
"font" => "Sans 18")
|
231
|
+
|
232
|
+
@source_buffer.create_tag("comment",
|
233
|
+
"foreground" => "red")
|
234
|
+
@source_buffer.create_tag("const",
|
235
|
+
"foreground" => "ForestGreen")
|
236
|
+
@source_buffer.create_tag("string",
|
237
|
+
"foreground" => "RosyBrown",
|
238
|
+
"weight" => Pango::FontDescription::WEIGHT_BOLD
|
239
|
+
)
|
240
|
+
@source_buffer.create_tag("reserved",
|
241
|
+
"foreground" => "purple")
|
59
242
|
end
|
60
243
|
|
61
|
-
signal_connect "activate" do |
|
62
|
-
puts "activate"
|
244
|
+
signal_connect "activate" do |_application|
|
63
245
|
begin
|
64
246
|
run_application
|
65
247
|
rescue => error
|
@@ -68,8 +250,7 @@ class Demo < Gtk::Application
|
|
68
250
|
end
|
69
251
|
end
|
70
252
|
|
71
|
-
signal_connect "command-line" do |
|
72
|
-
puts "cmd"
|
253
|
+
signal_connect "command-line" do |_application, command_line|
|
73
254
|
begin
|
74
255
|
parse_command_line(command_line.arguments)
|
75
256
|
rescue SystemExit => error
|
@@ -85,9 +266,10 @@ class Demo < Gtk::Application
|
|
85
266
|
@exit_status
|
86
267
|
end
|
87
268
|
end
|
88
|
-
|
269
|
+
end
|
89
270
|
|
90
271
|
private
|
272
|
+
|
91
273
|
def parse_command_line(arguments)
|
92
274
|
parser = OptionParser.new
|
93
275
|
parser.on("-r", "--run EXAMPLE", "Run an example") do |example|
|
@@ -109,66 +291,194 @@ class Demo < Gtk::Application
|
|
109
291
|
|
110
292
|
def run_application
|
111
293
|
if @options[:list]
|
112
|
-
|
113
|
-
# list_demos
|
294
|
+
list_demos(generate_index)
|
114
295
|
quit
|
115
296
|
end
|
116
297
|
|
117
|
-
if @options[:name]
|
118
|
-
puts "name"
|
119
|
-
# lookup_for_corresponding_demo
|
120
|
-
# load_demo
|
121
|
-
end
|
122
|
-
|
123
|
-
if @options[:autoquit]
|
124
|
-
puts "autoquit"
|
125
|
-
GLib::Timeout.add(1) do
|
126
|
-
#implement auto_quit
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
298
|
window = @builder["window"]
|
131
299
|
add_window(window)
|
132
|
-
|
133
300
|
action = Gio::SimpleAction.new("run")
|
301
|
+
|
134
302
|
action.signal_connect "activate" do |_action, _parameter|
|
135
|
-
|
303
|
+
selection = @treeview.selection
|
304
|
+
iter = selection.selected
|
305
|
+
filename = iter[1]
|
306
|
+
run_demo_from_file(filename, windows.first) if filename
|
136
307
|
end
|
137
|
-
add_action(action)
|
308
|
+
window.add_action(action)
|
138
309
|
|
139
|
-
notebook = @builder["notebook"]
|
140
|
-
|
141
|
-
|
310
|
+
@notebook = @builder["notebook"]
|
311
|
+
@info_view = @builder["info-textview"]
|
312
|
+
@source_view = @builder["source-textview"]
|
142
313
|
headerbar = @builder["headerbar"]
|
143
|
-
treeview = @builder["treeview"]
|
144
|
-
model = treeview.model
|
314
|
+
@treeview = @builder["treeview"]
|
315
|
+
model = @treeview.model
|
316
|
+
append_children(model, generate_index)
|
145
317
|
|
146
|
-
|
147
|
-
scrollbar =
|
318
|
+
@source_sw = @builder["source-scrolledwindow"]
|
319
|
+
scrollbar = @source_sw.vscrollbar
|
148
320
|
|
149
|
-
menu = Gtk::Menu.new
|
321
|
+
@menu = Gtk::Menu.new
|
150
322
|
|
151
|
-
item = Gtk::MenuItem.new("Start")
|
152
|
-
menu.append(item)
|
323
|
+
item = Gtk::MenuItem.new(:label => "Start")
|
324
|
+
@menu.append(item)
|
153
325
|
item.signal_connect "activate" do
|
154
|
-
adj = scrollbar.
|
155
|
-
adj.value = adj.
|
326
|
+
adj = scrollbar.adjustment
|
327
|
+
adj.value = adj.lower
|
156
328
|
end
|
157
329
|
|
158
|
-
item = Gtk::MenuItem.new("End")
|
159
|
-
menu.append(item)
|
330
|
+
item = Gtk::MenuItem.new(:label => "End")
|
331
|
+
@menu.append(item)
|
160
332
|
item.signal_connect "activate" do
|
161
|
-
adj = scrollbar.
|
162
|
-
adj.value = adj.
|
333
|
+
adj = scrollbar.adjustment
|
334
|
+
adj.value = adj.upper - adj.page_size
|
163
335
|
end
|
164
336
|
|
165
|
-
|
337
|
+
@info_sw = @builder["info-scrolledwindow"]
|
338
|
+
|
339
|
+
@menu.show_all
|
166
340
|
|
167
|
-
scrollbar.signal_connect "popup-menu" do
|
168
|
-
menu.popup(nil, nil, Gtk.current_event_time)
|
341
|
+
scrollbar.signal_connect "popup-menu" do |widget, button, activate_time|
|
342
|
+
@menu.popup(nil, nil, 0, Gtk.current_event_time)
|
343
|
+
end
|
344
|
+
|
345
|
+
@treeview.signal_connect "row-activated" do |_tree_view, path, _column|
|
346
|
+
iter = model.get_iter(path)
|
347
|
+
filename = iter[1]
|
348
|
+
iter[2] = Pango::FontDescription::STYLE_ITALIC
|
349
|
+
demo = run_demo_from_file(filename, windows.first)
|
350
|
+
demo.signal_connect "destroy" do
|
351
|
+
iter[2] = Pango::FontDescription::STYLE_NORMAL
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
treeview_selection = @builder["treeview-selection"]
|
356
|
+
treeview_selection.signal_connect "changed" do |selection, _model|
|
357
|
+
iter = selection.selected
|
358
|
+
filename = iter[1]
|
359
|
+
title = iter[0]
|
360
|
+
load_file(filename) if filename
|
361
|
+
headerbar.set_title(title)
|
169
362
|
end
|
170
363
|
|
171
364
|
window.show_all
|
365
|
+
|
366
|
+
if @options[:name]
|
367
|
+
filename = get_demo_filename_from_name(@options[:name])
|
368
|
+
run_demo_from_file(filename, windows.first)
|
369
|
+
end
|
370
|
+
|
371
|
+
if @options[:autoquit]
|
372
|
+
GLib::Timeout.add_seconds(1) do
|
373
|
+
quit
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def fill_buffers_from(file)
|
379
|
+
start = @info_buffer.get_iter_at(:offset => 0)
|
380
|
+
state = :before_header
|
381
|
+
|
382
|
+
file.each do |line|
|
383
|
+
case state
|
384
|
+
when :before_header
|
385
|
+
state = :in_header if line =~ /^=begin$/
|
386
|
+
when :in_header
|
387
|
+
if line =~ /^=end$/
|
388
|
+
state = :body
|
389
|
+
start = @source_buffer.get_iter_at(:offset => 0)
|
390
|
+
elsif line =~ /^=\s+(.*)$/
|
391
|
+
title = Regexp.last_match(1)
|
392
|
+
title.gsub!(/\s*\(.*\)$/, "") # Delete depend field
|
393
|
+
|
394
|
+
last = start
|
395
|
+
|
396
|
+
@info_buffer.insert(last, title)
|
397
|
+
start = last.clone
|
398
|
+
|
399
|
+
start.backward_chars(title.length)
|
400
|
+
@info_buffer.apply_tag("title", start, last)
|
401
|
+
|
402
|
+
start = last
|
403
|
+
else
|
404
|
+
@info_buffer.insert(start, line)
|
405
|
+
end
|
406
|
+
when :body # Reading program body
|
407
|
+
@source_buffer.insert(start, line)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def load_file(filename)
|
413
|
+
return if filename == @current_file
|
414
|
+
|
415
|
+
# implement add_data_tab
|
416
|
+
|
417
|
+
@info_buffer.delete(*@info_buffer.bounds)
|
418
|
+
|
419
|
+
@source_buffer.delete(*@source_buffer.bounds)
|
420
|
+
|
421
|
+
file = begin
|
422
|
+
File.open(filename)
|
423
|
+
rescue
|
424
|
+
$stderr.puts "Cannot open: #{$ERROR_INFO}" if $DEBUG
|
425
|
+
return
|
426
|
+
end
|
427
|
+
|
428
|
+
fill_buffers_from(file)
|
429
|
+
|
430
|
+
fontify
|
431
|
+
|
432
|
+
@source_view.buffer = @source_buffer
|
433
|
+
@info_view.buffer = @info_buffer
|
434
|
+
|
435
|
+
@current_file = filename
|
436
|
+
end
|
437
|
+
|
438
|
+
def fontify(start_iter = @source_buffer.start_iter,
|
439
|
+
end_iter = @source_buffer.end_iter)
|
440
|
+
str = @source_buffer.get_text(start_iter, end_iter, true)
|
441
|
+
tokenizer = RubyTokonizer.new
|
442
|
+
tokenizer.tokenize(str, start_iter.offset) do |tag, start, last|
|
443
|
+
@source_buffer.apply_tag(tag.to_s,
|
444
|
+
@source_buffer.get_iter_at(:offset => start),
|
445
|
+
@source_buffer.get_iter_at(:offset => last))
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
class RubyTokonizer
|
450
|
+
RESERVED_WORDS = %w(begin end module class def if then else
|
451
|
+
while unless do case when require yield)
|
452
|
+
RESERVED_WORDS_PATTERN = Regexp.compile(/(^|\s+)(#{RESERVED_WORDS.collect do |pat| Regexp.quote(pat) end.join("|")})(\s+|$)/)
|
453
|
+
|
454
|
+
def tokenize(str, index = 0)
|
455
|
+
until str.empty?
|
456
|
+
tag = nil
|
457
|
+
|
458
|
+
case str
|
459
|
+
when /".+?"/, /'.+?'/
|
460
|
+
tag = :string
|
461
|
+
when /#.*$/
|
462
|
+
tag = :comment
|
463
|
+
when RESERVED_WORDS_PATTERN
|
464
|
+
tag = :reserved
|
465
|
+
when /[A-Z][A-Za-z0-9_]+/
|
466
|
+
tag = :const
|
467
|
+
end
|
468
|
+
|
469
|
+
if tag
|
470
|
+
tokenize($LAST_MATCH_INFO.pre_match, index) do |*args|
|
471
|
+
yield(*args)
|
472
|
+
end
|
473
|
+
yield(tag, index + $LAST_MATCH_INFO.begin(0), index + $LAST_MATCH_INFO.end(0))
|
474
|
+
index += (str.length - $LAST_MATCH_INFO.post_match.length)
|
475
|
+
str = $LAST_MATCH_INFO.post_match
|
476
|
+
else
|
477
|
+
index += str.length
|
478
|
+
str = ""
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
172
482
|
end
|
173
483
|
end
|
174
484
|
|