mittens_ui 0.0.15 → 0.0.16
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/Gemfile +1 -1
- data/examples/hn.rb +73 -0
- data/examples/keyboard_shortcut_demo.rb +71 -0
- data/examples/mig.rb +13 -0
- data/lib/mittens_ui/button.rb +4 -2
- data/lib/mittens_ui/checkbox.rb +1 -1
- data/lib/mittens_ui/colorpicker.rb +3 -3
- data/lib/mittens_ui/core.rb +110 -2
- data/lib/mittens_ui/header_bar.rb +3 -4
- data/lib/mittens_ui/knob.rb +1 -1
- data/lib/mittens_ui/label.rb +10 -0
- data/lib/mittens_ui/table_view.rb +30 -12
- data/lib/mittens_ui/textbox.rb +9 -0
- data/lib/mittens_ui/version.rb +1 -1
- data/lib/mittens_ui/web_link.rb +8 -0
- data/mittens_ui.gemspec +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce8a7d0aa1723a2134b6364e0e6fda2c2b9cd4e91b4e05c4f4ca6e948428c643
|
|
4
|
+
data.tar.gz: 34d9f15cb0cae6dedbc33bd62a8e2a137c06323d196fb607295ddd47b66196a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3528b40c3376faf23d93874d84247cfa6bcfa4b59f932a3e6000090619aa26c7dba5a2ff617f8530ca1cb62096f97ac533a4235da5ba91479e2dc9fa2601bb9d
|
|
7
|
+
data.tar.gz: b1c75473975e722ca380dda49dba9566128bc8becae1e6937a7e02a543361b367f5eb57a7b9c6837e980c95e7fa837583ce85a20c55c076ff4c3b664789ab932
|
data/Gemfile
CHANGED
data/examples/hn.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require '../lib/mittens_ui'
|
|
7
|
+
|
|
8
|
+
class HackerNewsClient
|
|
9
|
+
BASE_URL = 'https://hacker-news.firebaseio.com/v0'
|
|
10
|
+
|
|
11
|
+
def self.get_json(path)
|
|
12
|
+
uri = URI("#{BASE_URL}/#{path}")
|
|
13
|
+
res = Net::HTTP.get_response(uri)
|
|
14
|
+
JSON.parse(res.body)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.top_story_ids
|
|
18
|
+
get_json('topstories.json')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.get_item(id)
|
|
22
|
+
get_json("item/#{id}.json")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.top_stories(limit = 20)
|
|
26
|
+
top_story_ids.first(limit).map do |id|
|
|
27
|
+
get_item(id)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.map_stories_to_rows(stories_data)
|
|
32
|
+
stories_data.map do |story|
|
|
33
|
+
url = story['url'] || "https://news.ycombinator.com/item?id=#{story['id']}"
|
|
34
|
+
|
|
35
|
+
[
|
|
36
|
+
story['title'] || 'N/A',
|
|
37
|
+
story['by'] || 'N/A',
|
|
38
|
+
story['score'] || 0,
|
|
39
|
+
url
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
MittensUi::Application.Window(
|
|
46
|
+
name: 'hn_viewer',
|
|
47
|
+
title: 'HN - Top Hacker News Stories',
|
|
48
|
+
width: 900,
|
|
49
|
+
height: 600
|
|
50
|
+
) do
|
|
51
|
+
|
|
52
|
+
stories = HackerNewsClient.top_stories(100)
|
|
53
|
+
rows = HackerNewsClient.map_stories_to_rows(stories)
|
|
54
|
+
|
|
55
|
+
top_stories_table = MittensUi::TableView.new(
|
|
56
|
+
%w[Title Author Score URL].freeze,
|
|
57
|
+
rows,
|
|
58
|
+
{ page_threshold: 20, page_size: 10 }.freeze
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
top_stories_table.row_double_clicked do |row|
|
|
62
|
+
link = MittensUi::WebLink.new('', row[3])
|
|
63
|
+
link.open_url
|
|
64
|
+
link.remove
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
MittensUi::Button.new(title: 'Refresh Stories').click do |btn|
|
|
68
|
+
btn.loading do
|
|
69
|
+
stories = HackerNewsClient.top_stories(5)
|
|
70
|
+
top_stories_table.update_data(HackerNewsClient.map_stories_to_rows(stories))
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require '../lib/mittens_ui'
|
|
2
|
+
|
|
3
|
+
app_options = {
|
|
4
|
+
name: 'shortcut_demo',
|
|
5
|
+
title: 'Keyboard Shortcut Demo',
|
|
6
|
+
height: 400,
|
|
7
|
+
width: 500,
|
|
8
|
+
can_resize: false,
|
|
9
|
+
theme: :light
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
MittensUi::Application.Window(app_options) do
|
|
13
|
+
|
|
14
|
+
press_counter = 0
|
|
15
|
+
status = MittensUi::Label.new('Press a shortcut key...', expand: true, margin: 12)
|
|
16
|
+
|
|
17
|
+
MittensUi::Separator.new(:horizontal, top: 8, bottom: 8)
|
|
18
|
+
|
|
19
|
+
d_btn = MittensUi::Button.new(title: 'Focus me → ctrl+d (instant)')
|
|
20
|
+
d_btn.keyboard_shortcut("ctrl", "d") do
|
|
21
|
+
press_counter += 1
|
|
22
|
+
status.text = "ctrl+d fired! x#{press_counter.to_s}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
MittensUi::Separator.new(:horizontal, top: 8, bottom: 8)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
s_btn = MittensUi::Button.new(title: 'Focus me → ctrl+s (2s delay)')
|
|
29
|
+
s_btn.keyboard_shortcut("ctrl", "s", timer: 2) do
|
|
30
|
+
press_counter += 1
|
|
31
|
+
status.text = "ctrl+s fired after 2s! x#{press_counter}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
MittensUi::Separator.new(:horizontal, top: 8, bottom: 8)
|
|
35
|
+
|
|
36
|
+
tb = MittensUi::Textbox.new(multiline: false, width: :full, placeholder: "write text, press alt+r to clear it!")
|
|
37
|
+
tb.keyboard_shortcut("alt", "r") do
|
|
38
|
+
tb.text = ""
|
|
39
|
+
press_counter += 1
|
|
40
|
+
status.text = "alt+r fired — text field cleared! x#{press_counter}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# can register multiple keyboard_shortcuts for the same Widget.
|
|
44
|
+
tb.keyboard_shortcut("alt", "u") do
|
|
45
|
+
tb.text = tb.text.upcase
|
|
46
|
+
press_counter += 1
|
|
47
|
+
status.text = "alt+u fired - text uppercased! x#{press_counter}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
tb.keyboard_shortcut("alt", "d") do
|
|
51
|
+
tb.text = tb.text.downcase
|
|
52
|
+
press_counter += 1
|
|
53
|
+
status.text = "alt+d fired - text downcased! x#{press_counter}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
MittensUi::Separator.new(:horizontal, top: 8, bottom: 8)
|
|
57
|
+
|
|
58
|
+
all = []
|
|
59
|
+
inspection_button = MittensUi::Button.new(title: 'Inspect Shortcuts')
|
|
60
|
+
|
|
61
|
+
inspection_button.click do
|
|
62
|
+
all = [d_btn.shortcuts, s_btn.shortcuts, tb.shortcuts].flatten
|
|
63
|
+
status.text = "Registered: #{all.join(', ')}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
inspection_button.keyboard_shortcut("ctrl", "s") do
|
|
67
|
+
status.text = "Registered: #{ all.map{ |cmd| cmd.upcase }.join(', ') }"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
MittensUi::Separator.new(:horizontal, top: 8, bottom: 8)
|
|
71
|
+
end
|
data/examples/mig.rb
CHANGED
|
@@ -109,4 +109,17 @@ MittensUi::Application.Window(app_options) do
|
|
|
109
109
|
MittensUi::Separator.new(:horizontal, top: 10, bottom: 100)
|
|
110
110
|
MittensUi::RadioButton.new({ options: %w[Red Green Blue], layout: :horizontal, bottom: 50 })
|
|
111
111
|
|
|
112
|
+
MittensUi::Separator.new(:horizontal, top: 10, bottom: 10)
|
|
113
|
+
|
|
114
|
+
status = MittensUi::Label.new('Press a shortcut key...', expand: true, margin: 12)
|
|
115
|
+
|
|
116
|
+
MittensUi::Separator.new(:horizontal, top: 8, bottom: 8)
|
|
117
|
+
|
|
118
|
+
# Ctrl+D fires instantly on the button
|
|
119
|
+
d_btn = MittensUi::Button.new(title: 'Focus me → Ctrl+D (instant)')
|
|
120
|
+
d_btn.keyboard_shortcut("ctrl", "d") do
|
|
121
|
+
status.text = "Ctrl+D fired!"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
112
125
|
end
|
data/lib/mittens_ui/button.rb
CHANGED
|
@@ -38,8 +38,8 @@ module MittensUi
|
|
|
38
38
|
# @option options [Symbol] :width (:full) column width in the layout grid
|
|
39
39
|
# @option options [Boolean] :defer_render (false) skip auto-rendering into layout
|
|
40
40
|
def initialize(options = {})
|
|
41
|
-
button_title = options
|
|
42
|
-
icon_type = options
|
|
41
|
+
button_title = options.fetch(:title, 'Button')
|
|
42
|
+
icon_type = options.fetch(:icon, nil)
|
|
43
43
|
|
|
44
44
|
@loading = false
|
|
45
45
|
@button = Gtk::Button.new
|
|
@@ -53,7 +53,9 @@ module MittensUi
|
|
|
53
53
|
|
|
54
54
|
@label = Gtk::Label.new(button_title)
|
|
55
55
|
@box.append(@label)
|
|
56
|
+
@box.set_halign(:center)
|
|
56
57
|
@box.append(@spinner)
|
|
58
|
+
|
|
57
59
|
@button.set_child(@box)
|
|
58
60
|
@spinner.hide
|
|
59
61
|
|
data/lib/mittens_ui/checkbox.rb
CHANGED
|
@@ -24,7 +24,7 @@ module MittensUi
|
|
|
24
24
|
# @option options [Symbol] :width (:full) column width in the layout grid
|
|
25
25
|
# @option options [Boolean] :defer_render (false) skip auto-rendering into layout
|
|
26
26
|
def initialize(options = {})
|
|
27
|
-
label = options
|
|
27
|
+
label = options.fetch(:label, 'Checkbox')
|
|
28
28
|
@value = nil
|
|
29
29
|
@checkbox = Gtk::CheckButton.new
|
|
30
30
|
@checkbox.set_label(label.to_s)
|
|
@@ -38,9 +38,9 @@ module MittensUi
|
|
|
38
38
|
# @yield [picker] called only if the user selected a color
|
|
39
39
|
# @yieldparam picker [MittensUi::ColorPicker] the picker with color data
|
|
40
40
|
def initialize(options = {}, &block)
|
|
41
|
-
@title = options
|
|
42
|
-
@default = options
|
|
43
|
-
@alpha = options
|
|
41
|
+
@title = options.fetch(:title, 'Pick a Color')
|
|
42
|
+
@default = options.fetch(:default, nil)
|
|
43
|
+
@alpha = options.fetch(:alpha, false)
|
|
44
44
|
@selected = false
|
|
45
45
|
@color = nil
|
|
46
46
|
|
data/lib/mittens_ui/core.rb
CHANGED
|
@@ -49,11 +49,13 @@ module MittensUi
|
|
|
49
49
|
# @option options [Integer] :bottom bottom margin in pixels
|
|
50
50
|
# @option options [Integer] :right right margin in pixels
|
|
51
51
|
def initialize(widget, options = {})
|
|
52
|
-
@core_widget = widget
|
|
52
|
+
@core_widget = widget # This represents the GTK widget.
|
|
53
|
+
@core_widget.focusable = true
|
|
53
54
|
@width = options[:width] || :full
|
|
54
55
|
@defer_render = options[:defer_render] || false
|
|
55
56
|
set_margin_from_opts_for(@core_widget, options)
|
|
56
57
|
render unless @defer_render
|
|
58
|
+
enable_hover_focus
|
|
57
59
|
end
|
|
58
60
|
|
|
59
61
|
# Shows the widget if it is hidden.
|
|
@@ -108,7 +110,7 @@ module MittensUi
|
|
|
108
110
|
# Adds the widget to the application layout grid.
|
|
109
111
|
# Called automatically during initialization unless +:defer_render+ is true.
|
|
110
112
|
# Can be overridden in subclasses that require special placement
|
|
111
|
-
# (
|
|
113
|
+
# ({HeaderBar}, {Notify}).
|
|
112
114
|
#
|
|
113
115
|
# @return [void]
|
|
114
116
|
def render
|
|
@@ -119,5 +121,111 @@ module MittensUi
|
|
|
119
121
|
MittensUi::Application.layout.add(@core_widget, width: @width)
|
|
120
122
|
end
|
|
121
123
|
end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# Registers a simple keyboard shortcut on +@core_wiget+ using a modifier + key combination.
|
|
127
|
+
#
|
|
128
|
+
# Attaches a +Gtk::EventControllerKey+ to the widget that listens for the given
|
|
129
|
+
# key combination. The widget must have focus for the shortcut to fire. If a
|
|
130
|
+
# +timer+ is provided, the block is executed after the specified delay via
|
|
131
|
+
# +GLib::Timeout+.
|
|
132
|
+
#
|
|
133
|
+
# @param modifier [String] The modifier key. Accepts "ctrl", "shift", "alt", or "super".
|
|
134
|
+
# @param key [String] The key name as a GTK key string ("d", "s", "Return", "Escape").
|
|
135
|
+
# @param timer [Integer] Seconds to wait before invoking the block. Defaults to 0 (immediate).
|
|
136
|
+
# @param block [Proc] The block to execute when the shortcut is triggered.
|
|
137
|
+
#
|
|
138
|
+
# @example Instant shortcut
|
|
139
|
+
# btn.keyboard_shortcut("ctrl", "d") { puts "Ctrl+D fired" }
|
|
140
|
+
#
|
|
141
|
+
# @example Delayed shortcut
|
|
142
|
+
# btn.keyboard_shortcut("ctrl", "s", timer: 2) { puts "fired after 2s" }
|
|
143
|
+
#
|
|
144
|
+
# @return [void]
|
|
145
|
+
def keyboard_shortcut(modifier, key, timer: 0, &block)
|
|
146
|
+
@shortcut_controllers ||= []
|
|
147
|
+
|
|
148
|
+
controller = Gtk::EventControllerKey.new
|
|
149
|
+
|
|
150
|
+
controller.signal_connect("key-pressed") do |_ctrl, keyval, _keycode, state|
|
|
151
|
+
mod_match = case modifier.to_s.downcase
|
|
152
|
+
when "ctrl" then (state & Gdk::ModifierType::CONTROL_MASK).nonzero?
|
|
153
|
+
when "shift" then (state & Gdk::ModifierType::SHIFT_MASK).nonzero?
|
|
154
|
+
when "alt" then (state & Gdk::ModifierType::ALT_MASK).nonzero?
|
|
155
|
+
when "super" then (state & Gdk::ModifierType::SUPER_MASK).nonzero?
|
|
156
|
+
else false
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
key_match = (keyval == Gdk::Keyval.from_name(key))
|
|
160
|
+
|
|
161
|
+
if mod_match && key_match
|
|
162
|
+
if timer > 0
|
|
163
|
+
GLib::Timeout.add(timer * 1000) do
|
|
164
|
+
block.call
|
|
165
|
+
GLib::Source::REMOVE
|
|
166
|
+
end
|
|
167
|
+
else
|
|
168
|
+
block.call
|
|
169
|
+
end
|
|
170
|
+
true # consume the event
|
|
171
|
+
else
|
|
172
|
+
false
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
@shortcut_controllers << { modifier: modifier, key: key, controller: controller }
|
|
177
|
+
@core_widget.add_controller(controller)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Removes a previously registered keyboard shortcut from +@core_widget+.
|
|
181
|
+
#
|
|
182
|
+
# Finds the shortcut matching the given +modifier+ and +key+ combination,
|
|
183
|
+
# detaches its +Gtk::EventControllerKey+ from the underlying GTK widget.
|
|
184
|
+
#
|
|
185
|
+
# If no matching shortcut is found, this is a no-op.
|
|
186
|
+
#
|
|
187
|
+
# @param modifier [String] The modifier key used when registering the shortcut ("ctrl").
|
|
188
|
+
# @param key [String] The key name used when registering the shortcut ("d").
|
|
189
|
+
#
|
|
190
|
+
# @example
|
|
191
|
+
# btn.remove_shortcut("ctrl", "d")
|
|
192
|
+
#
|
|
193
|
+
# @return [void]
|
|
194
|
+
def remove_keyboard_shortcut(modifier, key)
|
|
195
|
+
@shortcut_controllers&.reject! do |entry|
|
|
196
|
+
if entry[:modifier] == modifier && entry[:key] == key
|
|
197
|
+
@gtk_widget.remove_controller(entry[:controller])
|
|
198
|
+
true
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Returns a list of all keyboard shortcuts registered on +@core_wiget+.
|
|
204
|
+
#
|
|
205
|
+
# Each shortcut is represented as a human-readable string in the format
|
|
206
|
+
# "modifier+key" ("ctrl+d", "alt+r").
|
|
207
|
+
#
|
|
208
|
+
# @example
|
|
209
|
+
# btn.shortcuts # => ["ctrl+d", "ctrl+s"]
|
|
210
|
+
#
|
|
211
|
+
# @return [Array<String>] Registered shortcuts, or an empty array if none.
|
|
212
|
+
def shortcuts
|
|
213
|
+
@shortcut_controllers&.map { |e| "#{e[:modifier]}+#{e[:key]}" } || []
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
private
|
|
217
|
+
|
|
218
|
+
# Grants focus to the +@core_wiget+ when the mouse pointer enters it.
|
|
219
|
+
#
|
|
220
|
+
# Attaches a +Gtk::EventControllerMotion+ and sets +focusable+ to +true+,
|
|
221
|
+
# which is required for +grab_focus+ to work with GTK4 wigets.
|
|
222
|
+
#
|
|
223
|
+
# @return [void]
|
|
224
|
+
def enable_hover_focus
|
|
225
|
+
@core_widget.focusable = true
|
|
226
|
+
motion = Gtk::EventControllerMotion.new
|
|
227
|
+
motion.signal_connect("enter") { @core_widget.grab_focus }
|
|
228
|
+
@core_widget.add_controller(motion)
|
|
229
|
+
end
|
|
122
230
|
end
|
|
123
231
|
end
|
|
@@ -25,8 +25,8 @@ module MittensUi
|
|
|
25
25
|
# Accepted values are +:left+ and +:right+
|
|
26
26
|
# @option options [Boolean] :defer_render (false) skip auto-rendering into layout
|
|
27
27
|
def initialize(widgets, options = {})
|
|
28
|
-
title = options
|
|
29
|
-
position = options
|
|
28
|
+
title = options.fetch(:title, '')
|
|
29
|
+
position = options.fetch(:position, :left)
|
|
30
30
|
|
|
31
31
|
@header = Gtk::HeaderBar.new
|
|
32
32
|
|
|
@@ -36,9 +36,8 @@ module MittensUi
|
|
|
36
36
|
title_label = Gtk::Label.new(title)
|
|
37
37
|
@header.title_widget = title_label
|
|
38
38
|
|
|
39
|
-
|
|
40
39
|
box = Gtk::Box.new(:horizontal, 0)
|
|
41
|
-
box.add_css_class(
|
|
40
|
+
box.add_css_class('linked')
|
|
42
41
|
|
|
43
42
|
widgets.each do |w|
|
|
44
43
|
w.remove
|
data/lib/mittens_ui/knob.rb
CHANGED
data/lib/mittens_ui/label.rb
CHANGED
|
@@ -32,5 +32,15 @@ module MittensUi
|
|
|
32
32
|
gtk_label = Gtk::Label.new(text)
|
|
33
33
|
super(gtk_label, options)
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
# @return [String] returns the current label text.
|
|
37
|
+
def text
|
|
38
|
+
@core_widget.label
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @param value [String] A String value that the label gets set to
|
|
42
|
+
def text=(value)
|
|
43
|
+
@core_widget.set_label(value.to_s)
|
|
44
|
+
end
|
|
35
45
|
end
|
|
36
46
|
end
|
|
@@ -23,7 +23,7 @@ module MittensUi
|
|
|
23
23
|
# table.add(['Jane', 'jane@example.com'])
|
|
24
24
|
#
|
|
25
25
|
# @example Pagination (automatic)
|
|
26
|
-
# # Pagination UI appears automatically when data > 500 rows
|
|
26
|
+
# # Pagination UI appears automatically when data > 500 rows, unless you change it by using options hash.
|
|
27
27
|
#
|
|
28
28
|
class TableView < Core
|
|
29
29
|
attr_reader :data, :headers, :selected_row_idx
|
|
@@ -41,6 +41,9 @@ module MittensUi
|
|
|
41
41
|
@sort_directions = {}
|
|
42
42
|
@current_page = 0
|
|
43
43
|
|
|
44
|
+
@page_threshold = options.fetch(:page_threshold, PAGE_THRESHOLD)
|
|
45
|
+
@page_size = options.fetch(:page_size, PAGE_SIZE)
|
|
46
|
+
|
|
44
47
|
# ---------------------------
|
|
45
48
|
# GTK Structure
|
|
46
49
|
# ---------------------------
|
|
@@ -149,23 +152,23 @@ module MittensUi
|
|
|
149
152
|
# ---------------------------
|
|
150
153
|
|
|
151
154
|
def paginated_data
|
|
152
|
-
return @data if @data.size <=
|
|
155
|
+
return @data if @data.size <= @page_threshold
|
|
153
156
|
|
|
154
|
-
start = @current_page *
|
|
155
|
-
@data.slice(start,
|
|
157
|
+
start = @current_page * @page_size
|
|
158
|
+
@data.slice(start, @page_size) || []
|
|
156
159
|
end
|
|
157
160
|
|
|
158
161
|
def next_page
|
|
159
|
-
return if @data.size <=
|
|
162
|
+
return if @data.size <= @page_threshold
|
|
160
163
|
|
|
161
|
-
max_page = (@data.size /
|
|
164
|
+
max_page = (@data.size / @page_size.to_f).ceil - 1
|
|
162
165
|
@current_page = [@current_page + 1, max_page].min
|
|
163
166
|
render_rows
|
|
164
167
|
update_pagination_ui
|
|
165
168
|
end
|
|
166
169
|
|
|
167
170
|
def prev_page
|
|
168
|
-
return if @data.size <=
|
|
171
|
+
return if @data.size <= @page_threshold
|
|
169
172
|
|
|
170
173
|
@current_page = [@current_page - 1, 0].max
|
|
171
174
|
render_rows
|
|
@@ -173,18 +176,18 @@ module MittensUi
|
|
|
173
176
|
end
|
|
174
177
|
|
|
175
178
|
def adjust_page_after_insert
|
|
176
|
-
return if @data.size <=
|
|
179
|
+
return if @data.size <= @page_threshold
|
|
177
180
|
|
|
178
|
-
@current_page = (@data.size /
|
|
181
|
+
@current_page = (@data.size / @page_size.to_f).floor
|
|
179
182
|
end
|
|
180
183
|
|
|
181
184
|
def update_pagination_ui
|
|
182
|
-
if @data.size <=
|
|
185
|
+
if @data.size <= @page_threshold
|
|
183
186
|
@pagination_box.hide
|
|
184
187
|
return
|
|
185
188
|
end
|
|
186
189
|
|
|
187
|
-
total_pages = (@data.size /
|
|
190
|
+
total_pages = (@data.size / @page_size.to_f).ceil
|
|
188
191
|
@page_label.set_label("#{@current_page + 1} / #{total_pages}")
|
|
189
192
|
|
|
190
193
|
@prev_btn.set_sensitive(@current_page > 0)
|
|
@@ -338,7 +341,22 @@ module MittensUi
|
|
|
338
341
|
arrow = dir == :asc ? ' ▲' : ' ▼'
|
|
339
342
|
@header_labels[col_idx].set_label(@headers[col_idx] + arrow)
|
|
340
343
|
|
|
341
|
-
@data.sort_by!
|
|
344
|
+
@data.sort_by! do |row|
|
|
345
|
+
val = row[col_idx]
|
|
346
|
+
|
|
347
|
+
case val
|
|
348
|
+
when Integer
|
|
349
|
+
val
|
|
350
|
+
when Float
|
|
351
|
+
val
|
|
352
|
+
when String
|
|
353
|
+
# try numeric string first
|
|
354
|
+
Integer(val) rescue Float(val) rescue val.downcase
|
|
355
|
+
else
|
|
356
|
+
val.to_s
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
342
360
|
@data.reverse! if dir == :desc
|
|
343
361
|
|
|
344
362
|
render_rows
|
data/lib/mittens_ui/textbox.rb
CHANGED
|
@@ -69,6 +69,15 @@ module MittensUi
|
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
+
# @param value [String] A String value that the label gets set to
|
|
73
|
+
def text=(value)
|
|
74
|
+
if @multiline
|
|
75
|
+
@text_buffer.text = value.to_s
|
|
76
|
+
else
|
|
77
|
+
@textbox.text = value.to_s
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
72
81
|
# Clears all text from the widget.
|
|
73
82
|
# Works in both single-line and multiline mode.
|
|
74
83
|
#
|
data/lib/mittens_ui/version.rb
CHANGED
data/lib/mittens_ui/web_link.rb
CHANGED
|
@@ -43,5 +43,13 @@ module MittensUi
|
|
|
43
43
|
@web_link = Gtk::LinkButton.new(@url, @name)
|
|
44
44
|
super(@web_link, options)
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
# Opens the set @url link in a web browser.
|
|
48
|
+
#
|
|
49
|
+
# @return [void]
|
|
50
|
+
def open_url
|
|
51
|
+
launcher = Gtk::UriLauncher.new(@url)
|
|
52
|
+
launcher.launch
|
|
53
|
+
end
|
|
46
54
|
end
|
|
47
55
|
end
|
data/mittens_ui.gemspec
CHANGED
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
#spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
|
15
15
|
|
|
16
16
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
17
|
-
spec.metadata["source_code_uri"] = "https://
|
|
17
|
+
spec.metadata["source_code_uri"] = "https://codeberg.org/tuttza/mittens_ui"
|
|
18
18
|
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
|
19
19
|
|
|
20
20
|
# Specify which files should be added to the gem when it is released.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mittens_ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Zach Tuttle
|
|
@@ -112,6 +112,8 @@ files:
|
|
|
112
112
|
- examples/assets/gnome_logo.png
|
|
113
113
|
- examples/assets/mittens_ui_preview.gif
|
|
114
114
|
- examples/contacts.rb
|
|
115
|
+
- examples/hn.rb
|
|
116
|
+
- examples/keyboard_shortcut_demo.rb
|
|
115
117
|
- examples/mig.rb
|
|
116
118
|
- lib/mittens_ui.rb
|
|
117
119
|
- lib/mittens_ui/alert.rb
|
|
@@ -150,7 +152,7 @@ licenses:
|
|
|
150
152
|
- MIT
|
|
151
153
|
metadata:
|
|
152
154
|
homepage_uri: https://github.com/tuttza/mittens_ui
|
|
153
|
-
source_code_uri: https://
|
|
155
|
+
source_code_uri: https://codeberg.org/tuttza/mittens_ui
|
|
154
156
|
rdoc_options: []
|
|
155
157
|
require_paths:
|
|
156
158
|
- lib
|
|
@@ -165,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
165
167
|
- !ruby/object:Gem::Version
|
|
166
168
|
version: '0'
|
|
167
169
|
requirements: []
|
|
168
|
-
rubygems_version: 4.0.
|
|
170
|
+
rubygems_version: 4.0.6
|
|
169
171
|
specification_version: 4
|
|
170
172
|
summary: A tiny GUI toolkit written on top of GTK
|
|
171
173
|
test_files: []
|