gtk3 3.0.7 → 3.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/ext/gtk3/extconf.rb +1 -0
  3. data/ext/gtk3/rb-gtk3-tree-view.c +4 -0
  4. data/ext/gtk3/rb-gtk3.c +245 -60
  5. data/lib/gtk3/box.rb +22 -0
  6. data/lib/gtk3/builder.rb +50 -29
  7. data/lib/gtk3/deprecated.rb +7 -0
  8. data/lib/gtk3/entry-buffer.rb +28 -0
  9. data/lib/gtk3/list-store.rb +2 -20
  10. data/lib/gtk3/loader.rb +6 -0
  11. data/lib/gtk3/menu-item.rb +8 -7
  12. data/lib/gtk3/tree-iter.rb +25 -1
  13. data/lib/gtk3/tree-model.rb +41 -0
  14. data/lib/gtk3/tree-store.rb +7 -6
  15. data/lib/gtk3/widget.rb +18 -1
  16. data/sample/gtk-demo/TODO +45 -39
  17. data/sample/gtk-demo/assistant.rb +123 -0
  18. data/sample/gtk-demo/builder.rb +75 -38
  19. data/sample/gtk-demo/button_box.rb +100 -0
  20. data/sample/gtk-demo/colorsel.rb +49 -65
  21. data/sample/gtk-demo/css_accordion.rb +33 -55
  22. data/sample/gtk-demo/css_basics.rb +55 -80
  23. data/sample/gtk-demo/css_multiplebgs.rb +112 -0
  24. data/sample/gtk-demo/css_pixbufs.rb +84 -0
  25. data/sample/gtk-demo/css_shadows.rb +101 -0
  26. data/sample/gtk-demo/cursors.rb +114 -0
  27. data/sample/gtk-demo/dialog.rb +105 -115
  28. data/sample/gtk-demo/entry_buffer.rb +44 -0
  29. data/sample/gtk-demo/entry_completion.rb +40 -52
  30. data/sample/gtk-demo/expander.rb +60 -26
  31. data/sample/gtk-demo/filtermodel.rb +119 -0
  32. data/sample/gtk-demo/font_features.rb +117 -0
  33. data/sample/gtk-demo/headerbar.rb +57 -0
  34. data/sample/gtk-demo/iconview_edit.rb +79 -0
  35. data/sample/gtk-demo/infobar.rb +75 -59
  36. data/sample/gtk-demo/links.rb +53 -40
  37. data/sample/gtk-demo/main.rb +353 -43
  38. data/sample/gtk-demo/main.ui +9 -9
  39. data/sample/gtk-demo/markup.rb +46 -0
  40. data/sample/gtk-demo/menus.rb +111 -162
  41. data/sample/gtk-demo/modelbutton.rb +47 -0
  42. data/sample/gtk-demo/overlay.rb +61 -0
  43. data/sample/gtk-demo/overlay2.rb +75 -0
  44. data/sample/gtk-demo/panes.rb +114 -133
  45. data/sample/gtk-demo/pickers.rb +70 -0
  46. data/sample/gtk-demo/popover.rb +110 -0
  47. data/sample/gtk-demo/printing.rb +68 -83
  48. data/sample/gtk-demo/revealer.rb +53 -0
  49. data/sample/gtk-demo/scale.rb +26 -0
  50. data/sample/gtk-demo/search_entry2.rb +107 -0
  51. data/sample/gtk-demo/sidebar.rb +68 -0
  52. data/sample/gtk-demo/sizegroup.rb +93 -105
  53. data/sample/gtk-demo/spinner.rb +53 -50
  54. data/sample/gtk-demo/stack.rb +28 -0
  55. data/sample/gtk-demo/test_mod.rb +22 -0
  56. data/sample/gtk-demo/textmask.rb +61 -0
  57. data/sample/gtk-demo/theming_style_classes.rb +16 -12
  58. data/sample/misc/app-menu.ui +19 -0
  59. data/sample/misc/button-menu.ui +19 -0
  60. data/sample/misc/icons-theme-viewer.rb +65 -0
  61. data/sample/misc/menu.rb +3 -3
  62. data/sample/misc/menus_from_resources.gresource.xml +8 -0
  63. data/sample/misc/menus_from_resources.rb +91 -0
  64. data/sample/misc/statusicon.rb +1 -1
  65. data/sample/misc/toolbar-menu.ui +23 -0
  66. data/sample/misc/treestore.rb +63 -0
  67. data/sample/tutorial/README.md +368 -6
  68. data/test/test-gtk-box.rb +13 -0
  69. data/test/test-gtk-builder.rb +1 -1
  70. data/test/test-gtk-clipboard.rb +124 -0
  71. data/test/test-gtk-container.rb +3 -3
  72. data/test/test-gtk-entry-buffer.rb +32 -0
  73. data/test/test-gtk-list-store.rb +30 -12
  74. data/test/test-gtk-menu.rb +32 -0
  75. data/test/test-gtk-tree-iter.rb +61 -5
  76. data/test/test-gtk-tree-path.rb +26 -1
  77. data/test/test-gtk-tree-sortable.rb +35 -0
  78. data/test/test-gtk-tree-store.rb +34 -0
  79. data/test/test-gtk-widget.rb +33 -2
  80. metadata +55 -19
  81. 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
