gtk3 3.0.9 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/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 +21 -16
data/sample/gtk-demo/links.rb
CHANGED
@@ -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
|
@@ -8,12 +8,12 @@ GtkLabel can show hyperlinks. The default action is to call
|
|
8
8
|
gtk_show_uri() on their URI, but it is possible to override
|
9
9
|
this with a custom handler.
|
10
10
|
=end
|
11
|
-
|
12
|
-
def
|
13
|
-
window = Gtk::Window.new(:toplevel)
|
14
|
-
window.screen = main_window.screen
|
15
|
-
window.
|
16
|
-
window.
|
11
|
+
class LinksDemo
|
12
|
+
def initialize(main_window)
|
13
|
+
@window = Gtk::Window.new(:toplevel)
|
14
|
+
@window.screen = main_window.screen
|
15
|
+
@window.title = "Links"
|
16
|
+
@window.border_width = 12
|
17
17
|
|
18
18
|
label = Gtk::Label.new(<<-MESSAGE)
|
19
19
|
Some <a href="http://en.wikipedia.org/wiki/Text"
|
@@ -27,40 +27,45 @@ searching on <a href="http://www.google.com/">
|
|
27
27
|
<span color="#00933B">l</span><span color="#F90101">e</span>
|
28
28
|
</a>.
|
29
29
|
MESSAGE
|
30
|
-
label.
|
30
|
+
label.use_markup = true
|
31
31
|
|
32
|
-
label.signal_connect "activate-link" do |
|
32
|
+
label.signal_connect "activate-link" do |widget, uri|
|
33
33
|
if uri == "keynav"
|
34
|
-
|
35
|
-
dialog = Gtk::MessageDialog.new(:parent => parent,
|
36
|
-
:flags => :destroy_with_parent,
|
37
|
-
:type => :info,
|
38
|
-
:buttons => :ok,
|
39
|
-
:message => <<-MESSAGE)
|
40
|
-
The term <i>keynav</i> is a shorthand for
|
41
|
-
keyboard navigation and refers to the process of using
|
42
|
-
a program (exclusively) via keyboard input.
|
43
|
-
MESSAGE
|
44
|
-
dialog.set_use_markup(true)
|
45
|
-
dialog.set_modal(true)
|
46
|
-
dialog.present
|
47
|
-
dialog.signal_connect "response" do
|
48
|
-
dialog.destroy
|
49
|
-
end
|
34
|
+
generate_dialog(widget)
|
50
35
|
true
|
51
36
|
else
|
52
37
|
false
|
53
38
|
end
|
54
39
|
end
|
55
40
|
|
56
|
-
window.add(label)
|
41
|
+
@window.add(label)
|
57
42
|
label.show
|
43
|
+
end
|
58
44
|
|
59
|
-
|
60
|
-
|
45
|
+
def run
|
46
|
+
if !@window.visible?
|
47
|
+
@window.show_all
|
61
48
|
else
|
62
|
-
window.destroy
|
49
|
+
@window.destroy
|
63
50
|
end
|
64
|
-
window
|
51
|
+
@window
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def generate_dialog(widget)
|
57
|
+
dialog = Gtk::MessageDialog.new(:parent => widget.toplevel,
|
58
|
+
:flags => :destroy_with_parent,
|
59
|
+
:type => :info,
|
60
|
+
:buttons => :ok,
|
61
|
+
:message => <<-MESSAGE)
|
62
|
+
The term <i>keynav</i> is a shorthand for
|
63
|
+
keyboard navigation and refers to the process of using
|
64
|
+
a program (exclusively) via keyboard input.
|
65
|
+
MESSAGE
|
66
|
+
dialog.use_markup = true
|
67
|
+
dialog.modal = true
|
68
|
+
dialog.present
|
69
|
+
dialog.signal_connect("response", &:destroy)
|
65
70
|
end
|
66
71
|
end
|
@@ -1,138 +1,193 @@
|
|
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: list_store.rb,v 1.5 2005/02/06 18:25:13 kzys Exp $
|
5
4
|
=begin
|
6
|
-
=
|
5
|
+
= Tree View/List Store
|
7
6
|
|
8
|
-
The
|
9
|
-
later on by a
|
10
|
-
simple
|
11
|
-
demo for a more advanced example.
|
12
|
-
=end
|
13
|
-
require 'common'
|
14
|
-
|
15
|
-
module Demo
|
16
|
-
class ListStore < BasicWindow
|
17
|
-
Bug = Struct.new('Bug', :fixed, :number, :severity, :description)
|
18
|
-
COLUMN_FIXED, COLUMN_NUMBER, COLUMN_SEVERITY, COLUMN_DESCRIPTION,
|
19
|
-
NUM_COLUMNS = *(0..5).to_a
|
20
|
-
DATA = [
|
21
|
-
[ false, 60482, 'Normal', 'scrollable notebooks and hidden tabs' ],
|
22
|
-
[ false, 60620, 'Critical', 'gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe' ],
|
23
|
-
[ false, 50214, 'Major', 'Xft support does not clean up correctly' ],
|
24
|
-
[ true, 52877, 'Major', 'GtkFileSelection needs a refresh method. ' ],
|
25
|
-
[ false, 56070, 'Normal', "Can't click button after setting in sensitive" ],
|
26
|
-
[ true, 56355, 'Normal', 'GtkLabel - Not all changes propagate correctly' ],
|
27
|
-
[ false, 50055, 'Normal', 'Rework width/height computations for TreeView' ],
|
28
|
-
[ false, 58278, 'Normal', "gtk_dialog_set_response_sensitive doesn't work" ],
|
29
|
-
[ false, 55767, 'Normal', 'Getters for all setters' ],
|
30
|
-
[ false, 56925, 'Normal', 'Gtkcalender size' ],
|
31
|
-
[ false, 56221, 'Normal', 'Selectable label needs right-click copy menu' ],
|
32
|
-
[ true, 50939, 'Normal', 'Add shift clicking to GtkTextView' ],
|
33
|
-
[ false, 6112, 'Enhancement','netscape-like collapsable toolbars' ],
|
34
|
-
[ false, 1, 'Normal', 'First bug :=)' ],
|
35
|
-
].collect do |ary|
|
36
|
-
Bug.new(*ary)
|
37
|
-
end
|
38
|
-
def initialize
|
39
|
-
super('GtkListStore demo')
|
40
|
-
self.border_width = 8
|
7
|
+
The GtkListStore is used to store data in list form, to be used
|
8
|
+
later on by a GtkTreeView to display it. This demo builds a
|
9
|
+
simple GtkListStore and displays it.
|
41
10
|
|
42
|
-
|
43
|
-
|
11
|
+
=end
|
12
|
+
class ListStoreDemo
|
13
|
+
Bug = Struct.new("Bug", :fixed, :number, :severity, :description)
|
14
|
+
COLUMN_FIXED, COLUMN_NUMBER, COLUMN_SEVERITY, COLUMN_DESCRIPTION,
|
15
|
+
COLUMN_PULSE, COLUMN_ICON, COLUMN_ACTIVE, COLUMN_SENSITIVE, NUM_COLUMNS =
|
16
|
+
*(0..8).to_a
|
17
|
+
DATA = [
|
18
|
+
[false, 60_482, "Normal", "scrollable notebooks and hidden tabs" ],
|
19
|
+
[false, 60_620, "Critical", "gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe" ],
|
20
|
+
[false, 50_214, "Major", "Xft support does not clean up correctly" ],
|
21
|
+
[true, 52_877, "Major", "GtkFileSelection needs a refresh method. " ],
|
22
|
+
[false, 56_070, "Normal", "Can't click button after setting in sensitive" ],
|
23
|
+
[true, 56_355, "Normal", "GtkLabel - Not all changes propagate correctly" ],
|
24
|
+
[false, 50_055, "Normal", "Rework width/height computations for TreeView" ],
|
25
|
+
[false, 58_278, "Normal", "gtk_dialog_set_response_sensitive doesn't work" ],
|
26
|
+
[false, 55_767, "Normal", "Getters for all setters" ],
|
27
|
+
[false, 56_925, "Normal", "Gtkcalender size" ],
|
28
|
+
[false, 56_221, "Normal", "Selectable label needs right-click copy menu" ],
|
29
|
+
[true, 50_939, "Normal", "Add shift clicking to GtkTextView" ],
|
30
|
+
[false, 6_112, "Enhancement","netscape-like collapsable toolbars" ],
|
31
|
+
[false, 1, "Normal", "First bug :=)" ],
|
32
|
+
].collect do |ary|
|
33
|
+
Bug.new(*ary)
|
34
|
+
end
|
44
35
|
|
45
|
-
|
46
|
-
|
36
|
+
def initialize(main_window)
|
37
|
+
@window = Gtk::Window.new(:toplevel)
|
38
|
+
@window.screen = main_window.screen
|
39
|
+
@window.title = "List Store"
|
40
|
+
@window.border_width = 8
|
41
|
+
@timeout = 0
|
42
|
+
@window.signal_connect "delete-event" do
|
43
|
+
@model = nil
|
44
|
+
GLib::Source.remove(@timeout) unless @timeout.zero?
|
45
|
+
@timeout = 0
|
46
|
+
false
|
47
|
+
end
|
48
|
+
vbox = Gtk::Box.new(:vertical, 8)
|
49
|
+
@window.add(vbox)
|
50
|
+
|
51
|
+
label = Gtk::Label.new(<<-EOF)
|
52
|
+
This is the bug list (note: not based on real data, it would be nice to
|
53
|
+
have a nice ODBC interface to bugzilla or so, though).
|
54
|
+
EOF
|
55
|
+
vbox.pack_start(label, :expand => false, :fill => false, :padding => 0)
|
56
|
+
sw = Gtk::ScrolledWindow.new(nil, nil)
|
57
|
+
sw.shadow_type = :etched_in
|
58
|
+
sw.set_policy(:never, :automatic)
|
59
|
+
vbox.pack_start(sw, :expand => true, :fill => true, :padding => 0)
|
60
|
+
|
61
|
+
# create tree model
|
62
|
+
create_model
|
63
|
+
|
64
|
+
# create tree view
|
65
|
+
treeview = Gtk::TreeView.new(@model)
|
66
|
+
treeview.search_column = COLUMN_DESCRIPTION
|
67
|
+
sw.add(treeview)
|
68
|
+
|
69
|
+
# add columns to the tree view
|
70
|
+
add_columns(treeview)
|
71
|
+
|
72
|
+
# finish and show
|
73
|
+
@window.set_default_size(280, 250)
|
74
|
+
end
|
47
75
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
76
|
+
def run
|
77
|
+
if !@window.visible?
|
78
|
+
@window.show_all
|
79
|
+
add_spinner
|
52
80
|
|
53
|
-
|
54
|
-
|
81
|
+
else
|
82
|
+
@window.destroy
|
83
|
+
GLib::Source.remove(@tiemout) unless @timeout.zero?
|
84
|
+
@timeout = 0
|
85
|
+
end
|
86
|
+
@window
|
87
|
+
end
|
55
88
|
|
56
|
-
|
57
|
-
treeview = Gtk::TreeView.new(model)
|
58
|
-
treeview.rules_hint = true
|
59
|
-
treeview.search_column = COLUMN_DESCRIPTION
|
89
|
+
private
|
60
90
|
|
61
|
-
|
91
|
+
def create_model
|
92
|
+
# create list store
|
93
|
+
@model = Gtk::ListStore.new(TrueClass, Integer, String, String, Integer,
|
94
|
+
String, TrueClass, TrueClass)
|
62
95
|
|
63
|
-
|
64
|
-
|
96
|
+
# add data to the list store
|
97
|
+
DATA.each_with_index do |bug, i|
|
98
|
+
icon_name = ""
|
99
|
+
icon_name = "battery-caution-charging-symbolic" if i == 1 || i == 3
|
100
|
+
sensitive = i == 3 ? false : true
|
65
101
|
|
66
|
-
|
102
|
+
iter = @model.append
|
103
|
+
iter.set_values([bug.fixed, bug.number, bug.severity, bug.description,
|
104
|
+
0, icon_name, false, sensitive])
|
67
105
|
end
|
106
|
+
end
|
68
107
|
|
69
|
-
|
70
|
-
|
71
|
-
|
108
|
+
def add_columns(treeview)
|
109
|
+
# column for fixed toggles
|
110
|
+
renderer = Gtk::CellRendererToggle.new
|
111
|
+
renderer.signal_connect("toggled") { |_cell, path| fixed_toggled(path) }
|
112
|
+
column = Gtk::TreeViewColumn.new("Fixed?",
|
113
|
+
renderer,
|
114
|
+
"active" => COLUMN_FIXED)
|
115
|
+
|
116
|
+
# set this column to a fixed sizing (of 50 pixels)
|
117
|
+
column.sizing = :fixed
|
118
|
+
column.fixed_width = 50
|
119
|
+
treeview.append_column(column)
|
120
|
+
|
121
|
+
# column for bug numbers
|
122
|
+
renderer = Gtk::CellRendererText.new
|
123
|
+
column = Gtk::TreeViewColumn.new("Bug number",
|
124
|
+
renderer,
|
125
|
+
"text" => COLUMN_NUMBER)
|
126
|
+
column.sort_column_id = COLUMN_NUMBER
|
127
|
+
treeview.append_column(column)
|
128
|
+
|
129
|
+
# column for severities
|
130
|
+
renderer = Gtk::CellRendererText.new
|
131
|
+
column = Gtk::TreeViewColumn.new("Severity",
|
132
|
+
renderer,
|
133
|
+
"text" => COLUMN_SEVERITY)
|
134
|
+
column.sort_column_id = COLUMN_SEVERITY
|
135
|
+
treeview.append_column(column)
|
136
|
+
|
137
|
+
# column for description
|
138
|
+
renderer = Gtk::CellRendererText.new
|
139
|
+
column = Gtk::TreeViewColumn.new("Description",
|
140
|
+
renderer,
|
141
|
+
"text" => COLUMN_DESCRIPTION)
|
142
|
+
column.sort_column_id = COLUMN_DESCRIPTION
|
143
|
+
treeview.append_column(column)
|
144
|
+
|
145
|
+
# column for spinner
|
146
|
+
renderer = Gtk::CellRendererSpinner.new
|
147
|
+
column = Gtk::TreeViewColumn.new("Spinning",
|
148
|
+
renderer,
|
149
|
+
"pulse" => COLUMN_PULSE,
|
150
|
+
"active" => COLUMN_ACTIVE)
|
151
|
+
column.sort_column_id = COLUMN_PULSE
|
152
|
+
treeview.append_column(column)
|
153
|
+
|
154
|
+
# column for symbolic icon
|
155
|
+
renderer = Gtk::CellRendererPixbuf.new
|
156
|
+
column = Gtk::TreeViewColumn.new("Symbolic icon",
|
157
|
+
renderer,
|
158
|
+
"icon-name" => COLUMN_ICON,
|
159
|
+
"sensitive" => COLUMN_SENSITIVE)
|
160
|
+
column.sort_column_id = COLUMN_ICON
|
161
|
+
treeview.append_column(column)
|
162
|
+
end
|
72
163
|
|
73
|
-
|
74
|
-
|
75
|
-
iter = store.append
|
76
|
-
bug.each_with_index do |value, index|
|
77
|
-
iter[index] = value
|
78
|
-
end
|
79
|
-
end
|
80
|
-
return store
|
81
|
-
end
|
164
|
+
def fixed_toggled(path_str)
|
165
|
+
path = Gtk::TreePath.new(path_str)
|
82
166
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
renderer.signal_connect('toggled') do |cell, path|
|
87
|
-
fixed_toggled(treeview.model, path)
|
88
|
-
end
|
167
|
+
# get toggled iter
|
168
|
+
iter = @model.get_iter(path)
|
169
|
+
fixed = iter[COLUMN_FIXED]
|
89
170
|
|
90
|
-
|
91
|
-
|
92
|
-
'active' => COLUMN_FIXED)
|
93
|
-
|
94
|
-
# set this column to a fixed sizing (of 50 pixels)
|
95
|
-
column.sizing = Gtk::TreeViewColumn::FIXED
|
96
|
-
column.fixed_width = 50
|
97
|
-
treeview.append_column(column)
|
98
|
-
|
99
|
-
# column for bug numbers
|
100
|
-
renderer = Gtk::CellRendererText.new
|
101
|
-
column = Gtk::TreeViewColumn.new('Bug number',
|
102
|
-
renderer,
|
103
|
-
'text' => COLUMN_NUMBER)
|
104
|
-
column.set_sort_column_id(COLUMN_NUMBER)
|
105
|
-
treeview.append_column(column)
|
106
|
-
|
107
|
-
# column for severities
|
108
|
-
renderer = Gtk::CellRendererText.new
|
109
|
-
column = Gtk::TreeViewColumn.new('Severity',
|
110
|
-
renderer,
|
111
|
-
'text' => COLUMN_SEVERITY)
|
112
|
-
column.set_sort_column_id(COLUMN_SEVERITY)
|
113
|
-
treeview.append_column(column)
|
114
|
-
|
115
|
-
# column for description
|
116
|
-
renderer = Gtk::CellRendererText.new
|
117
|
-
column = Gtk::TreeViewColumn.new('Description',
|
118
|
-
renderer,
|
119
|
-
'text' => COLUMN_DESCRIPTION)
|
120
|
-
column.set_sort_column_id(COLUMN_DESCRIPTION)
|
121
|
-
treeview.append_column(column)
|
122
|
-
end
|
171
|
+
# do something with the value
|
172
|
+
fixed ^= 1
|
123
173
|
|
124
|
-
|
125
|
-
|
174
|
+
# set new value
|
175
|
+
iter[COLUMN_FIXED] = fixed
|
176
|
+
end
|
126
177
|
|
127
|
-
|
128
|
-
|
129
|
-
|
178
|
+
def add_spinner
|
179
|
+
if @timeout.zero?
|
180
|
+
@timeout = GLib::Timeout.add(80) do
|
181
|
+
GLib::Source.remove(@timeout) unless @model
|
182
|
+
iter = @model.iter_first
|
183
|
+
pulse = iter[COLUMN_PULSE]
|
130
184
|
|
131
|
-
|
132
|
-
|
185
|
+
pulse = pulse == GLib::MAXUINT ? 0 : pulse + 1
|
186
|
+
iter[COLUMN_PULSE] = pulse
|
187
|
+
iter[COLUMN_ACTIVE] = true
|
133
188
|
|
134
|
-
|
135
|
-
|
189
|
+
true
|
190
|
+
end
|
136
191
|
end
|
137
192
|
end
|
138
193
|
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# Copyright (c) 2016 Ruby-GNOME2 Project Team
|
2
|
+
# This program is licenced under the same licence as Ruby-GNOME2.
|
3
|
+
#
|
4
|
+
=begin
|
5
|
+
= List Box
|
6
|
+
|
7
|
+
GtkListBox allows lists with complicated layouts, using
|
8
|
+
regular widgets supporting sorting and filtering.
|
9
|
+
|
10
|
+
=end
|
11
|
+
class ListboxDemo
|
12
|
+
def initialize(main_window)
|
13
|
+
@window = Gtk::Window.new(:toplevel)
|
14
|
+
@window.screen = main_window.screen
|
15
|
+
@window.title = "List Box"
|
16
|
+
@window.set_default_size(400, 600)
|
17
|
+
|
18
|
+
vbox = Gtk::Box.new(:vertical, 12)
|
19
|
+
@window.add(vbox)
|
20
|
+
label = Gtk::Label.new("Messages from Gtk+ and friends")
|
21
|
+
vbox.pack_start(label, :expand => false, :fill => false, :padding => 0)
|
22
|
+
scrolled = Gtk::ScrolledWindow.new
|
23
|
+
scrolled.set_policy(:never, :automatic)
|
24
|
+
vbox.pack_start(scrolled, :expand => true, :fill => true, :padding => 0)
|
25
|
+
|
26
|
+
listbox = Gtk::ListBox.new
|
27
|
+
scrolled.add(listbox)
|
28
|
+
|
29
|
+
listbox.set_sort_func do |a, b|
|
30
|
+
a.sort(b)
|
31
|
+
end
|
32
|
+
listbox.activate_on_single_click = false
|
33
|
+
listbox.signal_connect("row-activated", &:row_activated)
|
34
|
+
vbox.show_all
|
35
|
+
|
36
|
+
data = Gio::Resources.lookup_data("/listbox/messages.txt", 0)
|
37
|
+
data.each_line do |line|
|
38
|
+
message = Message.new(line)
|
39
|
+
row = GtkMessageRow.new(message)
|
40
|
+
row.show
|
41
|
+
listbox.add(row)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
if !@window.visible?
|
47
|
+
@window.show_all
|
48
|
+
else
|
49
|
+
@window.destroy
|
50
|
+
end
|
51
|
+
@window
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Message
|
56
|
+
attr_reader :id, :sender_name, :sender_nick, :message, :time, :reply_to,
|
57
|
+
:resent_by
|
58
|
+
attr_accessor :n_favorites, :n_reshares
|
59
|
+
|
60
|
+
def initialize(str)
|
61
|
+
strv = str.split("|")
|
62
|
+
parse(strv)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def parse(array_of_strings)
|
68
|
+
@id = array_of_strings[0].to_i
|
69
|
+
@sender_name = array_of_strings[1]
|
70
|
+
@sender_nick = array_of_strings[2]
|
71
|
+
@message = array_of_strings[3]
|
72
|
+
@time = array_of_strings[4].to_i
|
73
|
+
@reply_to = array_of_strings[5] || nil
|
74
|
+
@resent_by = array_of_strings[6] || nil
|
75
|
+
@n_favorites = array_of_strings[7] ? array_of_strings[7].to_i : nil
|
76
|
+
@n_reshares = array_of_strings[8] ? array_of_strings[8].to_i : nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class GtkMessageRow < Gtk::ListBoxRow
|
81
|
+
|
82
|
+
type_register
|
83
|
+
class << self
|
84
|
+
def init
|
85
|
+
set_template(:resource => "/listbox/listbox.ui")
|
86
|
+
bind_template_child("content_label")
|
87
|
+
bind_template_child("source_name")
|
88
|
+
bind_template_child("source_nick")
|
89
|
+
bind_template_child("short_time_label")
|
90
|
+
bind_template_child("detailed_time_label")
|
91
|
+
bind_template_child("extra_buttons_box")
|
92
|
+
bind_template_child("details_revealer")
|
93
|
+
bind_template_child("avatar_image")
|
94
|
+
bind_template_child("resent_box")
|
95
|
+
bind_template_child("resent_by_button")
|
96
|
+
bind_template_child("n_reshares_label")
|
97
|
+
bind_template_child("n_favorites_label")
|
98
|
+
bind_template_child("expand_button")
|
99
|
+
|
100
|
+
set_connect_func do |name|
|
101
|
+
method(name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def favorite_clicked(button)
|
108
|
+
row = button.parent
|
109
|
+
row = row.parent while row.class != GtkMessageRow
|
110
|
+
row.message.n_favorites += 1
|
111
|
+
row.message_row_update
|
112
|
+
end
|
113
|
+
|
114
|
+
def expand_clicked(button)
|
115
|
+
row = button.parent
|
116
|
+
row = row.parent while row.class != GtkMessageRow
|
117
|
+
row.row_expand
|
118
|
+
end
|
119
|
+
|
120
|
+
def reshare_clicked(button)
|
121
|
+
row = button.parent
|
122
|
+
row = row.parent while row.class != GtkMessageRow
|
123
|
+
row.message.n_reshares += 1
|
124
|
+
row.message_row_update
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
attr_reader :message
|
129
|
+
|
130
|
+
def initialize(message)
|
131
|
+
super()
|
132
|
+
@message = message
|
133
|
+
@avatar_pixbuf_other = GdkPixbuf::Pixbuf.new(:resource => "/listbox/apple-red.png",
|
134
|
+
:width => 32, :height => 32,
|
135
|
+
:preserve_aspect_ratio => false)
|
136
|
+
message_row_update
|
137
|
+
extra_buttons_box.hide
|
138
|
+
extra_buttons_box.visible = false
|
139
|
+
extra_buttons_box.unset_state_flags([:prelight, :selected])
|
140
|
+
set_state_flags(Gtk::StateFlags::NORMAL, false)
|
141
|
+
|
142
|
+
signal_connect "state-flags-changed" do |widget, _previous_flags|
|
143
|
+
flags = widget.state_flags
|
144
|
+
|
145
|
+
is_prelight_or_selected = flags & (Gtk::StateFlags::PRELIGHT |
|
146
|
+
Gtk::StateFlags::SELECTED)
|
147
|
+
if is_prelight_or_selected.nonzero?
|
148
|
+
widget.extra_buttons_box.visible = true
|
149
|
+
else
|
150
|
+
widget.extra_buttons_box.visible = false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def message_row_update
|
156
|
+
source_name.text = @message.sender_name
|
157
|
+
source_nick.text = @message.sender_nick
|
158
|
+
content_label.text = @message.message
|
159
|
+
short_time_label.text = Time.at(@message.time).utc.strftime("%e %b %y")
|
160
|
+
detailed_time_label.text = Time.at(@message.time).utc.strftime("%Y - %e %b %Y")
|
161
|
+
n_favorites_label.visible = @message.n_favorites.nonzero?
|
162
|
+
n_favorites_label.markup = "<b>#{@message.n_favorites}</b>\nFavorites"
|
163
|
+
n_reshares_label.visible = @message.n_reshares.nonzero?
|
164
|
+
n_reshares_label.markup = "<b>#{@message.n_reshares}</b>\nReshares"
|
165
|
+
resent_box.visible = !@message.resent_by.nil?
|
166
|
+
resent_by_button.label = @message.resent_by if @message.resent_by
|
167
|
+
if @message.sender_nick == "@GTKtoolkit"
|
168
|
+
avatar_image.set_from_icon_name("gtk3-demo", Gtk::IconSize::DND)
|
169
|
+
else
|
170
|
+
avatar_image.from_pixbuf = @avatar_pixbuf_other
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def sort(b)
|
175
|
+
@message.time - b.message.time
|
176
|
+
end
|
177
|
+
|
178
|
+
def row_expand
|
179
|
+
expand = !details_revealer.reveal_child?
|
180
|
+
details_revealer.reveal_child = expand
|
181
|
+
expand ? expand_button.label = "Hide" : expand_button.label = "Expand"
|
182
|
+
end
|
183
|
+
end
|