gtk3 3.0.7 → 3.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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/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 +55 -19
- 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
|
|