gtk4 4.0.3 → 4.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/gtk4/extconf.rb +10 -0
- data/ext/gtk4/rb-gtk4-cell-layout.c +41 -0
- data/ext/gtk4/rb-gtk4-private.h +2 -0
- data/ext/gtk4/rb-gtk4-tree-view.c +44 -0
- data/ext/gtk4/rb-gtk4.c +2 -0
- data/lib/gtk4/deprecated.rb +1 -1
- data/lib/gtk4/scrolled-window.rb +4 -2
- data/lib/gtk4/widget.rb +4 -0
- data/sample/examples/action-namespace.rb +1 -1
- data/sample/examples/builder.rb +21 -14
- data/sample/examples/builder.ui +15 -20
- data/sample/examples/drawing.rb +10 -16
- data/sample/examples/grid_packing.rb +1 -1
- data/sample/examples/hello_world.rb +11 -11
- data/sample/examples/window_default.rb +36 -0
- data/sample/getting-started/README.md +355 -2
- data/sample/getting-started/images/example-0.png +0 -0
- data/sample/getting-started/images/example-1.png +0 -0
- data/sample/getting-started/images/example-2.png +0 -0
- data/sample/getting-started/images/example-3.png +0 -0
- metadata +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd956d7d34f4285571a9afaf17f4b942f973de302868f8a6b854692467b4dc16
|
4
|
+
data.tar.gz: c171947ea6785c3b529f0b05f9251388c4edacbe3b1f8ff401252e5dc2cf5d63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ad4711c7b084a033c558d924029bdbd73190fd4fa805d6584d3d73429c89057689e7a9eaa9afa63bbc8466174c6718cf97a13c78ae696a85d52a25c84edb0c6
|
7
|
+
data.tar.gz: 151c10f1af8eed7f1144ce5a9a626872b51ca711055b90ff762df4d57135e0b4b0105c684f6951ebef3974197d12b8dbb706f310f068bf413ff096c617b9c338
|
data/ext/gtk4/extconf.rb
CHANGED
@@ -80,6 +80,16 @@ end
|
|
80
80
|
create_pkg_config_file("Ruby/GTK4", package_id)
|
81
81
|
|
82
82
|
$defs << "-DRUBY_GTK4_COMPILATION"
|
83
|
+
case RUBY_PLATFORM
|
84
|
+
when /darwin/
|
85
|
+
symbols_in_external_bundles = [
|
86
|
+
"_rbgobj_gc_mark_instance",
|
87
|
+
"_rbgobj_register_mark_func",
|
88
|
+
]
|
89
|
+
symbols_in_external_bundles.each do |symbol|
|
90
|
+
$DLDFLAGS << " -Wl,-U,#{symbol}"
|
91
|
+
end
|
92
|
+
end
|
83
93
|
create_makefile(module_name)
|
84
94
|
|
85
95
|
pkg_config_dir = with_config("pkg-config-dir")
|
@@ -0,0 +1,41 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright (C) 2015-2022 Ruby-GNOME Project Team
|
4
|
+
*
|
5
|
+
* This library is free software; you can redistribute it and/or
|
6
|
+
* modify it under the terms of the GNU Lesser General Public
|
7
|
+
* License as published by the Free Software Foundation; either
|
8
|
+
* version 2.1 of the License, or (at your option) any later version.
|
9
|
+
*
|
10
|
+
* This library is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
* Lesser General Public License for more details.
|
14
|
+
*
|
15
|
+
* You should have received a copy of the GNU Lesser General Public
|
16
|
+
* License along with this library; if not, write to the Free Software
|
17
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
18
|
+
* MA 02110-1301 USA
|
19
|
+
*/
|
20
|
+
|
21
|
+
#include "rb-gtk4-private.h"
|
22
|
+
|
23
|
+
static void
|
24
|
+
rb_gtk4_cell_layout_mark(gpointer object)
|
25
|
+
{
|
26
|
+
GtkCellLayout *cell_layout = object;
|
27
|
+
|
28
|
+
GList *renderers = gtk_cell_layout_get_cells(cell_layout);
|
29
|
+
GList *node;
|
30
|
+
for (node = renderers; node; node = g_list_next(node)) {
|
31
|
+
GtkCellRenderer *renderer = node->data;
|
32
|
+
rbgobj_gc_mark_instance(renderer);
|
33
|
+
}
|
34
|
+
g_list_free(renderers);
|
35
|
+
}
|
36
|
+
|
37
|
+
void
|
38
|
+
rb_gtk4_cell_layout_init(void)
|
39
|
+
{
|
40
|
+
rbgobj_register_mark_func(GTK_TYPE_CELL_LAYOUT, rb_gtk4_cell_layout_mark);
|
41
|
+
}
|
data/ext/gtk4/rb-gtk4-private.h
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright (C) 2015-2022 Ruby-GNOME Project Team
|
4
|
+
*
|
5
|
+
* This library is free software; you can redistribute it and/or
|
6
|
+
* modify it under the terms of the GNU Lesser General Public
|
7
|
+
* License as published by the Free Software Foundation; either
|
8
|
+
* version 2.1 of the License, or (at your option) any later version.
|
9
|
+
*
|
10
|
+
* This library is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
* Lesser General Public License for more details.
|
14
|
+
*
|
15
|
+
* You should have received a copy of the GNU Lesser General Public
|
16
|
+
* License along with this library; if not, write to the Free Software
|
17
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
18
|
+
* MA 02110-1301 USA
|
19
|
+
*/
|
20
|
+
|
21
|
+
#include "rb-gtk4-private.h"
|
22
|
+
|
23
|
+
static void
|
24
|
+
rb_gtk4_tree_view_mark(gpointer object)
|
25
|
+
{
|
26
|
+
GtkTreeView *tree_view = object;
|
27
|
+
|
28
|
+
GList *columns = gtk_tree_view_get_columns(tree_view);
|
29
|
+
GList *node;
|
30
|
+
for (node = columns; node; node = g_list_next(node)) {
|
31
|
+
GtkTreeViewColumn *column = node->data;
|
32
|
+
rbgobj_gc_mark_instance(column);
|
33
|
+
}
|
34
|
+
g_list_free(columns);
|
35
|
+
|
36
|
+
GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
|
37
|
+
rbgobj_gc_mark_instance(selection);
|
38
|
+
}
|
39
|
+
|
40
|
+
void
|
41
|
+
rb_gtk4_tree_view_init(void)
|
42
|
+
{
|
43
|
+
rbgobj_register_mark_func(GTK_TYPE_TREE_VIEW, rb_gtk4_tree_view_mark);
|
44
|
+
}
|
data/ext/gtk4/rb-gtk4.c
CHANGED
data/lib/gtk4/deprecated.rb
CHANGED
data/lib/gtk4/scrolled-window.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2014 Ruby-
|
1
|
+
# Copyright (C) 2014-2022 Ruby-GNOME Project Team
|
2
2
|
#
|
3
3
|
# This library is free software; you can redistribute it and/or
|
4
4
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -18,7 +18,9 @@ module Gtk
|
|
18
18
|
class ScrolledWindow
|
19
19
|
alias_method :initialize_raw, :initialize
|
20
20
|
def initialize(hadjustment=nil, vadjustment=nil)
|
21
|
-
initialize_raw
|
21
|
+
initialize_raw
|
22
|
+
set_hadjustment(hadjustment) if hadjustment
|
23
|
+
set_vadjustment(vadjustment) if vadjustment
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/gtk4/widget.rb
CHANGED
data/sample/examples/builder.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013-
|
3
|
+
# Copyright (C) 2013-2022 Ruby-GNOME Project Team
|
4
4
|
#
|
5
5
|
# This library is free software; you can redistribute it and/or
|
6
6
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -16,26 +16,33 @@
|
|
16
16
|
# License along with this library; if not, write to the Free Software
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
|
19
|
-
# example from https://
|
19
|
+
# example from https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/builder.c
|
20
20
|
|
21
21
|
require_relative "utils"
|
22
22
|
|
23
23
|
require_gtk4
|
24
24
|
|
25
|
-
|
26
|
-
builder = Gtk::Builder.new(:file => "#{path}/builder.ui")
|
25
|
+
app = Gtk::Application.new("org.gtk.example", :flags_none)
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
app.signal_connect "activate" do
|
28
|
+
# Construct a GtkBuilder instance and load our UI description
|
29
|
+
builder = Gtk::Builder.new(file: File.join(__dir__, "builder.ui"))
|
31
30
|
|
32
|
-
|
33
|
-
|
31
|
+
# Connect signal handlers to the constructed widgets.
|
32
|
+
window = builder["window"]
|
33
|
+
window.set_application(app)
|
34
34
|
|
35
|
-
button = builder["
|
36
|
-
button.signal_connect("clicked") { puts "Hello World!" }
|
35
|
+
button = builder["button1"]
|
36
|
+
button.signal_connect("clicked") { puts "Hello World!" }
|
37
37
|
|
38
|
-
button = builder["
|
39
|
-
button.signal_connect("clicked") {
|
38
|
+
button = builder["button2"]
|
39
|
+
button.signal_connect("clicked") { puts "Hello World!" }
|
40
|
+
|
41
|
+
button = builder["quit"]
|
42
|
+
button.signal_connect("clicked") { window.close }
|
43
|
+
|
44
|
+
window.show
|
45
|
+
end
|
46
|
+
|
47
|
+
app.run
|
40
48
|
|
41
|
-
Gtk.main
|
data/sample/examples/builder.ui
CHANGED
@@ -1,44 +1,39 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
1
2
|
<interface>
|
2
3
|
<object id="window" class="GtkWindow">
|
3
|
-
<property name="visible">True</property>
|
4
4
|
<property name="title">Grid</property>
|
5
5
|
<child>
|
6
6
|
<object id="grid" class="GtkGrid">
|
7
|
-
<property name="visible">True</property>
|
8
7
|
<child>
|
9
8
|
<object id="button1" class="GtkButton">
|
10
|
-
<property name="visible">True</property>
|
11
9
|
<property name="label">Button 1</property>
|
10
|
+
<layout>
|
11
|
+
<property name="column">0</property>
|
12
|
+
<property name="row">0</property>
|
13
|
+
</layout>
|
12
14
|
</object>
|
13
|
-
<packing>
|
14
|
-
<property name="left-attach">0</property>
|
15
|
-
<property name="top-attach">0</property>
|
16
|
-
</packing>
|
17
15
|
</child>
|
18
16
|
<child>
|
19
17
|
<object id="button2" class="GtkButton">
|
20
|
-
<property name="visible">True</property>
|
21
18
|
<property name="label">Button 2</property>
|
19
|
+
<layout>
|
20
|
+
<property name="column">1</property>
|
21
|
+
<property name="row">0</property>
|
22
|
+
</layout>
|
22
23
|
</object>
|
23
|
-
<packing>
|
24
|
-
<property name="left-attach">1</property>
|
25
|
-
<property name="top-attach">0</property>
|
26
|
-
</packing>
|
27
24
|
</child>
|
28
25
|
<child>
|
29
26
|
<object id="quit" class="GtkButton">
|
30
|
-
<property name="visible">True</property>
|
31
27
|
<property name="label">Quit</property>
|
28
|
+
<layout>
|
29
|
+
<property name="column">0</property>
|
30
|
+
<property name="row">1</property>
|
31
|
+
<property name="column-span">2</property>
|
32
|
+
</layout>
|
32
33
|
</object>
|
33
|
-
<packing>
|
34
|
-
<property name="left-attach">0</property>
|
35
|
-
<property name="top-attach">1</property>
|
36
|
-
<property name="width">2</property>
|
37
|
-
</packing>
|
38
34
|
</child>
|
39
35
|
</object>
|
40
|
-
<packing>
|
41
|
-
</packing>
|
42
36
|
</child>
|
43
37
|
</object>
|
44
38
|
</interface>
|
39
|
+
|
data/sample/examples/drawing.rb
CHANGED
@@ -34,17 +34,13 @@ def draw_brush(widget, surface, x, y)
|
|
34
34
|
cr = Cairo::Context.new(surface)
|
35
35
|
cr.rectangle(x - 3, y - 3, 6, 6)
|
36
36
|
cr.fill
|
37
|
-
widget.
|
37
|
+
widget.queue_draw
|
38
38
|
end
|
39
39
|
|
40
40
|
def generate_surface_from_widget(widget)
|
41
|
-
surface
|
42
|
-
|
43
|
-
|
44
|
-
widget.allocated_width,
|
45
|
-
widget.allocated_height)
|
46
|
-
end
|
47
|
-
surface
|
41
|
+
widget.native.surface.create_similar_surface(Cairo::CONTENT_COLOR,
|
42
|
+
widget.allocated_width,
|
43
|
+
widget.allocated_height)
|
48
44
|
end
|
49
45
|
|
50
46
|
myapp = Gtk::Application.new("org.gtk.example", :flags_none)
|
@@ -60,14 +56,10 @@ myapp.signal_connect "activate" do |app|
|
|
60
56
|
win.destroy
|
61
57
|
end
|
62
58
|
|
63
|
-
frame = Gtk::Frame.new
|
64
|
-
frame.shadow_type = Gtk::ShadowType::IN
|
65
|
-
win.add(frame)
|
66
|
-
|
67
59
|
drawing_area = Gtk::DrawingArea.new
|
68
60
|
# Set a minimum size
|
69
61
|
drawing_area.set_size_request(100, 100)
|
70
|
-
|
62
|
+
win.set_child(drawing_area)
|
71
63
|
|
72
64
|
drawing_area.set_draw_func do |da, cr|
|
73
65
|
if surface.nil?
|
@@ -82,15 +74,16 @@ myapp.signal_connect "activate" do |app|
|
|
82
74
|
cr.paint
|
83
75
|
end
|
84
76
|
|
85
|
-
drawing_area.signal_connect_after "
|
77
|
+
drawing_area.signal_connect_after "resize" do |da, alloc|
|
86
78
|
surface.destroy if surface
|
87
79
|
surface = generate_surface_from_widget(da)
|
88
80
|
# Initialize the surface to white
|
89
81
|
clear_surface(surface) if surface
|
90
82
|
end
|
91
83
|
|
92
|
-
drag = Gtk::GestureDrag.new
|
84
|
+
drag = Gtk::GestureDrag.new
|
93
85
|
drag.button = Gdk::BUTTON_PRIMARY
|
86
|
+
drawing_area.add_controller(drag)
|
94
87
|
|
95
88
|
start_x = 0.0
|
96
89
|
start_y = 0.0
|
@@ -109,8 +102,9 @@ myapp.signal_connect "activate" do |app|
|
|
109
102
|
draw_brush(drawing_area, surface, start_x + x, start_y + y)
|
110
103
|
end
|
111
104
|
|
112
|
-
press = Gtk::
|
105
|
+
press = Gtk::GestureClick.new
|
113
106
|
press.button = Gdk::BUTTON_SECONDARY
|
107
|
+
drawing_area.add_controller(press)
|
114
108
|
press.signal_connect "pressed" do |gesture, n_press, x, y|
|
115
109
|
clear_surface(surface)
|
116
110
|
drawing_area.queue_draw
|
@@ -33,7 +33,7 @@ application.signal_connect "activate" do |app|
|
|
33
33
|
grid = Gtk::Grid.new
|
34
34
|
|
35
35
|
# Pack the container in the window
|
36
|
-
win.
|
36
|
+
win.set_child(grid)
|
37
37
|
|
38
38
|
button = Gtk::Button.new(:label => "Button 1")
|
39
39
|
button.signal_connect("clicked") { puts "Hello World!" }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013-
|
3
|
+
# Copyright (C) 2013-2022 Ruby-GNOME Project Team
|
4
4
|
#
|
5
5
|
# This library is free software; you can redistribute it and/or
|
6
6
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# License along with this library; if not, write to the Free Software
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
|
19
|
-
# example from https://
|
19
|
+
# example from https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/hello/hello-world.c
|
20
20
|
|
21
21
|
require_relative "utils"
|
22
22
|
|
@@ -25,22 +25,22 @@ require_gtk4
|
|
25
25
|
application = Gtk::Application.new("org.gtk.example", :flags_none)
|
26
26
|
|
27
27
|
application.signal_connect "activate" do |app|
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
window = Gtk::ApplicationWindow.new(app)
|
29
|
+
window.title = "Window"
|
30
|
+
window.set_default_size(200, 200)
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
button = Gtk::Button.new(label: "Hello World")
|
33
|
+
button.halign = :center
|
34
|
+
button.valign = :center
|
34
35
|
|
35
|
-
button = Gtk::Button.new(:label => "Hello World")
|
36
36
|
button.signal_connect "clicked" do
|
37
37
|
puts "Hello World"
|
38
|
-
|
38
|
+
window.destroy
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
window.child = button
|
42
42
|
|
43
|
-
|
43
|
+
window.show
|
44
44
|
end
|
45
45
|
|
46
46
|
application.run
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (C) 2022 Ruby-GNOME Project Team
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
# example from https://gitlab.gnome.org/GNOME/gtk/blob/main/examples/window-default.c
|
20
|
+
#
|
21
|
+
# License: LGPL2.1+
|
22
|
+
|
23
|
+
require_relative "utils"
|
24
|
+
|
25
|
+
require_gtk4
|
26
|
+
|
27
|
+
application = Gtk::Application.new("org.gtk.example", :flags_none)
|
28
|
+
|
29
|
+
application.signal_connect "activate" do |app|
|
30
|
+
window = Gtk::ApplicationWindow.new(app)
|
31
|
+
window.title = "Window"
|
32
|
+
window.set_default_size(200, 200)
|
33
|
+
window.show
|
34
|
+
end
|
35
|
+
|
36
|
+
application.run
|
@@ -1,4 +1,357 @@
|
|
1
1
|
# Ruby/GTK4 getting started
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
This is a ruby adaptation of the [official tutorial](https://docs.gtk.org/gtk4/getting_started.html) for the C language.
|
4
|
+
|
5
|
+
The Gtk4 module of the ruby-gnome project is an implementation of the ruby bindings for GTK.
|
6
|
+
|
7
|
+
GTK is a [widget toolkit](http://en.wikipedia.org/wiki/Widget_toolkit). Each user interface created by GTK consists of widgets. Widgets are organized in a hierarchy. The window widget is the main container. The user interface is then built by adding buttons, drop-down menus, input fields, and other widgets to the window. If you are creating complex user interfaces it is recommended to use `Gtk::Builder` and its GTK-specific markup description language, instead of assembling the interface manually.
|
8
|
+
|
9
|
+
GTK is event-driven. The toolkit listens for events such as a click on a button, and passes the event to your application.
|
10
|
+
|
11
|
+
This chapter contains some tutorial information to get you started with GTK programming. It assumes that you have GTK, its dependencies and ruby with the gtk4 gem installed.
|
12
|
+
|
13
|
+
## Basics
|
14
|
+
To begin our introduction to GTK, we’ll start with a very simple application. This program will create an empty 200 × 200 pixel window.
|
15
|
+
|
16
|
+
![example-0](images/example-0.png)
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# example-0.rb
|
20
|
+
require "gtk4"
|
21
|
+
|
22
|
+
application = Gtk::Application.new("org.gtk.example", :flags_none)
|
23
|
+
|
24
|
+
application.signal_connect "activate" do |app|
|
25
|
+
window = Gtk::ApplicationWindow.new(app)
|
26
|
+
window.title = "Window"
|
27
|
+
window.set_default_size(200, 200)
|
28
|
+
window.show
|
29
|
+
end
|
30
|
+
|
31
|
+
application.run
|
32
|
+
```
|
33
|
+
|
34
|
+
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).
|
35
|
+
|
36
|
+
Lastly `Gtk::Application#new` takes a `Gio::ApplicationFlags` constant as input for your application, if your application would have special needs (those constants can be replaced by theirs respective symbol ie. `Gio::ApplicationFlags::FLAGS_NONE` == `:flags_none`). You must know that `Gio:::Application` ignores arguments passed to `Gio::Application#run` on the Windows systems. It always uses command line arguments even when we pass an empty array to `Gio::Application#run`.
|
37
|
+
|
38
|
+
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-gnome/ruby-gnome/issues/721 ).
|
39
|
+
|
40
|
+
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. Your application can override the command line handling, e.g. to open files passed on the commandline.
|
41
|
+
|
42
|
+
A window title is set using `Gtk::ApplicationWindow#title=`. This setter function takes a string as input.
|
43
|
+
|
44
|
+
Finally the window size is set using `Gtk::ApplicationWindow#set_default_size` and the window is then shown by GTK via `Gtk::Widget#show`.
|
45
|
+
|
46
|
+
While the program is running, GTK is receiving *events*. These are typically input events caused by the user interacting with your program, but also things like messages from the window manager or other applications. GTK processes these and as a result, signals may be emitted on your widgets. Connecting handlers for these signals is how you normally make your program do something in response to user input.
|
47
|
+
|
48
|
+
The following example is slightly more complex, and tries to showcase some of the capabilities of GTK.
|
49
|
+
|
50
|
+
## Hello, World
|
51
|
+
|
52
|
+
In the long tradition of programming languages and libraries, this example is called *Hello, World*.
|
53
|
+
|
54
|
+
![example-1](images/example-1.png)
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# example-1.rb
|
58
|
+
application = Gtk::Application.new("org.gtk.example", :flags_none)
|
59
|
+
|
60
|
+
application.signal_connect "activate" do |app|
|
61
|
+
window = Gtk::ApplicationWindow.new(app)
|
62
|
+
window.title = "Window"
|
63
|
+
window.set_default_size(200, 200)
|
64
|
+
|
65
|
+
button_box = Gtk::Box.new(:horizontal)
|
66
|
+
button_box.halign = :center
|
67
|
+
button_box.valign = :center
|
68
|
+
window.set_child(button_box)
|
69
|
+
|
70
|
+
button = Gtk::Button.new(label: "Hello World")
|
71
|
+
|
72
|
+
button.signal_connect "clicked" do
|
73
|
+
puts "Hello World"
|
74
|
+
window.destroy
|
75
|
+
end
|
76
|
+
button_box.append(button)
|
77
|
+
|
78
|
+
window.show
|
79
|
+
end
|
80
|
+
|
81
|
+
application.run
|
82
|
+
```
|
83
|
+
|
84
|
+
As seen above, example-1.rb builds further upon example-0.rb by adding a button to our window, with the label “Hello World”.
|
85
|
+
|
86
|
+
The button_box variable stores a `Gtk::Box` object, which is GTK's way of controlling the size and layout of widgets. The `Gtk::Box` is created with the method `Gtk::Box#new` which takes a `Gtk::Orientation `constant as parameter or the related symbols (`:vertical` or `:horizontal`).
|
87
|
+
|
88
|
+
The buttons which this box will contain can either be stored horizontally or vertically but this does not matter in this particular case as we are dealing with only one button. After initializing button_box with horizontal orientation, the code adds the button_box widget to the window widget using `Gtk::Box#append`.
|
89
|
+
|
90
|
+
Next the button variable is initialized in similar manner. The method `Gtk::Button#new` is called which returns a `Gtk::Button` to be stored in button. A label is set using a ruby hash as argument: `label: "Hello World"`. Afterwards button is added to our button_box.
|
91
|
+
|
92
|
+
Using the method `Gtk::Button#signal_connect` we add instructions, so that when the button is clicked, a message will be displayed in the terminal if the GTK application was started from one.
|
93
|
+
|
94
|
+
After that, `Gtk::ApplicationWindow#destroy` is called. This method is inherited from `Gtk::Widget`. This has the effect that when the button is clicked, the whole GTK window is destroyed. More information about creating buttons can be found [here](https://wiki.gnome.org/HowDoI/Buttons).
|
95
|
+
|
96
|
+
The rest of the code in example-1.rb is identical to example-0.rb. Next section will elaborate further on how to add several GtkWidgets to your GTK application.
|
97
|
+
|
98
|
+
## Packing
|
99
|
+
|
100
|
+
When creating an application, you’ll want to put more than one widget inside a window. When you do so, it becomes important to control how each widget is positioned and sized. This is where packing comes in.
|
101
|
+
|
102
|
+
GTK comes with a large variety of layout containers whose purpose it is to control the layout of the child widgets that are added to them, like:
|
103
|
+
|
104
|
+
* [Gtk::Box](https://docs.gtk.org/gtk4/class.Box.html)
|
105
|
+
* [Gtk::Grid](https://docs.gtk.org/gtk4/class.Grid.html)
|
106
|
+
* [Gtk::Revealer](https://docs.gtk.org/gtk4/class.Revealer.html)
|
107
|
+
* [Gtk::Stack](https://docs.gtk.org/gtk4/class.Stack.html)
|
108
|
+
* [Gtk::Overlay](https://docs.gtk.org/gtk4/class.Overlay.html)
|
109
|
+
* [Gtk::Paned](https://docs.gtk.org/gtk4/class.Paned.html)
|
110
|
+
* [Gtk::Expander](https://docs.gtk.org/gtk4/class.Expander.html)
|
111
|
+
* [Gtk::Fixed](https://docs.gtk.org/gtk4/class.Fixed.html)
|
112
|
+
|
113
|
+
The following example shows how the `Gtk::Grid` container lets you arrange several buttons:
|
114
|
+
|
115
|
+
![example-2](images/example-2.png)
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
# example-2.rb
|
119
|
+
require "gtk4"
|
120
|
+
|
121
|
+
application = Gtk::Application.new("org.gtk.example", :flags_none)
|
122
|
+
|
123
|
+
application.signal_connect "activate" do |app|
|
124
|
+
# Create a new window and set its title
|
125
|
+
win = Gtk::ApplicationWindow.new(app)
|
126
|
+
win.title = "Window"
|
127
|
+
|
128
|
+
# Here we construct the container that is going to pack our buttons.
|
129
|
+
grid = Gtk::Grid.new
|
130
|
+
|
131
|
+
# Pack the container in the window
|
132
|
+
win.set_child(grid)
|
133
|
+
|
134
|
+
button = Gtk::Button.new(label: "Button 1")
|
135
|
+
button.signal_connect("clicked") { puts "Hello World!" }
|
136
|
+
|
137
|
+
# Place the first button in the grid cell (0, 0), and make it fill
|
138
|
+
# just 1 cell horizontally and vertically (ie no spanning)
|
139
|
+
grid.attach(button, 0, 0, 1, 1)
|
140
|
+
|
141
|
+
button = Gtk::Button.new(label: "Button 2")
|
142
|
+
button.signal_connect("clicked") { puts "Hello World!" }
|
143
|
+
|
144
|
+
# Place the second button in the grid cell (1, 0), and make it fill
|
145
|
+
# just 1 cell horizontally and vertically (ie no spanning)
|
146
|
+
grid.attach(button, 1, 0, 1, 1)
|
147
|
+
|
148
|
+
button = Gtk::Button.new(label: "Quit")
|
149
|
+
button.signal_connect("clicked") { win.destroy }
|
150
|
+
|
151
|
+
# Place the Quit button in the grid cell (0, 1), and make it
|
152
|
+
# span 2 columns.
|
153
|
+
grid.attach(button, 0, 1, 2, 1)
|
154
|
+
|
155
|
+
win.show
|
156
|
+
end
|
157
|
+
|
158
|
+
application.run
|
159
|
+
```
|
160
|
+
|
161
|
+
## Custom Drawing
|
162
|
+
|
163
|
+
Many widgets, like buttons, do all their drawing themselves. You just tell them the label you want to see, and they figure out what font to use, draw the button outline and focus rectangle, etc. Sometimes, it is necessary to do some custom drawing. In that case, a `Gtk::DrawingArea` might be the right widget to use. It offers a canvas on which you can draw by setting its draw function.
|
164
|
+
|
165
|
+
The contents of a widget often need to be partially or fully redrawn, e.g. when another window is moved and uncovers part of the widget, or when the window containing it is resized. It is also possible to explicitly cause a widget to be redrawn, by calling `Gtk::Widget#queue_draw`. GTK takes care of most of the details by providing a ready-to-use cairo context to the draw function.
|
166
|
+
|
167
|
+
The following example shows how to use a draw function with `Gtk::DrawingArea`. It is a bit more complicated than the previous examples, since it also demonstrates input event handling with event controllers.
|
168
|
+
|
169
|
+
![example-3](images/example-3.png)
|
170
|
+
|
171
|
+
### Drawing in response to input
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
# example-3.rb
|
175
|
+
require "gtk4"
|
176
|
+
|
177
|
+
def clear_surface(surface)
|
178
|
+
cr = Cairo::Context.new(surface)
|
179
|
+
cr.set_source_rgb(1, 1, 1)
|
180
|
+
cr.paint
|
181
|
+
cr.destroy
|
182
|
+
end
|
183
|
+
|
184
|
+
# Draw a rectangle on the surface at the given position
|
185
|
+
def draw_brush(widget, surface, x, y)
|
186
|
+
cr = Cairo::Context.new(surface)
|
187
|
+
cr.rectangle(x - 3, y - 3, 6, 6)
|
188
|
+
cr.fill
|
189
|
+
widget.queue_draw
|
190
|
+
end
|
191
|
+
|
192
|
+
def generate_surface_from_widget(widget)
|
193
|
+
widget.native.surface.create_similar_surface(Cairo::CONTENT_COLOR,
|
194
|
+
widget.allocated_width,
|
195
|
+
widget.allocated_height)
|
196
|
+
end
|
197
|
+
|
198
|
+
myapp = Gtk::Application.new("org.gtk.example", :flags_none)
|
199
|
+
|
200
|
+
myapp.signal_connect "activate" do |app|
|
201
|
+
win = Gtk::ApplicationWindow.new(app)
|
202
|
+
win.set_title("Drawing Area")
|
203
|
+
|
204
|
+
surface = nil
|
205
|
+
|
206
|
+
win.signal_connect "destroy" do
|
207
|
+
surface.destroy if surface
|
208
|
+
win.destroy
|
209
|
+
end
|
210
|
+
|
211
|
+
drawing_area = Gtk::DrawingArea.new
|
212
|
+
# Set a minimum size
|
213
|
+
drawing_area.set_size_request(100, 100)
|
214
|
+
win.set_child(drawing_area)
|
215
|
+
|
216
|
+
drawing_area.set_draw_func do |da, cr|
|
217
|
+
if surface.nil?
|
218
|
+
surface = generate_surface_from_widget(da)
|
219
|
+
## Initialize the surface to white
|
220
|
+
clear_surface(surface)
|
221
|
+
end
|
222
|
+
# Redraw the screen from the surface. Note that the draw
|
223
|
+
# callback receives a ready-to-be-used cairo_t that is already
|
224
|
+
# clipped to only draw the exposed areas of the widget
|
225
|
+
cr.set_source(surface, 0, 0)
|
226
|
+
cr.paint
|
227
|
+
end
|
228
|
+
|
229
|
+
drawing_area.signal_connect_after "resize" do |da, alloc|
|
230
|
+
surface.destroy if surface
|
231
|
+
surface = generate_surface_from_widget(da)
|
232
|
+
# Initialize the surface to white
|
233
|
+
clear_surface(surface) if surface
|
234
|
+
end
|
235
|
+
|
236
|
+
drag = Gtk::GestureDrag.new
|
237
|
+
drag.button = Gdk::BUTTON_PRIMARY
|
238
|
+
drawing_area.add_controller(drag)
|
239
|
+
|
240
|
+
start_x = 0.0
|
241
|
+
start_y = 0.0
|
242
|
+
|
243
|
+
drag.signal_connect "drag-begin" do |gesture, x, y|
|
244
|
+
start_x = x
|
245
|
+
start_y = y
|
246
|
+
draw_brush(drawing_area, surface, x, y)
|
247
|
+
end
|
248
|
+
|
249
|
+
drag.signal_connect "drag-update" do |gesture, x, y|
|
250
|
+
draw_brush(drawing_area, surface, start_x + x, start_y + y)
|
251
|
+
end
|
252
|
+
|
253
|
+
drag.signal_connect "drag-end" do |gesture, x, y|
|
254
|
+
draw_brush(drawing_area, surface, start_x + x, start_y + y)
|
255
|
+
end
|
256
|
+
|
257
|
+
press = Gtk::GestureClick.new
|
258
|
+
press.button = Gdk::BUTTON_SECONDARY
|
259
|
+
drawing_area.add_controller(press)
|
260
|
+
press.signal_connect "pressed" do |gesture, n_press, x, y|
|
261
|
+
clear_surface(surface)
|
262
|
+
drawing_area.queue_draw
|
263
|
+
end
|
264
|
+
win.show
|
265
|
+
end
|
266
|
+
|
267
|
+
myapp.run
|
268
|
+
```
|
269
|
+
|
270
|
+
## Building user interfaces
|
271
|
+
When constructing a more complicated user interface, with dozens or hundreds of widgets, doing all the setup work in code is cumbersome, and making changes becomes next to impossible.
|
272
|
+
|
273
|
+
Thankfully, GTK supports the separation of user interface layout from your business logic, by using UI descriptions in an XML format that can be parsed by the `Gtk::Builder` class.
|
274
|
+
|
275
|
+
### Packing buttons with GtkBuilder
|
276
|
+
|
277
|
+
Create a new file with the following content:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
# example-4.rb
|
281
|
+
require "gtk4"
|
282
|
+
|
283
|
+
app = Gtk::Application.new("org.gtk.example", :flags_none)
|
284
|
+
|
285
|
+
app.signal_connect "activate" do
|
286
|
+
# Construct a GtkBuilder instance and load our UI description
|
287
|
+
builder = Gtk::Builder.new(file: File.join(__dir__, "builder.ui"))
|
288
|
+
|
289
|
+
# Connect signal handlers to the constructed widgets.
|
290
|
+
window = builder["window"]
|
291
|
+
window.set_application(app)
|
292
|
+
|
293
|
+
button = builder["button1"]
|
294
|
+
button.signal_connect("clicked") { puts "Hello World!" }
|
295
|
+
|
296
|
+
button = builder["button2"]
|
297
|
+
button.signal_connect("clicked") { puts "Hello World!" }
|
298
|
+
|
299
|
+
button = builder["quit"]
|
300
|
+
button.signal_connect("clicked") { window.close }
|
301
|
+
|
302
|
+
window.show
|
303
|
+
end
|
304
|
+
|
305
|
+
app.run
|
306
|
+
```
|
307
|
+
|
308
|
+
Then, create a new file with the following content named `builder.ui`.
|
309
|
+
|
310
|
+
```xml
|
311
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
312
|
+
<interface>
|
313
|
+
<object id="window" class="GtkWindow">
|
314
|
+
<property name="title">Grid</property>
|
315
|
+
<child>
|
316
|
+
<object id="grid" class="GtkGrid">
|
317
|
+
<child>
|
318
|
+
<object id="button1" class="GtkButton">
|
319
|
+
<property name="label">Button 1</property>
|
320
|
+
<layout>
|
321
|
+
<property name="column">0</property>
|
322
|
+
<property name="row">0</property>
|
323
|
+
</layout>
|
324
|
+
</object>
|
325
|
+
</child>
|
326
|
+
<child>
|
327
|
+
<object id="button2" class="GtkButton">
|
328
|
+
<property name="label">Button 2</property>
|
329
|
+
<layout>
|
330
|
+
<property name="column">1</property>
|
331
|
+
<property name="row">0</property>
|
332
|
+
</layout>
|
333
|
+
</object>
|
334
|
+
</child>
|
335
|
+
<child>
|
336
|
+
<object id="quit" class="GtkButton">
|
337
|
+
<property name="label">Quit</property>
|
338
|
+
<layout>
|
339
|
+
<property name="column">0</property>
|
340
|
+
<property name="row">1</property>
|
341
|
+
<property name="column-span">2</property>
|
342
|
+
</layout>
|
343
|
+
</object>
|
344
|
+
</child>
|
345
|
+
</object>
|
346
|
+
</child>
|
347
|
+
</object>
|
348
|
+
</interface>
|
349
|
+
```
|
350
|
+
|
351
|
+
The usage of the `Gtk::Builder` is easy, we just create an instance from the
|
352
|
+
file "builder.ui" with `Gtk::Builder.new(file: path/to/builder.ui)`. Then you can access every widget or part of the interface thanks to its name: `window = builder["window"]`. Note that `Gtk::Builder` can also be used to construct objects that are not widgets, such as tree models, adjustments, etc.
|
353
|
+
|
354
|
+
It is also possible to embed the UI description in the source code as a string and use `GtkBuilder::add_from_string` to load it. But keeping the UI description in a separate file has several advantages:
|
355
|
+
|
356
|
+
* it is easier to isolate the UI code from the business logic of your application
|
357
|
+
* it is easier to restructure your UI into separate classes using composite widget templates
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gtk4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The Ruby-GNOME Project Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: atk
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 4.0.
|
19
|
+
version: 4.0.5
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 4.0.
|
26
|
+
version: 4.0.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: gdk4
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 4.0.
|
33
|
+
version: 4.0.5
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 4.0.
|
40
|
+
version: 4.0.5
|
41
41
|
description: Ruby/GTK4 is a Ruby binding of GTK+-4.x.
|
42
42
|
email: ruby-gnome2-devel-en@lists.sourceforge.net
|
43
43
|
executables: []
|
@@ -49,7 +49,9 @@ files:
|
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
51
|
- ext/gtk4/extconf.rb
|
52
|
+
- ext/gtk4/rb-gtk4-cell-layout.c
|
52
53
|
- ext/gtk4/rb-gtk4-private.h
|
54
|
+
- ext/gtk4/rb-gtk4-tree-view.c
|
53
55
|
- ext/gtk4/rb-gtk4-widget.c
|
54
56
|
- ext/gtk4/rb-gtk4-window.c
|
55
57
|
- ext/gtk4/rb-gtk4.c
|
@@ -121,7 +123,12 @@ files:
|
|
121
123
|
- sample/examples/grid_packing.rb
|
122
124
|
- sample/examples/hello_world.rb
|
123
125
|
- sample/examples/utils.rb
|
126
|
+
- sample/examples/window_default.rb
|
124
127
|
- sample/getting-started/README.md
|
128
|
+
- sample/getting-started/images/example-0.png
|
129
|
+
- sample/getting-started/images/example-1.png
|
130
|
+
- sample/getting-started/images/example-2.png
|
131
|
+
- sample/getting-started/images/example-3.png
|
125
132
|
homepage: https://ruby-gnome2.osdn.jp/
|
126
133
|
licenses:
|
127
134
|
- LGPL-2.1+
|