interphase 1.0.0
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 +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: []
|