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,19 @@
1
+ <?xml version="1.0"?>
2
+ <interface>
3
+ <!-- interface-requires gtk+ 3.0 -->
4
+ <menu id="appmenu">
5
+ <section>
6
+ <item>
7
+ <attribute name="label" translatable="yes">_About</attribute>
8
+ <attribute name="action">app.about</attribute>
9
+ </item>
10
+ </section>
11
+
12
+ <section>
13
+ <item>
14
+ <attribute name="label" translatable="yes">_Quit</attribute>
15
+ <attribute name="action">app.quit</attribute>
16
+ </item>
17
+ </section>
18
+ </menu>
19
+ </interface>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0"?>
2
+ <interface>
3
+ <!-- interface-requires gtk+ 3.0 -->
4
+ <menu id="buttonmenu">
5
+ <section>
6
+ <attribute name="display-hint">horizontal-buttons</attribute>
7
+ <item>
8
+ <attribute name="label">Copy</attribute>
9
+ <attribute name="action">app.copy</attribute>
10
+ <attribute name="verb-icon">edit-copy-symbolic</attribute>
11
+ </item>
12
+ <item>
13
+ <attribute name="label">Paste</attribute>
14
+ <attribute name="action">app.paste</attribute>
15
+ <attribute name="verb-icon">edit-paste-symbolic</attribute>
16
+ </item>
17
+ </section>
18
+ </menu>
19
+ </interface>
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ icons-theme-viewer.rb - Ruby/GTK sample script.
4
+
5
+ Copyright (c) 2016 Ruby-GNOME2 Project Team
6
+ This program is licenced under the same licence as Ruby-GNOME2.
7
+ =end
8
+
9
+ require "gtk3"
10
+
11
+ def fill_model(icons)
12
+ model = Gtk::ListStore.new(String, Gdk::Pixbuf)
13
+ icons.each do |icon|
14
+ pixbuf = Gtk::IconTheme.default.load_icon(icon, 32, 0)
15
+ iter = model.append
16
+ iter[0] = icon
17
+ iter[1] = pixbuf
18
+ end
19
+ model
20
+ end
21
+
22
+ def gen_icon_view(pattern, context = nil)
23
+ icon_theme = Gtk::IconTheme.default
24
+ icons = icon_theme.icons(context).grep(/#{pattern}/)
25
+ model = fill_model(icons)
26
+ icon_view = Gtk::IconView.new(:model => model)
27
+ icon_view.text_column = 0
28
+ icon_view.pixbuf_column = 1
29
+ icon_view
30
+ end
31
+
32
+ window = Gtk::Window.new("View all your icons")
33
+ window.set_default_size(700, 700)
34
+ window.signal_connect("delete-event") { Gtk.main_quit }
35
+
36
+ icon_view = gen_icon_view("application")
37
+ sw = Gtk::ScrolledWindow.new(nil, nil)
38
+ sw.add(icon_view)
39
+
40
+ entry = Gtk::Entry.new
41
+ entry.buffer.text = "application"
42
+ entry.tooltip_text = "Use a pattern to filter icons"
43
+ entry.set_icon_from_icon_name(:secondary, "edit-clear")
44
+ entry.set_icon_tooltip_text(:secondary, "Reset pattern")
45
+
46
+ entry.signal_connect "icon-release" do |widget, position|
47
+ widget.buffer.text = "" if position == :secondary
48
+ end
49
+
50
+ entry.signal_connect "activate" do |widget|
51
+ sw.remove(icon_view)
52
+ pattern = widget.buffer.text
53
+ icon_view = gen_icon_view(pattern)
54
+ sw.add(icon_view)
55
+ window.show_all
56
+ end
57
+
58
+ box = Gtk::Box.new(:vertical, 0)
59
+ box.pack_start(entry)
60
+ box.pack_start(sw, :expand => true, :fill => true)
61
+
62
+ window.add(box)
63
+ window.show_all
64
+
65
+ Gtk.main
@@ -64,15 +64,15 @@ menubar = Gtk::MenuBar.new
64
64
  box1.pack_start(menubar, :expand => false, :fill => true, :padding => 0)
65
65
 
66
66
  menu = create_menu(2)
67
- menuitem = Gtk::MenuItem.new("test\nline2")
67
+ menuitem = Gtk::MenuItem.new(:label => "test\nline2")
68
68
  menuitem.set_submenu(menu)
69
69
  menubar.append(menuitem)
70
70
 
71
- menuitem = Gtk::MenuItem.new("foo")
71
+ menuitem = Gtk::MenuItem.new(:label => "foo")
72
72
  menuitem.set_submenu(create_menu(3))
73
73
  menubar.append(menuitem)
74
74
 
75
- menuitem = Gtk::MenuItem.new("bar")
75
+ menuitem = Gtk::MenuItem.new(:label => "bar")
76
76
  menuitem.set_submenu(create_menu(4))
77
77
  menubar.append(menuitem)
78
78
 
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <gresources>
3
+ <gresource prefix="/org/gtk/menus_from_resources">
4
+ <file preprocess="xml-stripblanks">app-menu.ui</file>
5
+ <file preprocess="xml-stripblanks">toolbar-menu.ui</file>
6
+ <file preprocess="xml-stripblanks">button-menu.ui</file>
7
+ </gresource>
8
+ </gresources>
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ menus_from_resources.rb - Ruby/GTK sample script.
4
+
5
+ Copyright (c) 2016 Ruby-GNOME2 Project Team
6
+ This program is licenced under the same licence as Ruby-GNOME2.
7
+ =end
8
+
9
+ require "gtk3"
10
+ require "fileutils"
11
+
12
+ PATH = File.expand_path(File.dirname(__FILE__))
13
+
14
+ gresource_bin = "#{PATH}/menus_from_resources.gresource"
15
+ gresource_xml = "#{PATH}/menus_from_resources.gresource.xml"
16
+
17
+ system("glib-compile-resources",
18
+ "--target", gresource_bin,
19
+ "--sourcedir", File.dirname(gresource_xml),
20
+ gresource_xml)
21
+
22
+ at_exit do
23
+ FileUtils.rm_f(gresource_bin)
24
+ end
25
+
26
+ resource = Gio::Resource.load(gresource_bin)
27
+ Gio::Resources.register(resource)
28
+
29
+ application_instance = Gtk::Application.new("org.gtk.menus_from_resources",
30
+ :non_unique)
31
+
32
+ application_instance.signal_connect "startup" do |application|
33
+ %w(about preferences quit copy paste open save close).each do |label|
34
+ action = Gio::SimpleAction.new(label)
35
+ action.signal_connect("activate") do |_action, _parameter|
36
+ puts label
37
+ end
38
+ application.add_action(action)
39
+ end
40
+ builder = Gtk::Builder.new(:resource => "/org/gtk/menus_from_resources/app-menu.ui")
41
+ app_menu = builder["appmenu"]
42
+ application.set_app_menu(app_menu)
43
+ end
44
+
45
+ application_instance.signal_connect "activate" do |application|
46
+ window = Gtk::ApplicationWindow.new(application)
47
+ window.set_default_size(200, 200)
48
+ window.border_width = 20
49
+
50
+ toolbar = Gtk::Toolbar.new
51
+ toolbar.style = :both
52
+ toolbutton = Gtk::ToolButton.new(:label => "Open a Menu", :stock_id => Gtk::Stock::OPEN)
53
+ toolbutton.signal_connect "clicked" do |widget|
54
+ builder = Gtk::Builder.new(:resource => "/org/gtk/menus_from_resources/toolbar-menu.ui")
55
+ menu = Gtk::Menu.new(builder["toolbarmenu"])
56
+ # This method is important, it links the menu to the
57
+ # Gio::Actions of the Gtk::Application throught one of
58
+ # its children
59
+ menu.attach_to_widget(widget)
60
+
61
+ menu.show_all
62
+ event = Gtk.current_event
63
+ menu.popup(nil, nil, event.button, event.time)
64
+ end
65
+ toolbar.insert(toolbutton, 0)
66
+
67
+ button = Gtk::Button.new(:label => "Click me")
68
+ button.signal_connect "clicked" do |widget|
69
+ builder = Gtk::Builder.new(:resource => "/org/gtk/menus_from_resources/button-menu.ui")
70
+ menu = Gtk::Popover.new(widget, builder["buttonmenu"])
71
+ event = Gtk.current_event
72
+ x, y = event.window.coords_to_parent(event.x,
73
+ event.y)
74
+ rect = Gdk::Rectangle.new(x - widget.allocation.x,
75
+ y - widget.allocation.y,
76
+ 1,
77
+ 1)
78
+ menu.set_pointing_to(rect)
79
+ menu.show
80
+ end
81
+ hbox = Gtk::Box.new(:vertical, 0)
82
+
83
+ hbox.pack_start(toolbar, :expand => false, :fill => false)
84
+ hbox.pack_start(button, :expand => true, :fill => true)
85
+ window.add(hbox)
86
+
87
+ window.show_all
88
+ window.present
89
+ end
90
+
91
+ application_instance.run
@@ -28,7 +28,7 @@ class StatusIconSample < Gtk::StatusIcon
28
28
  signal_connect("popup-menu") do |w, button, activate_time|
29
29
  menu = Gtk::Menu.new
30
30
 
31
- menuitem = Gtk::MenuItem.new("Quit")
31
+ menuitem = Gtk::MenuItem.new(:label => "Quit")
32
32
  menuitem.signal_connect("activate") do
33
33
  set_visible(false)
34
34
  Gtk.main_quit
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0"?>
2
+ <interface>
3
+ <!-- interface-requires gtk+ 3.0 -->
4
+ <menu id="toolbarmenu">
5
+ <section>
6
+ <item>
7
+ <attribute name="label" translatable="yes">_Open</attribute>
8
+ <attribute name="action">app.open</attribute>
9
+ </item>
10
+ <item>
11
+ <attribute name="label" translatable="yes">_Save</attribute>
12
+ <attribute name="action">app.save</attribute>
13
+ </item>
14
+ </section>
15
+
16
+ <section>
17
+ <item>
18
+ <attribute name="label" translatable="yes">_Close</attribute>
19
+ <attribute name="action">app.close</attribute>
20
+ </item>
21
+ </section>
22
+ </menu>
23
+ </interface>
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ treestore.rb - Gtk::TreeStore sample
4
+
5
+ Copyright (c) 2016 Ruby-GNOME2 Project Team
6
+ This program is licenced under the same licence as Ruby-GNOME2.
7
+ Based on https://developer.gnome.org/gtk3/stable/TreeWidget.html
8
+ =end
9
+
10
+ require "gtk3"
11
+
12
+ TITLE_COLUMN = 0
13
+ AUTHOR_COLUMN = 1
14
+ CHECKED_COLUMN = 2
15
+
16
+ model = Gtk::TreeStore.new(String, String, TrueClass)
17
+ iter = model.append(nil)
18
+ iter[TITLE_COLUMN] = "The Principle of Reason"
19
+ iter[AUTHOR_COLUMN] = "Martin Heidegger"
20
+ iter[CHECKED_COLUMN] = false
21
+
22
+ iter = model.append(nil)
23
+ iter.set_values(["The Art of Computer Programming", "Donald E. Knuth", true])
24
+
25
+ # append child
26
+ child_iter = model.append(iter)
27
+ child_iter[TITLE_COLUMN] = "Volume 1: Fundamental Algorithms"
28
+
29
+ # append another child
30
+ child_iter = model.append(iter)
31
+ child_iter.set_value(TITLE_COLUMN, "Volume 2: Seminumerical Algorithms")
32
+ child_iter.set_value(CHECKED_COLUMN, true)
33
+
34
+ # append another child
35
+ child_iter = model.append(iter)
36
+ child_iter.set_values(["Volume 3: Sorting and Searching",
37
+ "Donald E. Knuth",
38
+ true])
39
+
40
+ def treeview_widget_of(model)
41
+ treeview = Gtk::TreeView.new(model)
42
+ treeview.append_column(Gtk::TreeViewColumn.new("Title",
43
+ Gtk::CellRendererText.new,
44
+ :text => TITLE_COLUMN))
45
+ treeview.append_column(Gtk::TreeViewColumn.new("Author",
46
+ Gtk::CellRendererText.new,
47
+ :text => AUTHOR_COLUMN))
48
+ treeview.append_column(Gtk::TreeViewColumn.new("Author",
49
+ Gtk::CellRendererToggle.new,
50
+ :active => CHECKED_COLUMN))
51
+ treeview
52
+ end
53
+
54
+ def display_model(model)
55
+ win = Gtk::Window.new(:toplevel)
56
+ win.title = "Simple Gtk::TreeStore"
57
+ win.add(treeview_widget_of(model))
58
+ win.show_all
59
+ win.signal_connect("destroy") { Gtk.main_quit }
60
+ Gtk.main
61
+ end
62
+
63
+ display_model(model)
@@ -32,6 +32,28 @@ Gtk.main
32
32
  ```
33
33
  This tutorial will mainly be focused on the use of Gtk::Application, which is the best way to create an application.
34
34
 
35
+ ## Table of Contents
36
+ * [Basics](#basics)
37
+ * [Packing](#packing)
38
+ * [Building user interfaces](#building-user-interfaces)
39
+ * [Building Applications](#building-applications)
40
+ * [A trivial application](#a trivial application)
41
+ * [Populating the window](#populating-the-window)
42
+ * [Link a template to a custom class widget](#link-a-template-to-a-custom-class-widget)
43
+ * [Load a resource file](#load-a-resource-file)
44
+ * [Opening files](#opening-file)
45
+ * [An application menu](#an-application-menu)
46
+ * [Adding the menu interface](#adding-the-menu-interface)
47
+ * [Linking menu items to actions](#linking-menu-items-to-actions)
48
+ * [Add accelerators for an action](#add-accelerators-for-an-action)
49
+ * [A preference dialog](#a-preference-dialog)
50
+ * [Define and store settings for an application with gschemas](#define-and-store-settings-for-an-application-with-gschemas)
51
+ * [Configure the settings with a dialog window](#configure-the-settings-with-a-dialog-window)
52
+ * [Adding a search bar](#adding-a-search-bar)
53
+ * [Adding a sidebar](#adding-a-sidebar)
54
+ * [Properties](#properties)
55
+ * [Header Bar](#header-bar)
56
+
35
57
  ## Basics
36
58
  https://developer.gnome.org/gtk3/stable/gtk-getting-started.html#id-1.2.3.5
37
59
 
@@ -54,7 +76,10 @@ puts app.run
54
76
 
55
77
  ```
56
78
  When creating a Gtk::Application you need to pick an application identifier (a name) and input to `Gtk::Application#new` as parameter. For this example *org.gtk.example* is used but for choosing an identifier for your application see this [guide](https://wiki.gnome.org/HowDoI/ChooseApplicationID).
57
- Lastly `Gtk::Application#new` takes a `Gio::ApplicationFlags` constants as input for your application, if your application would have special needs (those constants can be replaced by theirs respective symbol ie. `Gio::ApplicationFlags::NONE` == `:flags_none`).
79
+
80
+ Lastly `Gtk::Application#new` takes a `Gio::ApplicationFlags` constants as input for your application, if your application would have special needs (those constants can be replaced by theirs respective symbol ie. `Gio::ApplicationFlags::NONE` == `:flags_none`). You must know that `GApplication` ignores arguments passed to `g_application_run()` on the Windows systems. It always uses command line arguments even when we pass an empty array to g_application_run().
81
+
82
+ If you plan to create a cross-platform application, it is recommanded to use the `:handles_command_line` flags and the *command-line* signal. (reference : https://github.com/ruby-gnome2/ruby-gnome2/issues/721 ).
58
83
 
59
84
  Next we add instructions for the "activate" event of the `Gtk::Application` instance we created. The activate signal will be sent when your application is launched with the method `Gtk::Application#run` on the line below. This method also takes as arguments a ruby array of string. This allows GTK+ to parse specific command line arguments that control the behavior of GTK+ itself. The parsed arguments will be removed from the array, leaving the unrecognized ones for your application to parse.
60
85
 
@@ -516,7 +541,6 @@ stack.add_titled(scrolled, basename, basename)
516
541
 
517
542
  In this line, given that `self` is `ExampleAppWindow` the usage of `stack` is a call to the method we have created previously. So here we add a tab with a `Gtk::ScrolledWindow` in the `Gtk::Stack` widget of our template and we display the file content.
518
543
 
519
-
520
544
  ### An application menu
521
545
  https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.8
522
546
 
@@ -599,10 +623,10 @@ application.add_action(action)
599
623
  application.set_accels_for_action("app.quit", quit_accels)
600
624
  ```
601
625
 
602
- ### A preferences dialog
626
+ ### A preference dialog
603
627
  https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.9
604
628
 
605
- ### Define and store settings for an application with gschemas
629
+ #### Define and store settings for an application with gschemas
606
630
  * exampleapp5/exampleapp.rb
607
631
 
608
632
  A typical application will have a some preferences that should be remembered from one run to the next. Even for our simple example application, we may want to change the font that is used for the content.
@@ -824,7 +848,7 @@ def open(file)
824
848
  end
825
849
  ```
826
850
 
827
- ## Adding a search bar
851
+ ### Adding a search bar
828
852
  https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.10
829
853
 
830
854
  * exampleapp7/exampleapp.rb
@@ -934,5 +958,343 @@ In this part of code, the use of the method `set_connect_func` will allow us to
934
958
 
935
959
  <signal name="search-changed" handler="search_text_changed"/>
936
960
 
937
- Those pieces together mean that for the signal *search-changed* of the `Gtk::SearchEntry`, trigger the private method of `ExampleAppWindow` that is called `search_text_changed`.
961
+ Those pieces together mean that the signal *search-changed* of the `Gtk::SearchEntry`, trigger the private method of `ExampleAppWindow` that is called `search_text_changed`.
962
+
963
+ ### Adding a sidebar
964
+ https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.11
965
+
966
+ * exampleapp8/exampleapp.rb
967
+
968
+ As another piece of functionality, we are adding a sidebar, which demonstrates `Gtk::MenuButton`, `Gtk::Revealer` and Gtk::ListBox`.
969
+
970
+ window.ui :
971
+
972
+ ```xml
973
+ <?xml version="1.0" encoding="UTF-8"?>
974
+ <interface>
975
+ <!-- interface-requires gtk+ 3.8 -->
976
+ <template class="ExampleAppWindow" parent="GtkApplicationWindow">
977
+ <property name="title" translatable="yes">Example Application</property>
978
+ <property name="default-width">600</property>
979
+ <property name="default-height">400</property>
980
+ <child>
981
+ <object class="GtkBox" id="content_box">
982
+ <property name="visible">True</property>
983
+ <property name="orientation">vertical</property>
984
+ <child>
985
+ <object class="GtkHeaderBar" id="header">
986
+ <property name="visible">True</property>
987
+ <child type="title">
988
+ <object class="GtkStackSwitcher" id="tabs">
989
+ <property name="visible">True</property>
990
+ <property name="margin">6</property>
991
+ <property name="stack">stack</property>
992
+ </object>
993
+ </child>
994
+ <child>
995
+ <object class="GtkToggleButton" id="search">
996
+ <property name="visible">True</property>
997
+ <property name="sensitive">False</property>
998
+ <style>
999
+ <class name="image-button"/>
1000
+ </style>
1001
+ <child>
1002
+ <object class="GtkImage" id="search-icon">
1003
+ <property name="visible">True</property>
1004
+ <property name="icon-name">edit-find-symbolic</property>
1005
+ <property name="icon-size">1</property>
1006
+ </object>
1007
+ </child>
1008
+ </object>
1009
+ <packing>
1010
+ <property name="pack-type">end</property>
1011
+ </packing>
1012
+ </child>
1013
+ <child>
1014
+ <object class="GtkMenuButton" id="gears">
1015
+ <property name="visible">True</property>
1016
+ <property name="direction">none</property>
1017
+ <property name="use-popover">True</property>
1018
+ <style>
1019
+ <class name="image-button"/>
1020
+ </style>
1021
+ </object>
1022
+ <packing>
1023
+ <property name="pack-type">end</property>
1024
+ </packing>
1025
+ </child>
1026
+ </object>
1027
+ </child>
1028
+ <child>
1029
+ <object class="GtkSearchBar" id="searchbar">
1030
+ <property name="visible">True</property>
1031
+ <child>
1032
+ <object class="GtkSearchEntry" id="searchentry">
1033
+ <signal name="search-changed" handler="search_text_changed"/>
1034
+ <property name="visible">True</property>
1035
+ </object>
1036
+ </child>
1037
+ </object>
1038
+ </child>
1039
+ <child>
1040
+ <object class="GtkBox" id="hbox">
1041
+ <property name="visible">True</property>
1042
+ <child>
1043
+ <object class="GtkRevealer" id="sidebar">
1044
+ <property name="visible">True</property>
1045
+ <property name="transition-type">slide-right</property>
1046
+ <child>
1047
+ <object class="GtkScrolledWindow" id="sidebar-sw">
1048
+ <property name="visible">True</property>
1049
+ <property name="hscrollbar-policy">never</property>
1050
+ <property name="vscrollbar-policy">automatic</property>
1051
+ <child>
1052
+ <object class="GtkListBox" id="words">
1053
+ <property name="visible">True</property>
1054
+ <property name="selection-mode">none</property>
1055
+ </object>
1056
+ </child>
1057
+ </object>
1058
+ </child>
1059
+ </object>
1060
+ </child>
1061
+ <child>
1062
+ <object class="GtkStack" id="stack">
1063
+ <signal name="notify::visible-child" handler="visible_child_changed"/>
1064
+ <property name="visible">True</property>
1065
+ </object>
1066
+ </child>
1067
+ </object>
1068
+ </child>
1069
+ </object>
1070
+ </child>
1071
+ </template>
1072
+ </interface>
1073
+ ```
1074
+
1075
+ The code to populate the sidebar with buttons for the words found in each file is a little too involved to go into here. But we'll look at the code to add the gears menu.
1076
+ As expected by now, the gears menu is specified in a GtkBuilder ui file.
1077
+
1078
+ gears-menu.ui
1079
+
1080
+ ```xml
1081
+ <?xml version="1.0"?>
1082
+ <interface>
1083
+ <!-- interface-requires gtk+ 3.0 -->
1084
+ <menu id="menu">
1085
+ <section>
1086
+ <item>
1087
+ <attribute name="label" translatable="yes">_Words</attribute>
1088
+ <attribute name="action">win.show-words</attribute>
1089
+ </item>
1090
+ </section>
1091
+ </menu>
1092
+ </interface>
1093
+ ```
1094
+ To connect the menuitem to the show-words setting, we use a `Gio::SimpleAction` corresponding to the given `Gio::Settings` key.
1095
+
1096
+ ```ruby
1097
+ class ExampleAppWindow < Gtk::ApplicationWindow
1098
+ # some code
1099
+ def initialize(application)
1100
+ super(:application => application)
1101
+ @settings = Gio::Settings.new("org.gtk.exampleapp")
1102
+ @settings.bind("transition",
1103
+ stack,
1104
+ "transition-type",
1105
+ Gio::SettingsBindFlags::DEFAULT)
1106
+ search.bind_property("active", searchbar, "search-mode-enabled", :bidirectional)
1107
+ @settings.bind("show-words",
1108
+ sidebar,
1109
+ "reveal-child",
1110
+ Gio::SettingsBindFlags::DEFAULT)
1111
+ sidebar.signal_connect "notify::reveal-child" do |_sidebar, _gparamspec|
1112
+ update_words(self)
1113
+ end
1114
+ builder = Gtk::Builder.new(:resource => "/org/gtk/exampleapp/gears-menu.ui")
1115
+ menu = builder.get_object("menu")
1116
+ gears.set_menu_model(menu)
1117
+ action = @settings.create_action("show-words")
1118
+ add_action(action)
1119
+ end
1120
+
1121
+ # some code
1122
+ end
1123
+ ```
1124
+
1125
+ ### Properties
1126
+
1127
+ https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.12
1128
+
1129
+ Widgets and other objects have many useful properties.
1130
+
1131
+ Here we show some ways to use them in new and flexible ways, by wrapping them in actions with `Gio::PropertyAction` or by binding them with `Gio::Binding`.
1132
+ To set this up, we add two labels to the header bar in our window template, named *lines_label* and *lines*, and bind them to struct members in the private struct, as we've seen a couple of times by now.
1133
+ We add a new "Lines" menu item to the gears menu, which triggers the show-lines action:
1134
+
1135
+ ```xml
1136
+ <?xml version="1.0"?>
1137
+ <interface>
1138
+ <!-- interface-requires gtk+ 3.0 -->
1139
+ <menu id="menu">
1140
+ <section>
1141
+ <item>
1142
+ <attribute name="label" translatable="yes">_Words</attribute>
1143
+ <attribute name="action">win.show-words</attribute>
1144
+ </item>
1145
+ <item>
1146
+ <attribute name="label" translatable="yes">_Lines</attribute>
1147
+ <attribute name="action">win.show-lines</attribute>
1148
+ </item>
1149
+ </section>
1150
+ </menu>
1151
+ </interface>
1152
+ ```
1153
+
1154
+ To make this menu item do something, we create a property action for the visible property of the lines label, and add it to the actions of the window. The effect of this is that the visibility of the label gets toggled every time the action is activated.
1155
+ Since we want both labels to appear and disappear together, we bind the visible property of the lines_label widget to the same property of the lines widget.
1156
+
1157
+ * exampleapp9/exampleapp.rb
1158
+
1159
+ ```ruby
1160
+ # ...
1161
+ class ExampleAppWindow < Gtk::ApplicationWindow
1162
+ # ...
1163
+ def initialize(application)
1164
+ super(:application => application)
1165
+ # ...
1166
+ action = Gio::PropertyAction.new("show-lines", lines, "visible")
1167
+ add_action(action)
1168
+ lines.bind_property("visible", lines_label, "visible", :default)
1169
+ end
1170
+ ```
1171
+ We also need a function that counts the lines of the currently active tab, and updates the lines label. See the full source if you are interested in the details.
1172
+
1173
+ ### Header Bar
1174
+
1175
+ https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.13
1176
+
1177
+ Our application already uses a `Gtk::HeaderBar`, but so far it still gets a 'normal' window titlebar on top of that. This is a bit redundant, and we will now tell GTK+ to use the header bar as replacement for the titlebar. To do so, we move it around to be a direct child of the window, and set its type to be titlebar.
1178
+
1179
+ ```xml
1180
+ <?xml version="1.0" encoding="UTF-8"?>
1181
+ <interface>
1182
+ <!-- interface-requires gtk+ 3.8 -->
1183
+ <template class="ExampleAppWindow" parent="GtkApplicationWindow">
1184
+ <property name="title" translatable="yes">Example Application</property>
1185
+ <property name="default-width">600</property>
1186
+ <property name="default-height">400</property>
1187
+ <child type="titlebar">
1188
+ <object class="GtkHeaderBar" id="header">
1189
+ <property name="visible">True</property>
1190
+ <property name="show-close-button">True</property>
1191
+ <child>
1192
+ <object class="GtkLabel" id="lines_label">
1193
+ <property name="visible">False</property>
1194
+ <property name="label" translatable="yes">Lines:</property>
1195
+ </object>
1196
+ <packing>
1197
+ <property name="pack-type">start</property>
1198
+ </packing>
1199
+ </child>
1200
+ <child>
1201
+ <object class="GtkLabel" id="lines">
1202
+ <property name="visible">False</property>
1203
+ </object>
1204
+ <packing>
1205
+ <property name="pack-type">start</property>
1206
+ </packing>
1207
+ </child>
1208
+ <child type="title">
1209
+ <object class="GtkStackSwitcher" id="tabs">
1210
+ <property name="visible">True</property>
1211
+ <property name="margin">6</property>
1212
+ <property name="stack">stack</property>
1213
+ </object>
1214
+ </child>
1215
+ <child>
1216
+ <object class="GtkToggleButton" id="search">
1217
+ <property name="visible">True</property>
1218
+ <property name="sensitive">False</property>
1219
+ <style>
1220
+ <class name="image-button"/>
1221
+ </style>
1222
+ <child>
1223
+ <object class="GtkImage" id="search-icon">
1224
+ <property name="visible">True</property>
1225
+ <property name="icon-name">edit-find-symbolic</property>
1226
+ <property name="icon-size">1</property>
1227
+ </object>
1228
+ </child>
1229
+ </object>
1230
+ <packing>
1231
+ <property name="pack-type">end</property>
1232
+ </packing>
1233
+ </child>
1234
+ <child>
1235
+ <object class="GtkMenuButton" id="gears">
1236
+ <property name="visible">True</property>
1237
+ <property name="direction">none</property>
1238
+ <property name="use-popover">True</property>
1239
+ <style>
1240
+ <class name="image-button"/>
1241
+ </style>
1242
+ </object>
1243
+ <packing>
1244
+ <property name="pack-type">end</property>
1245
+ </packing>
1246
+ </child>
1247
+ </object>
1248
+ </child>
1249
+ <child>
1250
+ <object class="GtkBox" id="content_box">
1251
+ <property name="visible">True</property>
1252
+ <property name="orientation">vertical</property>
1253
+ <child>
1254
+ <object class="GtkSearchBar" id="searchbar">
1255
+ <property name="visible">True</property>
1256
+ <child>
1257
+ <object class="GtkSearchEntry" id="searchentry">
1258
+ <signal name="search-changed" handler="search_text_changed"/>
1259
+ <property name="visible">True</property>
1260
+ </object>
1261
+ </child>
1262
+ </object>
1263
+ </child>
1264
+ <child>
1265
+ <object class="GtkBox" id="hbox">
1266
+ <property name="visible">True</property>
1267
+ <child>
1268
+ <object class="GtkRevealer" id="sidebar">
1269
+ <property name="visible">True</property>
1270
+ <property name="transition-type">slide-right</property>
1271
+ <child>
1272
+ <object class="GtkScrolledWindow" id="sidebar-sw">
1273
+ <property name="visible">True</property>
1274
+ <property name="hscrollbar-policy">never</property>
1275
+ <property name="vscrollbar-policy">automatic</property>
1276
+ <child>
1277
+ <object class="GtkListBox" id="words">
1278
+ <property name="visible">True</property>
1279
+ <property name="selection-mode">none</property>
1280
+ </object>
1281
+ </child>
1282
+ </object>
1283
+ </child>
1284
+ </object>
1285
+ </child>
1286
+ <child>
1287
+ <object class="GtkStack" id="stack">
1288
+ <signal name="notify::visible-child" handler="visible_child_changed"/>
1289
+ <property name="visible">True</property>
1290
+ </object>
1291
+ </child>
1292
+ </object>
1293
+ </child>
1294
+ </object>
1295
+ </child>
1296
+ </template>
1297
+ </interface>
1298
+ ```
938
1299
 
1300
+ A small extra bonus of using a header bar is that we get a fallback application menu for free.