interphase 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/interphase.rb +14 -0
- data/lib/interphase/helpers/observable.rb +43 -0
- data/lib/interphase/widgets/basic_widgets.rb +113 -0
- data/lib/interphase/widgets/box.rb +48 -0
- data/lib/interphase/widgets/button.rb +34 -0
- data/lib/interphase/widgets/dialog.rb +78 -0
- data/lib/interphase/widgets/fixed.rb +23 -0
- data/lib/interphase/widgets/label.rb +23 -0
- data/lib/interphase/widgets/list_view.rb +47 -0
- data/lib/interphase/widgets/simple_list_view.rb +30 -0
- data/lib/interphase/widgets/status_bar.rb +30 -0
- data/lib/interphase/widgets/window.rb +56 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 601ea62e61b89deb55c6ff518e6d8340dc6c6c73
|
4
|
+
data.tar.gz: 2f3c770ff1b03e94ed2f54b9ccb2bf804d7215a4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2feefd55a3a5186c6a091479faed94f32fc313480f47ed50ccfd1239e400a57e8ef78e750243bbf458ffe90e92b6d89b4330e854d9db951506652c1382e476f9
|
7
|
+
data.tar.gz: bb4b30b3de6fdf7d45b3e30a383ffad570f6862f0a66d1d0cf133e761ae6f380b6faf9fd47aed4bb1f467254d7b6dff8e5dbfab3ed6b1e09fcba63eb3b7d3e69
|
data/lib/interphase.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'interphase/helpers/observable'
|
4
|
+
|
5
|
+
require 'interphase/widgets/basic_widgets'
|
6
|
+
require 'interphase/widgets/window'
|
7
|
+
require 'interphase/widgets/label'
|
8
|
+
require 'interphase/widgets/box'
|
9
|
+
require 'interphase/widgets/status_bar'
|
10
|
+
require 'interphase/widgets/list_view'
|
11
|
+
require 'interphase/widgets/simple_list_view'
|
12
|
+
require 'interphase/widgets/fixed'
|
13
|
+
require 'interphase/widgets/dialog'
|
14
|
+
require 'interphase/widgets/button'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Interphase
|
4
|
+
module Helpers
|
5
|
+
# An object wrapper which can invoke a method whenever the wrapped object
|
6
|
+
# changes.
|
7
|
+
# Unlike most classes, this class inherits from `BasicObject`, which has
|
8
|
+
# absolutely no methods whatsoever. This means that everything, even
|
9
|
+
# +inspect+ and +class+, fall into +Observable#method_missing+.
|
10
|
+
class Observable < BasicObject
|
11
|
+
# Wrap an object in a new instance of +Observable+.
|
12
|
+
# Takes a block which executes upon the object changing. This block is
|
13
|
+
# passed +object+ as a paremeter.
|
14
|
+
# +object+:: The object to wrap.
|
15
|
+
def initialize(object, &block)
|
16
|
+
# :: is required because we inherit BasicObject, not Object
|
17
|
+
::Kernal.raise ::ArgumentError, 'Requires a block' if block.nil?
|
18
|
+
|
19
|
+
@object = object
|
20
|
+
@on_change = block
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO responds_to?
|
24
|
+
def method_missing(name, *args, &block)
|
25
|
+
if @object.respond_to?(name)
|
26
|
+
before_hash = @object.hash
|
27
|
+
ret_val = @object.send(name, *args, &block)
|
28
|
+
after_hash = @object.hash
|
29
|
+
|
30
|
+
@on_change.call(@object) if before_hash != after_hash
|
31
|
+
|
32
|
+
ret_val
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def respond_to_missing?(*)
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# A basic GTK widget wrapper.
|
7
|
+
class Widget
|
8
|
+
attr_accessor :gtk_instance, :parent, :name
|
9
|
+
|
10
|
+
# Creates a new widget.
|
11
|
+
# +gtk_instance+:: The GTK widget instance this is wrapping.
|
12
|
+
# +name:+:: This widgets name, allowing it to be referred to after being
|
13
|
+
# created.
|
14
|
+
def initialize(gtk_instance, **options, &block)
|
15
|
+
@gtk_instance = gtk_instance
|
16
|
+
@parent = nil
|
17
|
+
@name = options[:name]
|
18
|
+
|
19
|
+
instance_eval(&block) if block_given?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Requests that this widget is resized. Note that this is a method, rather
|
23
|
+
# than a 'size=' setter, because the request is not guaranteed, and indeed
|
24
|
+
# in many cases will not. Only some containers allow their child widgets
|
25
|
+
# to be resized.
|
26
|
+
def size(width, height)
|
27
|
+
gtk_instance.set_size_request(width, height)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Shows this widget.
|
31
|
+
def show
|
32
|
+
gtk_instance.show
|
33
|
+
end
|
34
|
+
|
35
|
+
# Associates a block with a signal. The block is invoked whenever the
|
36
|
+
# signal occurs.
|
37
|
+
# +name+:: The name of the signal.
|
38
|
+
def on(name, &block)
|
39
|
+
gtk_instance.signal_connect(name, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Destroy this widget.
|
43
|
+
def destroy
|
44
|
+
gtk_instance.destroy
|
45
|
+
end
|
46
|
+
|
47
|
+
# Respond to lookups by name.
|
48
|
+
# TODO IMPLEMENT RESPONDS_TO
|
49
|
+
def method_missing(requested, *args, &block)
|
50
|
+
# If any arguments or a block have been given, then this isn't an attr
|
51
|
+
if !args.empty? || block_given?
|
52
|
+
super
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
return self if requested.to_s == name
|
57
|
+
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
def respond_to_missing?
|
62
|
+
true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# A widget which may contain other widgets.
|
67
|
+
class Container < Widget
|
68
|
+
attr_accessor :children
|
69
|
+
|
70
|
+
# Add a widget as a child of this one.
|
71
|
+
# Accepts a block which is executed on the child.
|
72
|
+
# +child+:: The new child widget.
|
73
|
+
# +should_add+:: (Optional) Whether to actually add the element, or just to
|
74
|
+
# register it as added by adding it to +children+. You
|
75
|
+
# probably shouldn't change this.
|
76
|
+
def add(child, should_add = true, &block)
|
77
|
+
child.instance_eval(&block) if block_given?
|
78
|
+
|
79
|
+
raise 'Widget already has a parent' unless child.parent.nil?
|
80
|
+
|
81
|
+
gtk_instance.add(child.gtk_instance) if should_add
|
82
|
+
child.parent = self
|
83
|
+
|
84
|
+
# Ensure a children array exists, and add the new child to it
|
85
|
+
@children ||= []
|
86
|
+
children << child
|
87
|
+
end
|
88
|
+
|
89
|
+
# Show this widget and all of its children.
|
90
|
+
def show_all
|
91
|
+
gtk_instance.show_all
|
92
|
+
end
|
93
|
+
|
94
|
+
# Allows child named widgets to be looked up like an attribute.
|
95
|
+
# TODO IMPLEMENT RESPONDS_TO
|
96
|
+
def method_missing(requested, *args, &block)
|
97
|
+
(children || []).each do |child|
|
98
|
+
# An exception simply means that wasn't the child we were looking for
|
99
|
+
begin
|
100
|
+
return child.send(requested)
|
101
|
+
rescue StandardError
|
102
|
+
next
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
super
|
107
|
+
end
|
108
|
+
|
109
|
+
def respond_to_missing?(*)
|
110
|
+
true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# A simple item container. You should use +VBox+ or +HBox+ rather than this.
|
7
|
+
class Box < Container
|
8
|
+
PACK_START = 0
|
9
|
+
PACK_END = 1
|
10
|
+
|
11
|
+
# Add a widget to the box, after all others added at the same reference.
|
12
|
+
# Accepts a block which is executed on the child.
|
13
|
+
# +child+:: The new child widget.
|
14
|
+
# +expand+:: (Optional) Allocate extra space to this widget, default +true+.
|
15
|
+
# +fill+:: (Optional) Allocate to the full width/height of the box, default
|
16
|
+
# +true+.
|
17
|
+
# +padding+:: (Optional) Any padding to allocate to this widget, default 0.
|
18
|
+
# +ref+:: (Optional) The reference at which to add the widget. Either
|
19
|
+
# +PACK_START+ (default) or +PACK_END+.
|
20
|
+
def add(child, expand = true, fill = true, padding = 0, ref = PACK_START, &block)
|
21
|
+
super(child, false, &block)
|
22
|
+
|
23
|
+
if ref == PACK_START
|
24
|
+
gtk_instance.pack_start(child.gtk_instance, expand, fill, padding)
|
25
|
+
elsif ref == PACK_END
|
26
|
+
gtk_instance.pack_end(child.gtk_instance, expand, fill, padding)
|
27
|
+
else
|
28
|
+
raise 'ref should be either PACK_START or PACK_END'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# A vertical item container.
|
34
|
+
class VBox < Box
|
35
|
+
# Creates a new vertical box.
|
36
|
+
def initialize(**options, &block)
|
37
|
+
super(Gtk::VBox.new, options, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# A horizontal item container.
|
42
|
+
class HBox < Box
|
43
|
+
# Creates a new horizontal box.
|
44
|
+
def initialize(**options, &block)
|
45
|
+
super(Gtk::HBox.new, options, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# A button which can perform an action upon being clicked.
|
7
|
+
class Button < Widget
|
8
|
+
# Create a new button.
|
9
|
+
# +label+:: The text to display on the button.
|
10
|
+
def initialize(label = '', **options, &block)
|
11
|
+
super(Gtk::Button.new(label), **options, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get the button's label text.
|
15
|
+
def label
|
16
|
+
gtk_instance.label
|
17
|
+
end
|
18
|
+
|
19
|
+
# Set the button's label text.
|
20
|
+
def label=(value)
|
21
|
+
gtk_instance.label = value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Register a block to execute upon clicking the button.
|
25
|
+
def on_click(&block)
|
26
|
+
on('clicked', &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Clicks the button, executing any blocks added using +#on_click+.
|
30
|
+
def click
|
31
|
+
gtk_instance.clicked
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# A base class representing a simple, blank dialog box.
|
7
|
+
class Dialog < Widget
|
8
|
+
# Construct a new blank dialog box.
|
9
|
+
def initialize(instance = nil, **options, &block)
|
10
|
+
super(instance || Gtk::Dialog.new, **options, &block)
|
11
|
+
|
12
|
+
options['buttons']&.map { |btn| add_button(*btn) }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Converts an +#add_button+ +action+ symbol to the GTK RESPONSE integer
|
16
|
+
# which it represents.
|
17
|
+
# +action+:: The action symbol to convert. Should be one of the valid
|
18
|
+
# values of +action+ to +#add_button+.
|
19
|
+
def action_to_integer(action)
|
20
|
+
valid_actions =
|
21
|
+
%i[none reject accept delete ok cancel close yes no apply help]
|
22
|
+
|
23
|
+
throw ArgumentError, 'Invalid button action' \
|
24
|
+
unless valid_actions.include? action
|
25
|
+
|
26
|
+
# Map :delete to its GTK equivalent
|
27
|
+
action = :delete_event if action == :delete
|
28
|
+
|
29
|
+
Gtk::Dialog.const_get("RESPONSE_#{action.to_s.upcase}")
|
30
|
+
end
|
31
|
+
|
32
|
+
# Adds a button to the dialog box.
|
33
|
+
# +text+:: The text to display on the button.
|
34
|
+
# +action+:: The action which occurs when this button is clicked. Must be
|
35
|
+
# one of: +:none+, +:reject+, +:accept+, +:delete+, +:ok+,
|
36
|
+
# +:cancel+, +:close+, +:yes+, +:no+, +:apply+, +:help+.
|
37
|
+
def add_button(text, action)
|
38
|
+
gtk_instance.add_button(text, action_to_integer(action))
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# Run this dialog box. This call will block execution until the dialog is
|
43
|
+
# closed. Consider using +Window#in_background+ if blocking is not desired.
|
44
|
+
# You should usually call +destroy+ after this method, otherwise the dialog
|
45
|
+
# will remain even after selecting an option.
|
46
|
+
def run
|
47
|
+
gtk_instance.run
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# A message dialog which displays text and some buttons.
|
52
|
+
class MessageDialog < Dialog
|
53
|
+
# Create a new message dialog.
|
54
|
+
# +message+:: The message which the dialog displays.
|
55
|
+
def initialize(message, **options, &block)
|
56
|
+
super(
|
57
|
+
Gtk::MessageDialog.new(
|
58
|
+
nil,
|
59
|
+
0,
|
60
|
+
Gtk::MessageDialog::OTHER,
|
61
|
+
Gtk::MessageDialog::BUTTONS_NONE,
|
62
|
+
message
|
63
|
+
),
|
64
|
+
options, &block
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
# A helper method which creates a new +MessageDialog+, adds an OK button,
|
69
|
+
# displays it, blocks until 'OK' is clicked, then destroys it.
|
70
|
+
# +message+:: The message which the dialog displays.
|
71
|
+
def self.show(message)
|
72
|
+
dialog = MessageDialog.new(message)
|
73
|
+
dialog.add_button('OK', :ok)
|
74
|
+
dialog.run
|
75
|
+
dialog.destroy
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# A container in which items can be placed in a specific x/y location.
|
7
|
+
class Fixed < Container
|
8
|
+
# Construct a new fixed container.
|
9
|
+
def initialize(**options, &block)
|
10
|
+
super(Gtk::Fixed.new, **options, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Add a child widget to this +Fixed+ at a location.
|
14
|
+
# +child+:: The new child widget.
|
15
|
+
# +x_pos+:: The x position.
|
16
|
+
# +y_pos+:: The y position.
|
17
|
+
def add(child, x_pos, y_pos, &block)
|
18
|
+
gtk_instance.put(child.gtk_instance, x_pos, y_pos)
|
19
|
+
|
20
|
+
super(child, false, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# A text label.
|
7
|
+
class Label < Widget
|
8
|
+
# Creates a new label.
|
9
|
+
def initialize(text = '', **options, &block)
|
10
|
+
super(Gtk::Label.new(text), options, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Set the text in this label.
|
14
|
+
def text=(value)
|
15
|
+
gtk_instance.text = value
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieve the label's text.
|
19
|
+
def text
|
20
|
+
gtk_instance.text
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
require 'interphase/helpers/observable'
|
5
|
+
|
6
|
+
module Interphase
|
7
|
+
# A list view which can be populated with objects.
|
8
|
+
class ListView < Widget
|
9
|
+
attr_reader :rows
|
10
|
+
|
11
|
+
# Create a new list view.
|
12
|
+
# +columns+:: The columns which this list view has, as an +Array+ of
|
13
|
+
# +String+ objects.
|
14
|
+
def initialize(columns, **options, &block)
|
15
|
+
@store = Gtk::ListStore.new(*[String] * columns.length)
|
16
|
+
|
17
|
+
super(Gtk::TreeView.new(@store), options, &block)
|
18
|
+
|
19
|
+
# Init columns
|
20
|
+
columns.each_with_index do |col, index|
|
21
|
+
renderer = Gtk::CellRendererText.new
|
22
|
+
new_col = Gtk::TreeViewColumn.new(col[0], renderer, text: index)
|
23
|
+
gtk_instance.append_column(new_col)
|
24
|
+
end
|
25
|
+
|
26
|
+
@rows = Interphase::Helpers::Observable.new([]) { refresh_rows }
|
27
|
+
|
28
|
+
refresh_rows
|
29
|
+
end
|
30
|
+
|
31
|
+
# Refreshes the contents of the list view according to its rows. This is
|
32
|
+
# called automatically upon mutating #rows.
|
33
|
+
def refresh_rows
|
34
|
+
@store.clear
|
35
|
+
|
36
|
+
# Insert the rows
|
37
|
+
@rows.each do |data_row|
|
38
|
+
store_row = @store.append
|
39
|
+
|
40
|
+
# Basically a memcpy
|
41
|
+
data_row.each_with_index do |item, index|
|
42
|
+
store_row[index] = item
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
require 'interphase/helpers/observable'
|
5
|
+
|
6
|
+
module Interphase
|
7
|
+
# A simple list view which displays an +Array+.
|
8
|
+
class SimpleListView < ListView
|
9
|
+
attr_reader :items
|
10
|
+
|
11
|
+
def initialize(items = [], **options, &block)
|
12
|
+
super(['Column'], options, &block)
|
13
|
+
|
14
|
+
gtk_instance.headers_visible = false
|
15
|
+
|
16
|
+
@items = Interphase::Helpers::Observable.new(items) do
|
17
|
+
refresh_items
|
18
|
+
end
|
19
|
+
|
20
|
+
refresh_items
|
21
|
+
end
|
22
|
+
|
23
|
+
# Copies #items into #rows, where each item is one row.
|
24
|
+
def refresh_items
|
25
|
+
items.each do |item|
|
26
|
+
rows << [item]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# Provides a simple status bar which can display a single message.
|
7
|
+
class SimpleStatusBar < Widget
|
8
|
+
attr_reader :text
|
9
|
+
|
10
|
+
# Create a new simple status bar.
|
11
|
+
def initialize(**options, &block)
|
12
|
+
super(Gtk::Statusbar.new, options, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sets the text displayed in the status bar.
|
16
|
+
def text=(value)
|
17
|
+
# Value is frozen to prevent modification without updating the text on the
|
18
|
+
# widget (i.e. mutation must be through this method)
|
19
|
+
@text = value.clone.freeze
|
20
|
+
|
21
|
+
begin
|
22
|
+
gtk_instance.pop(1)
|
23
|
+
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
24
|
+
# It doesn't matter; just means that there was no text previously
|
25
|
+
end
|
26
|
+
|
27
|
+
gtk_instance.push(1, text)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gtk2'
|
4
|
+
|
5
|
+
module Interphase
|
6
|
+
# An application window.
|
7
|
+
class Window < Container
|
8
|
+
# Creates a new window.
|
9
|
+
def initialize(title, **options, &block)
|
10
|
+
super(Gtk::Window.new(title), options, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# The given block will trigger when this window is closed.
|
14
|
+
def on_delete(&block)
|
15
|
+
on('delete-event', &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Registers an #on_delete block which calls #quit.
|
19
|
+
def quit_on_delete!
|
20
|
+
on_delete do
|
21
|
+
quit
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Runs the entire Interphase application.
|
26
|
+
def run
|
27
|
+
Gtk.main
|
28
|
+
end
|
29
|
+
|
30
|
+
# Quits the entire Interphase application, killing all its threads.
|
31
|
+
def quit
|
32
|
+
@threads&.each(&:kill)
|
33
|
+
Gtk.main_quit
|
34
|
+
end
|
35
|
+
|
36
|
+
# Force-quits the entire Interphase application, including the Ruby Kernel.
|
37
|
+
# If your GUI quits but your terminal stays occupied after #quit, this will
|
38
|
+
# probably solve that issue.
|
39
|
+
# Having to use this is usually the sign of a badly-written program!
|
40
|
+
def quit!
|
41
|
+
@threads&.each(&:kill)
|
42
|
+
Gtk.main_quit
|
43
|
+
exit!
|
44
|
+
end
|
45
|
+
|
46
|
+
# Binds a block to run as a +Thread+; it begins executing immediately.
|
47
|
+
# Destroying the window kills all threads.
|
48
|
+
# TOOD DOES IT?
|
49
|
+
def in_background(&block)
|
50
|
+
@threads ||= []
|
51
|
+
thread = Thread.new(&block)
|
52
|
+
thread.abort_on_exception = true
|
53
|
+
@threads << thread
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: interphase
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Christiansen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gtk2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.2.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.2'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.2.0
|
33
|
+
description:
|
34
|
+
email: aaronc20000@gmail.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- lib/interphase.rb
|
40
|
+
- lib/interphase/helpers/observable.rb
|
41
|
+
- lib/interphase/widgets/basic_widgets.rb
|
42
|
+
- lib/interphase/widgets/box.rb
|
43
|
+
- lib/interphase/widgets/button.rb
|
44
|
+
- lib/interphase/widgets/dialog.rb
|
45
|
+
- lib/interphase/widgets/fixed.rb
|
46
|
+
- lib/interphase/widgets/label.rb
|
47
|
+
- lib/interphase/widgets/list_view.rb
|
48
|
+
- lib/interphase/widgets/simple_list_view.rb
|
49
|
+
- lib/interphase/widgets/status_bar.rb
|
50
|
+
- lib/interphase/widgets/window.rb
|
51
|
+
homepage:
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 2.6.14
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: A powerful, easy-to-use, native-looking GUI library
|
75
|
+
test_files: []
|