mittens_ui 0.0.15 → 0.0.17

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65ad0d43134bc7e47bcb8d797b70f275a6330426ba073f2f0861fa56a1f8f551
4
- data.tar.gz: c613e0ddc59df4efdc64a0ee5b4af846c2549e30c562352c52864bfcdc62abe2
3
+ metadata.gz: 965d4306bb231d1777baa35f4553db1fd56d9c23ff483d1e7e469dba85933029
4
+ data.tar.gz: f00541e8f1a59fe6240e307cec7d53d2afde596ec3f62385d56fa9980f8a5fe6
5
5
  SHA512:
6
- metadata.gz: 98a84d6b246ec8112a724d9c7cb1ec6b3f147e369aafa8cb8290cdc40b1359ce9bd656f6f8e83555ce5acb99387983eb7a4b6af8beb27388b7b4834c35a29d18
7
- data.tar.gz: ebda9e48f8553c48b9548d73a7778d0211a07d605e0758f107bdcca33e1877dadd07ff5132db3ca646e0070916675cb4685b150205e7cdce01305ec3a5feeb28
6
+ metadata.gz: 90288b844f09fa72f4e1aea63e564797f9ed2c82d16ed76aa4ea8debc6a12282cfc519aea6d2a99201ae58abe2fc2bfa0d033a64a1ebf532072f6daba02d4520
7
+ data.tar.gz: c4578d1b32fdc6da890c9d3ca5db4ebf03ca7f34077a0bbbe2cc97fc20597a10d240e7d34ace1dd26c4cb867ed6f998b819fc97e5da8712b40cfc9e8d9011a5d
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- ruby "4.0.0"
3
+ ruby "4.0.3"
4
4
 
5
5
  # Specify your gem's dependencies in mittens_ui.gemspec
6
6
  gemspec
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
@@ -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[:title] || 'Button'
42
- icon_type = options[:icon] || nil
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
 
@@ -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[:label] || 'Checkbox'
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[:title] || 'Pick a Color'
42
- @default = options[:default] || nil
43
- @alpha = options[:alpha] || false
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
 
@@ -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
- # (e.g. {HeaderBar}, {Notify}).
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[:title] || ''
29
- position = options[:position] || :left
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("linked")
40
+ box.add_css_class('linked')
42
41
 
43
42
  widgets.each do |w|
44
43
  w.remove
@@ -210,7 +210,7 @@ module MittensUi
210
210
 
211
211
  # value text
212
212
  cr.set_source_rgb(0.9, 0.9, 0.9)
213
- cr.set_font_size(9)
213
+ cr.set_font_size(10.4)
214
214
  text = value.to_s
215
215
  extents = cr.text_extents(text)
216
216
  cr.move_to(cx - extents.width / 2, cy + extents.height / 2)
@@ -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 <= PAGE_THRESHOLD
155
+ return @data if @data.size <= @page_threshold
153
156
 
154
- start = @current_page * PAGE_SIZE
155
- @data.slice(start, PAGE_SIZE) || []
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 <= PAGE_THRESHOLD
162
+ return if @data.size <= @page_threshold
160
163
 
161
- max_page = (@data.size / PAGE_SIZE.to_f).ceil - 1
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 <= PAGE_THRESHOLD
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 <= PAGE_THRESHOLD
179
+ return if @data.size <= @page_threshold
177
180
 
178
- @current_page = (@data.size / PAGE_SIZE.to_f).floor
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 <= PAGE_THRESHOLD
185
+ if @data.size <= @page_threshold
183
186
  @pagination_box.hide
184
187
  return
185
188
  end
186
189
 
187
- total_pages = (@data.size / PAGE_SIZE.to_f).ceil
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! { |row| row[col_idx].to_s }
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
@@ -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
  #
@@ -1,3 +1,3 @@
1
1
  module MittensUi
2
- VERSION = "0.0.15"
2
+ VERSION = "0.0.17"
3
3
  end
@@ -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
@@ -8,13 +8,13 @@ Gem::Specification.new do |spec|
8
8
  spec.licenses = ['MIT']
9
9
  spec.summary = "A tiny GUI toolkit written on top of GTK"
10
10
  spec.description = "GUI Toolkit!"
11
- spec.homepage = "https://github.com/tuttza/mittens_ui"
11
+ spec.homepage = "https://codeberg.org/tuttza/mittens_ui"
12
12
  spec.required_ruby_version = Gem::Requirement.new(">= 3.3.0")
13
13
 
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://github.com/tuttza/mittens_ui"
17
+ spec.metadata["source_code_uri"] = spec.homepage
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.15
4
+ version: 0.0.17
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
@@ -145,12 +147,12 @@ files:
145
147
  - mittens_ui.gemspec
146
148
  - notes/dev_setup.txt
147
149
  - notes/gtk.txt
148
- homepage: https://github.com/tuttza/mittens_ui
150
+ homepage: https://codeberg.org/tuttza/mittens_ui
149
151
  licenses:
150
152
  - MIT
151
153
  metadata:
152
- homepage_uri: https://github.com/tuttza/mittens_ui
153
- source_code_uri: https://github.com/tuttza/mittens_ui
154
+ homepage_uri: https://codeberg.org/tuttza/mittens_ui
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.3
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: []