gtk3 3.0.9-x64-mingw32 → 3.1.0-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/gtk3/rb-gtk3-private.h +1 -0
- data/ext/gtk3/rb-gtk3-spin-button.c +85 -0
- data/ext/gtk3/rb-gtk3.c +3 -0
- data/lib/2.2/gtk3.so +0 -0
- data/lib/2.3/gtk3.so +0 -0
- data/lib/gtk3/deprecated.rb +0 -8
- data/lib/gtk3/loader.rb +1 -7
- data/lib/gtk3/tree-model.rb +2 -0
- data/sample/gtk-demo/TODO +10 -10
- data/sample/gtk-demo/assistant.rb +44 -39
- data/sample/gtk-demo/builder.rb +71 -50
- data/sample/gtk-demo/button_box.rb +39 -28
- data/sample/gtk-demo/clipboard.rb +139 -46
- data/sample/gtk-demo/colorsel.rb +50 -36
- data/sample/gtk-demo/css_accordion.rb +18 -17
- data/sample/gtk-demo/css_basics.rb +60 -47
- data/sample/gtk-demo/css_multiplebgs.rb +92 -71
- data/sample/gtk-demo/css_pixbufs.rb +61 -48
- data/sample/gtk-demo/css_shadows.rb +63 -50
- data/sample/gtk-demo/cursors.rb +95 -64
- data/sample/gtk-demo/dialog.rb +95 -78
- data/sample/gtk-demo/drawingarea.rb +138 -171
- data/sample/gtk-demo/editable_cells.rb +169 -130
- data/sample/gtk-demo/entry_buffer.rb +15 -13
- data/sample/gtk-demo/entry_completion.rb +22 -17
- data/sample/gtk-demo/expander.rb +39 -31
- data/sample/gtk-demo/filtermodel.rb +67 -63
- data/sample/gtk-demo/font_features.rb +91 -60
- data/sample/gtk-demo/glarea.rb +277 -0
- data/sample/gtk-demo/headerbar.rb +17 -15
- data/sample/gtk-demo/hypertext.rb +146 -167
- data/sample/gtk-demo/iconview.rb +132 -91
- data/sample/gtk-demo/iconview_edit.rb +49 -38
- data/sample/gtk-demo/infobar.rb +81 -62
- data/sample/gtk-demo/links.rb +35 -30
- data/sample/gtk-demo/list_store.rb +169 -114
- data/sample/gtk-demo/listbox.rb +183 -0
- data/sample/gtk-demo/main.rb +32 -21
- data/sample/gtk-demo/markup.rb +65 -52
- data/sample/gtk-demo/menus.rb +57 -58
- data/sample/gtk-demo/modelbutton.rb +11 -9
- data/sample/gtk-demo/modelbutton.ui +3 -0
- data/sample/gtk-demo/overlay.rb +39 -32
- data/sample/gtk-demo/overlay2.rb +68 -54
- data/sample/gtk-demo/panes.rb +56 -68
- data/sample/gtk-demo/pickers.rb +46 -45
- data/sample/gtk-demo/pixbufs.rb +27 -25
- data/sample/gtk-demo/popover.rb +70 -63
- data/sample/gtk-demo/printing.rb +94 -69
- data/sample/gtk-demo/revealer.rb +46 -38
- data/sample/gtk-demo/rotated_text.rb +75 -54
- data/sample/gtk-demo/scale.rb +10 -8
- data/sample/gtk-demo/search_entry.rb +195 -0
- data/sample/gtk-demo/search_entry2.rb +71 -59
- data/sample/gtk-demo/sidebar.rb +20 -19
- data/sample/gtk-demo/sizegroup.rb +36 -35
- data/sample/gtk-demo/spinbutton.rb +128 -0
- data/sample/gtk-demo/spinner.rb +55 -40
- data/sample/gtk-demo/stack.rb +11 -8
- data/sample/gtk-demo/textmask.rb +14 -13
- data/sample/gtk-demo/textscroll.rb +16 -12
- data/sample/gtk-demo/theming_style_classes.rb +14 -12
- data/sample/gtk-demo/transparent.rb +17 -13
- data/sample/misc/treemodelfilter.rb +1 -1
- metadata +24 -19
@@ -0,0 +1,277 @@
|
|
1
|
+
# Copyright (c) 2016 Ruby-GNOME2 Project Team
|
2
|
+
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
|
+
#
|
4
|
+
=begin
|
5
|
+
= OpenGL Area
|
6
|
+
|
7
|
+
GtkGLArea is a widget that allows custom drawing using OpenGL calls.
|
8
|
+
=end
|
9
|
+
require "opengl"
|
10
|
+
OpenGL.load_lib
|
11
|
+
include OpenGL
|
12
|
+
|
13
|
+
class GlareaDemo
|
14
|
+
X_AXIS, Y_AXIS, Z_AXIS = (0..2).to_a
|
15
|
+
# The object we are drawing
|
16
|
+
VERTEX_DATA = [0.0, 0.5, 0.0, 1.0,
|
17
|
+
0.5, -0.366, 0.0, 1.0,
|
18
|
+
-0.5, -0.366, 0.0, 1.0].freeze
|
19
|
+
|
20
|
+
def initialize(main_window)
|
21
|
+
# Rotation angles on each axis
|
22
|
+
@rotation_angles = [0.0, 0.0, 0.0]
|
23
|
+
@window = Gtk::Window.new(:toplevel)
|
24
|
+
@window.screen = main_window.screen
|
25
|
+
@window.title = "OpenGL Area"
|
26
|
+
@window.set_default_size(400, 600)
|
27
|
+
@window.border_width = 12
|
28
|
+
|
29
|
+
box = Gtk::Box.new(:vertical, false)
|
30
|
+
box.spacing = 6
|
31
|
+
@window.add(box)
|
32
|
+
|
33
|
+
@gl_area = Gtk::GLArea.new
|
34
|
+
@gl_area.hexpand = true
|
35
|
+
@gl_area.vexpand = true
|
36
|
+
box.add(@gl_area)
|
37
|
+
|
38
|
+
# We need to initialize and free GL resources, so we use
|
39
|
+
# the realize and unrealize signals on the widget
|
40
|
+
@gl_area.signal_connect "realize" do |widget|
|
41
|
+
# We need to set up our state when we realize the GtkGLArea widget
|
42
|
+
widget.make_current
|
43
|
+
unless widget.error
|
44
|
+
init_buffers
|
45
|
+
@program, @mvp_location = init_shaders
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@gl_area.signal_connect "unrealize" do |widget|
|
50
|
+
widget.make_current
|
51
|
+
unless widget.error
|
52
|
+
# We should tear down the state when unrealizing
|
53
|
+
glDeleteProgram(@program)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# The main "draw" call for GtkGLArea
|
58
|
+
@gl_area.signal_connect "render" do |area, _context|
|
59
|
+
return false if area.error
|
60
|
+
|
61
|
+
# Clear the viewport
|
62
|
+
glClearColor(0.5, 0.5, 0.5, 1.0)
|
63
|
+
glClear(GL_COLOR_BUFFER_BIT)
|
64
|
+
draw_triangle
|
65
|
+
glFlush
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
controls = Gtk::Box.new(:vertical, false)
|
70
|
+
box.add(controls)
|
71
|
+
controls.hexpand = true
|
72
|
+
(0..2).each do |i|
|
73
|
+
controls.add(create_axis_slider(i))
|
74
|
+
end
|
75
|
+
|
76
|
+
button = Gtk::Button.new(:label => "Quit")
|
77
|
+
button.hexpand = true
|
78
|
+
box.add(button)
|
79
|
+
button.signal_connect "clicked" do
|
80
|
+
@window.destroy
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def run
|
85
|
+
if !@window.visible?
|
86
|
+
@window.show_all
|
87
|
+
else
|
88
|
+
@window.destroy
|
89
|
+
end
|
90
|
+
@window
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def init_buffers
|
96
|
+
vao = " "
|
97
|
+
glGenVertexArrays(1, vao)
|
98
|
+
gl_vao = vao.unpack("L")[0]
|
99
|
+
@position_buffer = gl_vao
|
100
|
+
glBindVertexArray(gl_vao)
|
101
|
+
|
102
|
+
# This is the buffer that holds the vertices
|
103
|
+
buffer = " "
|
104
|
+
glGenBuffers(1, buffer)
|
105
|
+
gl_vbo = buffer.unpack("L")[0]
|
106
|
+
glBindBuffer(GL_ARRAY_BUFFER, gl_vbo)
|
107
|
+
glBufferData(GL_ARRAY_BUFFER, 3 * 4 * Fiddle::SIZEOF_FLOAT,
|
108
|
+
VERTEX_DATA.pack("F*"), GL_STATIC_DRAW)
|
109
|
+
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Initialize shaders and link them into a programm
|
113
|
+
def init_shaders
|
114
|
+
src_vertex = Gio::Resources.lookup_data("/glarea/glarea-vertex.glsl", 0)
|
115
|
+
src_fragment = Gio::Resources.lookup_data("/glarea/glarea-fragment.glsl", 0)
|
116
|
+
vertex = create_shader(GL_VERTEX_SHADER, src_vertex)
|
117
|
+
return [0, nil] if vertex.zero?
|
118
|
+
fragment = create_shader(GL_FRAGMENT_SHADER, src_fragment)
|
119
|
+
return [0, nil] if fragment.zero?
|
120
|
+
|
121
|
+
program = glCreateProgram
|
122
|
+
glAttachShader(program, vertex)
|
123
|
+
glAttachShader(program, fragment)
|
124
|
+
glLinkProgram(program)
|
125
|
+
# Check if the program is valid
|
126
|
+
linked_buf = " "
|
127
|
+
glGetProgramiv(program, GL_LINK_STATUS, linked_buf)
|
128
|
+
status = linked_buf.unpack("L")[0]
|
129
|
+
if status.zero?
|
130
|
+
log_len = " "
|
131
|
+
glGetShaderiv(program, GL_INFO_LOG_LENGTH, log_len)
|
132
|
+
len = log_len.unpack("L")[0]
|
133
|
+
info_log = " " * (len + 1)
|
134
|
+
glGetProgramInfoLog(program, len, nil, info_log)
|
135
|
+
STDERR.puts "Linking failure:\n#{info_log}\n"
|
136
|
+
glDeleteProgram(program)
|
137
|
+
glDeleteShader(vertex)
|
138
|
+
glDeleteShader(fragment)
|
139
|
+
program = 0
|
140
|
+
end
|
141
|
+
mvp = glGetUniformLocation(program, "mvp")
|
142
|
+
[program, mvp]
|
143
|
+
end
|
144
|
+
|
145
|
+
def create_shader(type, source)
|
146
|
+
# Load the shaders sources
|
147
|
+
shader = glCreateShader(type)
|
148
|
+
|
149
|
+
glShaderSource(shader, 1, [source].pack("p"), [source.bytesize].pack("I"))
|
150
|
+
# Compile the vertex shader
|
151
|
+
glCompileShader(shader)
|
152
|
+
# Check the vertex shader compilation
|
153
|
+
compiled_buf = " "
|
154
|
+
glGetShaderiv(shader, GL_COMPILE_STATUS, compiled_buf)
|
155
|
+
status = compiled_buf.unpack("L")[0]
|
156
|
+
if status.zero?
|
157
|
+
log_len = " "
|
158
|
+
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, log_len)
|
159
|
+
len = log_len.unpack("L")[0]
|
160
|
+
info_log = " " * (len + 1)
|
161
|
+
glGetShaderInfoLog(shader, len, nil, info_log)
|
162
|
+
type_name = type == GL_VERTEX_SHADER ? "vertex" : "fragment"
|
163
|
+
STDERR.puts "Compile failure in #{type_name}:\n#{info_log}\n"
|
164
|
+
return 0
|
165
|
+
end
|
166
|
+
shader
|
167
|
+
end
|
168
|
+
|
169
|
+
def draw_triangle
|
170
|
+
# Compute the model view projection matrix using the rotation angles
|
171
|
+
# specified through the GtkRange widgets
|
172
|
+
mvp = compute_mvp
|
173
|
+
# Use our program
|
174
|
+
glUseProgram(@program)
|
175
|
+
# Update the "mvp" matrix we use in the shader
|
176
|
+
glUniformMatrix4fv(@mvp_location, 1, GL_FALSE, mvp.pack("F16"))
|
177
|
+
# Use the vertices in our buffer
|
178
|
+
glBindBuffer(GL_ARRAY_BUFFER, @position_buffer)
|
179
|
+
glEnableVertexAttribArray(0)
|
180
|
+
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0)
|
181
|
+
|
182
|
+
# Draw the three vertices as a triangle
|
183
|
+
glDrawArrays(GL_TRIANGLES, 0, 3)
|
184
|
+
|
185
|
+
# We finished using the buffers and program
|
186
|
+
glDisableVertexAttribArray(0)
|
187
|
+
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
188
|
+
glUseProgram(0)
|
189
|
+
end
|
190
|
+
|
191
|
+
def compute_mvp
|
192
|
+
phi = @rotation_angles[X_AXIS]
|
193
|
+
theta = @rotation_angles[Y_AXIS]
|
194
|
+
psi = @rotation_angles[Z_AXIS]
|
195
|
+
res = Array.new(16, 0.0)
|
196
|
+
x = phi * (Math::PI / 180.0)
|
197
|
+
y = theta * (Math::PI / 180.0)
|
198
|
+
z = psi * (Math::PI / 180.0)
|
199
|
+
c1 = Math.cos(x)
|
200
|
+
c2 = Math.cos(y)
|
201
|
+
c3 = Math.cos(z)
|
202
|
+
s1 = Math.sin(x)
|
203
|
+
s2 = Math.sin(y)
|
204
|
+
s3 = Math.sin(z)
|
205
|
+
c3c2 = c3 * c2
|
206
|
+
s3c1 = s3 * c1
|
207
|
+
c3s2s1 = c3 * s2 * s1
|
208
|
+
s3s1 = s3 * s1
|
209
|
+
c3s2c1 = c3 * s2 * c1
|
210
|
+
s3c2 = s3 * c2
|
211
|
+
c3c1 = c3 * c1
|
212
|
+
s3s2s1 = s3 * s2 * s1
|
213
|
+
c3s1 = c3 * s1
|
214
|
+
s3s2c1 = s3 * s2 * c1
|
215
|
+
c2s1 = c2 * s1
|
216
|
+
c2c1 = c2 * c1
|
217
|
+
|
218
|
+
# initialize to the identity matrix
|
219
|
+
res[0] = 1.0
|
220
|
+
res[5] = 1.0
|
221
|
+
res[10] = 1.0
|
222
|
+
res[15] = 1.0
|
223
|
+
|
224
|
+
# apply all three rotations using the three matrices:
|
225
|
+
#
|
226
|
+
# ⎡ c3 s3 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ 1 0 0 ⎤
|
227
|
+
# ⎢ -s3 c3 0 ⎥ ⎢ 0 1 0 ⎥ ⎢ 0 c1 s1 ⎥
|
228
|
+
# ⎣ 0 0 1 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 -s1 c1 ⎦
|
229
|
+
|
230
|
+
res[0] = c3c2
|
231
|
+
res[1] = -s3c2
|
232
|
+
res[2] = s2
|
233
|
+
res[3] = 0.0
|
234
|
+
res[4] = s3c1 + c3s2s1
|
235
|
+
res[5] = c3c1 - s3s2s1
|
236
|
+
res[6] = -c2s1
|
237
|
+
res[7] = 0.0
|
238
|
+
res[8] = s3s1 - c3s2c1
|
239
|
+
res[9] = c3s1 + s3s2c1
|
240
|
+
res[10] = c2c1
|
241
|
+
res[11] = 0.0
|
242
|
+
res[12] = 0.0
|
243
|
+
res[13] = 0.0
|
244
|
+
res[14] = 0.0
|
245
|
+
res[15] = 1.0
|
246
|
+
res
|
247
|
+
end
|
248
|
+
|
249
|
+
def create_axis_slider(axis)
|
250
|
+
box = Gtk::Box.new(:horizontal, 0)
|
251
|
+
text = case axis
|
252
|
+
when X_AXIS
|
253
|
+
"X axis"
|
254
|
+
when Y_AXIS
|
255
|
+
"Y axis"
|
256
|
+
when Z_AXIS
|
257
|
+
"Z axis"
|
258
|
+
end
|
259
|
+
label = Gtk::Label.new(text)
|
260
|
+
box.add(label)
|
261
|
+
label.show
|
262
|
+
|
263
|
+
adj = Gtk::Adjustment.new(0.0, 0.0, 360.0, 1.0, 12.0, 0.0)
|
264
|
+
adj.signal_connect "value-changed" do |widget|
|
265
|
+
# Updte the rotation angle
|
266
|
+
@rotation_angles[axis] = widget.value
|
267
|
+
# Update the contents of the GL drawing area
|
268
|
+
@gl_area.queue_draw
|
269
|
+
end
|
270
|
+
slider = Gtk::Scale.new(:horizontal, adj)
|
271
|
+
box.add(slider)
|
272
|
+
slider.hexpand = true
|
273
|
+
slider.show
|
274
|
+
box.show
|
275
|
+
box
|
276
|
+
end
|
277
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2015 Ruby-GNOME2 Project Team
|
1
|
+
# Copyright (c) 2015-2016 Ruby-GNOME2 Project Team
|
2
2
|
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
3
|
#
|
4
4
|
=begin
|
@@ -12,18 +12,18 @@ or right.
|
|
12
12
|
|
13
13
|
It is commonly used with gtk_window_set_titlebar()
|
14
14
|
=end
|
15
|
-
|
16
|
-
def
|
17
|
-
window = Gtk::Window.new(:toplevel)
|
18
|
-
window.screen = main_window.screen
|
19
|
-
window.set_default_size(600, 400)
|
15
|
+
class HeaderbarDemo
|
16
|
+
def initialize(main_window)
|
17
|
+
@window = Gtk::Window.new(:toplevel)
|
18
|
+
@window.screen = main_window.screen
|
19
|
+
@window.set_default_size(600, 400)
|
20
20
|
|
21
21
|
header = Gtk::HeaderBar.new
|
22
|
-
header.
|
23
|
-
header.
|
24
|
-
header.
|
22
|
+
header.show_close_button = true
|
23
|
+
header.title = "Welcome to Facebook - Log in, sign up or learn more"
|
24
|
+
header.has_subtitle = false
|
25
25
|
|
26
|
-
button = Gtk::Button.new
|
26
|
+
button = Gtk::Button.new
|
27
27
|
|
28
28
|
icon = Gio::ThemedIcon.new("mail-send-receive-symbolic")
|
29
29
|
image = Gtk::Image.new(:icon => icon, :size => :button)
|
@@ -45,13 +45,15 @@ module HeaderbarDemo
|
|
45
45
|
box.add(button)
|
46
46
|
|
47
47
|
header.pack_start(box)
|
48
|
-
window.
|
49
|
-
window.add(Gtk::TextView.new
|
48
|
+
@window.titlebar = header
|
49
|
+
@window.add(Gtk::TextView.new)
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
def run
|
53
|
+
if !@window.visible?
|
54
|
+
@window.show_all
|
53
55
|
else
|
54
|
-
window.destroy
|
56
|
+
@window.destroy
|
55
57
|
end
|
56
58
|
end
|
57
59
|
end
|
@@ -1,205 +1,184 @@
|
|
1
|
-
# Copyright (c)
|
1
|
+
# Copyright (c) 2016 Ruby-GNOME2 Project Team
|
2
2
|
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
3
|
#
|
4
|
-
# $Id: hypertext.rb,v 1.2 2005/12/01 09:27:01 ktou Exp $
|
5
4
|
=begin
|
6
|
-
=
|
5
|
+
= Text View/Hypertext
|
7
6
|
|
8
|
-
Usually, tags modify the appearance of text in the view, e.g. making it
|
9
|
-
bold or colored or underlined. But tags are not restricted to appearance.
|
10
|
-
They can also affect the behavior of mouse and key presses, as this demo
|
11
|
-
shows.
|
7
|
+
Usually, tags modify the appearance of text in the view, e.g. making it
|
8
|
+
bold or colored or underlined. But tags are not restricted to appearance.
|
9
|
+
They can also affect the behavior of mouse and key presses, as this demo
|
10
|
+
shows.
|
12
11
|
=end
|
12
|
+
class HypertextDemo
|
13
|
+
def initialize(main_window)
|
14
|
+
initialize_window(main_window)
|
15
|
+
initialize_cursors(main_window)
|
16
|
+
initialize_view
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
super('Hypertext')
|
20
|
-
|
21
|
-
@hand_cursor = Gdk::Cursor.new(Gdk::Cursor::HAND2)
|
22
|
-
@regular_cursor = Gdk::Cursor.new(Gdk::Cursor::XTERM)
|
23
|
-
@hovering = false
|
24
|
-
|
25
|
-
set_default_size(450, 450)
|
26
|
-
self.border_width = 0
|
27
|
-
|
28
|
-
view = Gtk::TextView.new
|
29
|
-
|
30
|
-
view.wrap_mode = :word
|
31
|
-
|
32
|
-
view.signal_connect('key-press-event') do |*args|
|
33
|
-
key_press_event(*args)
|
34
|
-
end
|
35
|
-
view.signal_connect('event-after') do |*args|
|
36
|
-
event_after(*args)
|
37
|
-
end
|
38
|
-
view.signal_connect('motion-notify-event') do |*args|
|
39
|
-
motion_notify_event(*args)
|
40
|
-
end
|
41
|
-
view.signal_connect('visibility-notify-event') do |*args|
|
42
|
-
visibility_notify_event(*args)
|
18
|
+
@view.signal_connect "key-press-event" do |_widget, event|
|
19
|
+
case event.keyval
|
20
|
+
when Gdk::Keyval::KEY_Return, Gdk::Keyval::KEY_KP_Enter
|
21
|
+
iter = @buffer.get_iter_at_mark(@buffer.get_mark("insert"))
|
22
|
+
follow_if_link(iter) if iter
|
43
23
|
end
|
44
24
|
|
45
|
-
|
46
|
-
|
47
|
-
sw = Gtk::ScrolledWindow.new
|
48
|
-
sw.set_policy(:automatic,
|
49
|
-
:automatic)
|
50
|
-
|
51
|
-
add(sw)
|
52
|
-
sw.add(view)
|
53
|
-
|
54
|
-
show_page(buffer, 1)
|
25
|
+
false
|
55
26
|
end
|
56
27
|
|
28
|
+
# Links can also be activated by clicking or tapping.
|
29
|
+
@view.signal_connect "event-after" do |widget, event|
|
30
|
+
if event.is_a?(Gdk::EventButton) && event.button == 1
|
31
|
+
buffer = widget.buffer
|
57
32
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
# as a link.
|
62
|
-
def insert_link(buffer, iter, text, page)
|
63
|
-
tag = buffer.create_tag(nil,
|
64
|
-
{
|
65
|
-
'foreground' => 'blue',
|
66
|
-
'underline' => Pango::AttrUnderline::SINGLE,
|
67
|
-
})
|
68
|
-
tag.page = page
|
69
|
-
|
70
|
-
buffer.insert(iter, text, tag)
|
71
|
-
print("Insert #{tag}:#{page}\n")
|
72
|
-
end
|
33
|
+
# we shouldn't follow a link if the user has selected something
|
34
|
+
range = buffer.selection_bounds
|
35
|
+
return false if range && range[0].offset != range[1].offset
|
73
36
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
buffer.text = ''
|
80
|
-
iter = buffer.get_iter_at(:offset => 0)
|
81
|
-
|
82
|
-
case page
|
83
|
-
when 1
|
84
|
-
buffer.insert(iter, 'Some text ot show that simple ')
|
85
|
-
insert_link(buffer, iter, 'hypertext', 3)
|
86
|
-
buffer.insert(iter, ' can easily be realized with ')
|
87
|
-
insert_link(buffer, iter, 'tags', 2)
|
88
|
-
buffer.insert(iter, '.')
|
89
|
-
when 2
|
90
|
-
buffer.insert(iter,
|
91
|
-
%Q[A tag is an attribute that can be applied to some range of text. For example, a tag might be called "bold" and make the text insid the tag bold. However, the tag concept is more general than that; tags don't have to affect appearance. They can instead affect the behavior of mouse and key presses, "lock" a range of text so the user can't edit it, or countless other things.])
|
92
|
-
buffer.insert(iter, "\n")
|
93
|
-
insert_link(buffer, iter, 'Go back', 1)
|
94
|
-
when 3
|
95
|
-
tag = buffer.create_tag(nil,
|
96
|
-
{
|
97
|
-
'weight' =>
|
98
|
-
Pango::FontDescription::WEIGHT_BOLD
|
99
|
-
})
|
100
|
-
buffer.insert(iter, "hypertext:\n", tag);
|
101
|
-
buffer.insert(iter, %Q[machine-readable text that is not sequential but is organized so that related items of information are connected.\n])
|
102
|
-
insert_link(buffer, iter, 'Go back', 1)
|
37
|
+
x, y = widget.window_to_buffer_coords(:widget, event.x, event.y)
|
38
|
+
iter = widget.get_iter_at_location(x, y)
|
39
|
+
follow_if_link(iter) if iter
|
40
|
+
else
|
41
|
+
false
|
103
42
|
end
|
104
43
|
end
|
105
44
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
tags = iter.tags
|
111
|
-
tags.each do |tag|
|
112
|
-
print("Follow #{tag}:#{tag.page}\n")
|
113
|
-
if tag.page
|
114
|
-
show_page(text_view.buffer, tag.page)
|
115
|
-
break
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# Links can be activated by pressing Enter.
|
121
|
-
def key_press_event(text_view, event)
|
122
|
-
case event.keyval
|
123
|
-
when Gdk::Keyval::KEY_Return, Gdk::Keyval::KEY_KP_Enter
|
124
|
-
buffer = text_view.buffer
|
125
|
-
iter = buffer.get_iter_at_mark(buffer.get_mark("insert"))
|
126
|
-
follow_if_link(text_view, iter)
|
127
|
-
end
|
45
|
+
@view.signal_connect "motion-notify-event" do |widget, event|
|
46
|
+
x, y = widget.window_to_buffer_coords(:widget, event.x, event.y)
|
47
|
+
set_cursor_if_appropriate(widget, x, y)
|
48
|
+
widget.window.pointer
|
128
49
|
|
129
50
|
false
|
130
51
|
end
|
131
52
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
53
|
+
sw = Gtk::ScrolledWindow.new
|
54
|
+
sw.set_policy(:automatic, :automatic)
|
55
|
+
@window.add(sw)
|
56
|
+
sw.add(@view)
|
57
|
+
show_page(1)
|
58
|
+
sw.show_all
|
59
|
+
end
|
137
60
|
|
138
|
-
|
61
|
+
def run
|
62
|
+
if !@window.visible?
|
63
|
+
@window.show_all
|
64
|
+
else
|
65
|
+
@window.destroy
|
66
|
+
end
|
67
|
+
@window
|
68
|
+
end
|
139
69
|
|
140
|
-
|
141
|
-
range = buffer.selection_bounds
|
142
|
-
if range and range[0].offset != range[1].offset
|
143
|
-
return false
|
144
|
-
end
|
70
|
+
private
|
145
71
|
|
146
|
-
|
147
|
-
|
148
|
-
|
72
|
+
def initialize_window(main_window)
|
73
|
+
@window = Gtk::Window.new(:toplevel)
|
74
|
+
@window.screen = main_window.screen
|
75
|
+
@window.title = "Hypertext"
|
76
|
+
@window.set_default_size(450, 450)
|
77
|
+
@window.border_width = 0
|
78
|
+
end
|
149
79
|
|
150
|
-
|
151
|
-
|
80
|
+
def initialize_cursors(main_window)
|
81
|
+
display = main_window.display
|
82
|
+
@hand_cursor = Gdk::Cursor.new("pointer", :display => display)
|
83
|
+
@regular_cursor = Gdk::Cursor.new("text", :display => display)
|
84
|
+
end
|
152
85
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
86
|
+
def initialize_view
|
87
|
+
@view = Gtk::TextView.new
|
88
|
+
@view.wrap_mode = :word
|
89
|
+
@view.left_margin = 20
|
90
|
+
@view.right_margin = 20
|
91
|
+
@buffer = @view.buffer
|
92
|
+
end
|
157
93
|
|
158
|
-
|
159
|
-
|
94
|
+
# Fills the buffer with text and interspersed links. In any real
|
95
|
+
# hypertext app, this method would parse a file to identify the links.
|
96
|
+
def show_page(page)
|
97
|
+
@buffer.text = ""
|
98
|
+
case page
|
99
|
+
when 1
|
100
|
+
generate_page_1
|
101
|
+
when 2
|
102
|
+
generate_page_2
|
103
|
+
when 3
|
104
|
+
generate_page_3
|
105
|
+
end
|
106
|
+
end
|
160
107
|
|
161
|
-
|
108
|
+
def generate_page_1
|
109
|
+
iter = @buffer.get_iter_at(:offset => 0)
|
110
|
+
@buffer.insert(iter, "Some text to show that simple")
|
111
|
+
insert_link(iter, "hyper text", 3)
|
112
|
+
@buffer.insert(iter, " can easily be realized with ")
|
113
|
+
insert_link(iter, "tags", 2)
|
114
|
+
@buffer.insert(iter, ".")
|
115
|
+
end
|
162
116
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
117
|
+
def generate_page_2
|
118
|
+
iter = @buffer.get_iter_at(:offset => 0)
|
119
|
+
@buffer.insert(iter, <<-EOF)
|
120
|
+
A tag is an attribute that can be applied to some range of text.
|
121
|
+
For example, a tag might be called "bold" and make the text inside
|
122
|
+
the tag bold. However, the tag concept is more general than that;
|
123
|
+
tags don't have to affect appearance. They can instead affect the
|
124
|
+
behavior of mouse and key presses, "lock" a range of text so the
|
125
|
+
user can't edit it, or countless other things.\n
|
126
|
+
EOF
|
127
|
+
insert_link(iter, "Goback", 1)
|
128
|
+
end
|
170
129
|
|
171
|
-
|
172
|
-
|
130
|
+
def generate_page_3
|
131
|
+
iter = @buffer.get_iter_at(:offset => 0)
|
132
|
+
tag = @buffer.create_tag(nil,
|
133
|
+
"weight" => Pango::FontDescription::WEIGHT_BOLD)
|
134
|
+
@buffer.insert(iter, "hypertext:\n", :tags => [tag])
|
135
|
+
@buffer.insert(iter, <<-EOF)
|
136
|
+
machine-readable text that is not sequential but is organized
|
137
|
+
so that related items of information are connected
|
138
|
+
EOF
|
139
|
+
insert_link(iter, "Go back", 1)
|
140
|
+
end
|
173
141
|
|
174
|
-
|
142
|
+
def insert_link(iter, text, page)
|
143
|
+
tag = @buffer.create_tag(nil,
|
144
|
+
"foreground" => "blue",
|
145
|
+
"underline" => Pango::AttrUnderline::SINGLE)
|
146
|
+
tag.page = page
|
147
|
+
@buffer.insert(iter, text, :tags => [tag])
|
148
|
+
end
|
175
149
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
150
|
+
# Looks at all tags covering the position of iter in the text view,
|
151
|
+
# and if one of them is a link, follow it by showing the page identified
|
152
|
+
# by the data attached to it.
|
153
|
+
def follow_if_link(iter)
|
154
|
+
tags = iter.tags
|
155
|
+
tags.each do |tag|
|
156
|
+
if tag.page
|
157
|
+
show_page(tag.page)
|
158
|
+
break
|
181
159
|
end
|
182
160
|
end
|
161
|
+
end
|
183
162
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
163
|
+
# Looks at all tags covering the position (x, y) in the text view,
|
164
|
+
# and if one of them is a link, change the cursor to the "hands" cursor
|
165
|
+
# typically used by web browsers.
|
166
|
+
def set_cursor_if_appropriate(text_view, x, y)
|
167
|
+
iter = text_view.get_iter_at_location(x, y)
|
168
|
+
return unless iter
|
169
|
+
hovering = false
|
170
|
+
tags = iter.tags
|
171
|
+
tags.each do |tag|
|
172
|
+
if tag.page
|
173
|
+
hovering = true
|
174
|
+
break
|
175
|
+
end
|
192
176
|
end
|
193
177
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
window
|
198
|
-
bx, by = text_view.window_to_buffer_coords(Gtk::TextView::WINDOW_WIDGET,
|
199
|
-
wx, wy)
|
200
|
-
set_cursor_if_appropriate(text_view, bx, by)
|
201
|
-
|
202
|
-
false
|
178
|
+
if hovering != @hovering
|
179
|
+
@hovering = hovering
|
180
|
+
window = text_view.get_window(:text)
|
181
|
+
window.cursor = @hovering ? @hand_cursor : @regular_cursor
|
203
182
|
end
|
204
183
|
end
|
205
184
|
end
|