@@ -1,78 +1,94 @@
1
- # Copyright (c) 2013 Ruby-GNOME2 Project Team
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
- = Info bar
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
- require 'common'
10
-
11
- module Demo
12
- class InfoBar < BasicWindow
13
- def initialize
14
- super('Info Bars')
15
-
16
- self.border_width = 8
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
- vbox = Gtk::Box.new :vertical
20
- self.add vbox
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
- bar = Gtk::InfoBar.new
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
- bar = Gtk::InfoBar.new
29
- vbox.pack_start bar, :expand => false, :fill => false, :padding => 0
30
- bar.message_type = :warning
31
- label = Gtk::Label.new 'This is an info bar with message type GTK_MESSAGE_WARNING'
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
- bar = Gtk::InfoBar.new [:ok, :ok]
35
- bar.signal_connect(:response) {|widget, response_id| on_bar_response widget, response_id}
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
- bar = Gtk::InfoBar.new
42
- vbox.pack_start bar, :expand => false, :fill => false, :padding => 0
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
- bar = Gtk::InfoBar.new
48
- vbox.pack_start bar, :expand => false, :fill => false, :padding => 0
49
- bar.message_type = :other
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
- frame = Gtk::Frame.new 'Info bars'
55
- vbox.pack_start frame, :expand => false, :fill => false, :padding => 8
71
+ if !window.visible?
72
+ window.show_all
73
+ else
74
+ window.destroy
75
+ end
76
+ window
77
+ end
56
78
 
57
- vbox2 = Gtk::Box.new :vertical, 8
58
- vbox2.border_width = 8
59
- frame.add vbox2
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
- # Standard message dialog
62
- label = Gtk::Label.new 'An example of different info bars'
63
- vbox2.pack_start label, :expand => false, :fill => false, :padding => 0
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
- def on_bar_response info_bar, response_id
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
- dialog.set_secondary_text "Your response has id %d" % response_id
74
- dialog.signal_connect(:response) {dialog.destroy}
75
- dialog.show_all
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
@@ -1,53 +1,66 @@
1
- # Copyright (c) 2013 Ruby-GNOME2 Project Team
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 gtk_show_uri() on their URI, but it is possible to override this with a custom handler.
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
- require 'common'
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
- module Demo
12
- class Links < BasicWindow
13
- def initialize
14
- super('Links')
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
- title = 'Links'
17
- border_width = 12
18
- signal_connect(:destroy) {self.destroy}
19
-
20
- label = Gtk::Label.new "Some <a href=\"http://en.wikipedia.org/wiki/Text\"" +
21
- "title=\"plain text\">text</a> may be marked up\n" +
22
- "as hyperlinks, which can be clicked\n" +
23
- "or activated via <a href=\"keynav\">keynav</a>\n" +
24
- "and they work fine with other markup, like when\n" +
25
- "searching on <a href=\"http://www.google.com/\">" +
26
- "<span color=\"#0266C8\">G</span><span color=\"#F90101\">o</span>" +
27
- "<span color=\"#F2B50F\">o</span><span color=\"#0266C8\">g</span>" +
28
- "<span color=\"#00933B\">l</span><span color=\"#F90101\">e</span>" +
29
- "</a>."
30
- label.use_markup = true
31
- label.signal_connect(:activate_link) {|widget, uri| activate_link uri}
32
- add label
33
- label.show
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
- def activate_link uri
37
- if uri == 'keynav'
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
- dialog.markup = "The term <i>keynav</i> is a shorthand for " +
44
- "keyboard navigation and refers to the process of using " +
45
- "a program (exclusively) via keyboard input."
46
- dialog.present
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
@@ -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 |application|
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 |application, command_line|
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
- end
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
- puts "list"
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
- # activate_run
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
- info_textwiew = @builder["info-textview"]
141
- source_textview = @builder["source-textview"]
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
- sw = @builder["source-scrolledwindow"]
147
- scrollbar = sw.vscrollbar
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.adjustement
155
- adj.value = adj.get_lower
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.adjustement
162
- adj.value = adj.get_upper - adj.get_page_size
333
+ adj = scrollbar.adjustment
334
+ adj.value = adj.upper - adj.page_size
163
335
  end
164
336
 
165
- menu.show_all
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