sirens 0.0.1

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/lib/components/component.rb +46 -0
  3. data/lib/components/component_behaviour.rb +160 -0
  4. data/lib/components/containers/splitter.rb +98 -0
  5. data/lib/components/containers/stack.rb +42 -0
  6. data/lib/components/containers/tabs.rb +24 -0
  7. data/lib/components/containers/window.rb +20 -0
  8. data/lib/components/primitive_component.rb +155 -0
  9. data/lib/components/widgets/button.rb +16 -0
  10. data/lib/components/widgets/checkbox.rb +39 -0
  11. data/lib/components/widgets/column_props.rb +23 -0
  12. data/lib/components/widgets/input_text.rb +27 -0
  13. data/lib/components/widgets/list.rb +68 -0
  14. data/lib/components/widgets/list_choice.rb +89 -0
  15. data/lib/components/widgets/radio_button.rb +33 -0
  16. data/lib/components/widgets/text.rb +31 -0
  17. data/lib/components/widgets/tree_choice.rb +82 -0
  18. data/lib/layouts/columns_builder.rb +63 -0
  19. data/lib/layouts/layout_builder.rb +203 -0
  20. data/lib/layouts/radio_button_group_builder.rb +28 -0
  21. data/lib/models/choice_model.rb +41 -0
  22. data/lib/models/list_model.rb +173 -0
  23. data/lib/models/tree_choice_model.rb +102 -0
  24. data/lib/models/value_model.rb +56 -0
  25. data/lib/models/virtual_tree_model.rb +150 -0
  26. data/lib/sirens/browsers/module_browser.rb +67 -0
  27. data/lib/sirens/browsers/object_browser.rb +103 -0
  28. data/lib/sirens/components/ancestors_list.rb +22 -0
  29. data/lib/sirens/components/class_browser.rb +38 -0
  30. data/lib/sirens/components/constants_list.rb +22 -0
  31. data/lib/sirens/components/method_source_code.rb +22 -0
  32. data/lib/sirens/components/methods_list.rb +63 -0
  33. data/lib/sirens/components/modules_list.rb +23 -0
  34. data/lib/sirens/components/namespaces_list.rb +21 -0
  35. data/lib/sirens/models/constant_model.rb +21 -0
  36. data/lib/sirens/models/method_model.rb +111 -0
  37. data/lib/sirens/models/module_browser_model.rb +225 -0
  38. data/lib/sirens/models/object_browser_model.rb +125 -0
  39. data/lib/sirens.rb +90 -0
  40. data/lib/views/button_view.rb +56 -0
  41. data/lib/views/check_button_view.rb +65 -0
  42. data/lib/views/entry_view.rb +25 -0
  43. data/lib/views/list_view.rb +230 -0
  44. data/lib/views/menu_view.rb +46 -0
  45. data/lib/views/notebook_view.rb +27 -0
  46. data/lib/views/paned_view.rb +26 -0
  47. data/lib/views/radio_button_view.rb +67 -0
  48. data/lib/views/stack_view.rb +26 -0
  49. data/lib/views/text_view.rb +112 -0
  50. data/lib/views/tree_view.rb +314 -0
  51. data/lib/views/view.rb +206 -0
  52. data/lib/views/window_view.rb +51 -0
  53. metadata +110 -0
data/lib/sirens.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'gtk3'
2
+
3
+ module Sirens
4
+ class << self
5
+ def browse(object: nil, klass: nil)
6
+ if ! klass.nil?
7
+ klass = klass.class if ! klass.kind_of?(Module)
8
+
9
+ Sirens::ModuleBrowser.open_on(klass: klass)
10
+ else
11
+ ObjectBrowser.open_on(object: object)
12
+ end
13
+
14
+ Gtk.main if @opened_windows == 1
15
+ end
16
+
17
+ def register_window()
18
+ @opened_windows = 0 if @opened_windows.nil?
19
+
20
+ @opened_windows += 1
21
+ end
22
+
23
+ def unregister_window()
24
+ @opened_windows -= 1
25
+
26
+ Gtk.main_quit if @opened_windows == 0
27
+ end
28
+ end
29
+
30
+ # Models
31
+ autoload(:ValueModel, 'models/value_model.rb')
32
+ autoload(:ListModel, 'models/list_model.rb')
33
+ autoload(:VirtualTreeModel, 'models/virtual_tree_model.rb')
34
+ autoload(:ChoiceModel, 'models/choice_model.rb')
35
+ autoload(:TreeChoiceModel, 'models/tree_choice_model.rb')
36
+
37
+ # Components
38
+ autoload(:ComponentBehaviour, 'components/component_behaviour.rb')
39
+ autoload(:Component, 'components/component.rb')
40
+ autoload(:PrimitiveComponent, 'components/primitive_component.rb')
41
+ autoload(:Window, 'components/containers/window.rb')
42
+ autoload(:Stack, 'components/containers/stack.rb')
43
+ autoload(:Splitter, 'components/containers/splitter.rb')
44
+ autoload(:Tabs, 'components/containers/tabs.rb')
45
+ autoload(:Button, 'components/widgets/button.rb')
46
+ autoload(:Checkbox, 'components/widgets/checkbox.rb')
47
+ autoload(:RadioButton, 'components/widgets/radio_button.rb')
48
+ autoload(:ColumnProps, 'components/widgets/column_props.rb')
49
+ autoload(:List, 'components/widgets/list.rb')
50
+ autoload(:ListChoice, 'components/widgets/list_choice.rb')
51
+ autoload(:InputText, 'components/widgets/input_text.rb')
52
+ autoload(:Text, 'components/widgets/text.rb')
53
+ autoload(:TreeChoice, 'components/widgets/tree_choice.rb')
54
+
55
+ # Layouts
56
+ autoload(:LayoutBuilder, 'layouts/layout_builder.rb')
57
+ autoload(:ColumnsBuilder, 'layouts/columns_builder.rb')
58
+ autoload(:RadioButtonGroupBuilder, 'layouts/radio_button_group_builder.rb')
59
+
60
+ # Views
61
+ autoload(:View, 'views/view.rb')
62
+ autoload(:MenuView, 'views/menu_view.rb')
63
+ autoload(:WindowView, 'views/window_view.rb')
64
+ autoload(:StackView, 'views/stack_view.rb')
65
+ autoload(:PanedView, 'views/paned_view.rb')
66
+ autoload(:NotebookView, 'views/notebook_view.rb')
67
+ autoload(:ButtonView, 'views/button_view.rb')
68
+ autoload(:CheckButtonView, 'views/check_button_view.rb')
69
+ autoload(:RadioButtonView, 'views/radio_button_view.rb')
70
+ autoload(:ListView, 'views/list_view.rb')
71
+ autoload(:EntryView, 'views/entry_view.rb')
72
+ autoload(:TextView, 'views/text_view.rb')
73
+ autoload(:TreeView, 'views/tree_view.rb')
74
+
75
+ autoload(:ModuleBrowserModel, 'sirens/models/module_browser_model.rb')
76
+ autoload(:MethodModel, 'sirens/models/method_model.rb')
77
+ autoload(:ConstantModel, 'sirens/models/constant_model.rb')
78
+ autoload(:ObjectBrowserModel, 'sirens/models/object_browser_model.rb')
79
+
80
+ autoload(:ModuleBrowser, 'sirens/browsers/module_browser.rb')
81
+ autoload(:ObjectBrowser, 'sirens/browsers/object_browser.rb')
82
+
83
+ autoload(:NamespacesList, 'sirens/components/namespaces_list.rb')
84
+ autoload(:ModulesList, 'sirens/components/modules_list.rb')
85
+ autoload(:ClassBrowser, 'sirens/components/class_browser.rb')
86
+ autoload(:AncestorsList, 'sirens/components/ancestors_list.rb')
87
+ autoload(:MethodsList, 'sirens/components/methods_list.rb')
88
+ autoload(:ConstantsList, 'sirens/components/constants_list.rb')
89
+ autoload(:MethodSourceCode, 'sirens/components/method_source_code.rb')
90
+ end
@@ -0,0 +1,56 @@
1
+ module Sirens
2
+ class ButtonView < View
3
+
4
+ # Class methods
5
+
6
+ class << self
7
+ ##
8
+ # Answer the styles accepted by this view.
9
+ #
10
+ def view_accepted_styles()
11
+ super() + [:label, :on_clicked].freeze
12
+ end
13
+ end
14
+
15
+ # Initializing
16
+
17
+ def initialize_handles()
18
+ @main_handle = Gtk::Button.new()
19
+ @on_clicked = nil
20
+ end
21
+
22
+ def subscribe_to_ui_events()
23
+ main_handle.signal_connect('clicked') {
24
+ on_clicked
25
+ }
26
+ end
27
+
28
+ # Styles
29
+
30
+ def label=(value)
31
+ main_handle.label = value
32
+ end
33
+
34
+ def label()
35
+ main_handle.label
36
+ end
37
+
38
+ # Actions
39
+
40
+ def click()
41
+ main_handle.clicked
42
+ end
43
+
44
+ # Handlers
45
+
46
+ def on_clicked=(block)
47
+ @on_clicked = block
48
+ end
49
+
50
+ # Events
51
+
52
+ def on_clicked()
53
+ @on_clicked.call(self) unless @on_clicked.nil?
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,65 @@
1
+ module Sirens
2
+ class CheckButtonView < View
3
+
4
+ # Class methods
5
+
6
+ class << self
7
+ ##
8
+ # Answer the styles accepted by this view.
9
+ #
10
+ def view_accepted_styles()
11
+ super() + [:label].freeze
12
+ end
13
+ end
14
+
15
+ # Initializing
16
+
17
+ def initialize(on_toggled:)
18
+ super()
19
+
20
+ @on_toggled_block = on_toggled
21
+ end
22
+
23
+ def initialize_handles()
24
+ @main_handle = Gtk::CheckButton.new()
25
+ end
26
+
27
+ def subscribe_to_ui_events()
28
+ main_handle.signal_connect('clicked') {
29
+ on_toggled
30
+ }
31
+ end
32
+
33
+ # Styles
34
+
35
+ def label=(value)
36
+ main_handle.label = value
37
+ end
38
+
39
+ def label()
40
+ main_handle.label
41
+ end
42
+
43
+ # Actions
44
+
45
+ def click()
46
+ main_handle.clicked
47
+ end
48
+
49
+ # Querying
50
+
51
+ def get_value()
52
+ main_handle.active?
53
+ end
54
+
55
+ def set_value(boolean)
56
+ main_handle.active = boolean
57
+ end
58
+
59
+ # Events
60
+
61
+ def on_toggled()
62
+ @on_toggled_block.call(state: get_value)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ module Sirens
2
+ class EntryView < View
3
+
4
+ # Initializing
5
+
6
+ def initialize_handles()
7
+ @main_handle = Gtk::Entry.new
8
+ end
9
+
10
+ def subscribe_to_ui_events()
11
+ end
12
+
13
+ # Accessing
14
+
15
+ def text()
16
+ main_handle.buffer.text
17
+ end
18
+
19
+ def set_text(text)
20
+ text = '' if text.nil?
21
+
22
+ main_handle.buffer.text = text
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,230 @@
1
+ module Sirens
2
+ class ListView < View
3
+
4
+ # Class methods
5
+
6
+ class << self
7
+ ##
8
+ # Answer the styles accepted by this view.
9
+ #
10
+ def view_accepted_styles()
11
+ super() + [:show_headers, :clickable_headers].freeze
12
+ end
13
+ end
14
+
15
+ # Initializing
16
+
17
+ def initialize_handles()
18
+ @tree_view = Gtk::TreeView.new()
19
+ @tree_view.set_model(Gtk::ListStore.new(String))
20
+
21
+ @main_handle = Gtk::ScrolledWindow.new
22
+ @main_handle.add(tree_view)
23
+ @main_handle.set_policy(:automatic, :automatic)
24
+
25
+ @current_selection_indices = []
26
+
27
+ @columns_props = []
28
+
29
+ @on_selection_changed = nil
30
+ end
31
+
32
+ # Configuring callbacks
33
+
34
+ def on_selection_changed_block(&block)
35
+ @on_selection_changed_block = block
36
+
37
+ self
38
+ end
39
+
40
+ def get_item_block(&block)
41
+ @get_item_block = block
42
+
43
+ self
44
+ end
45
+
46
+ # Building columns
47
+
48
+ def define_columns(columns_props_array)
49
+ @columns_props = columns_props_array
50
+
51
+ list_store_types = @columns_props
52
+ .collect { |each_column_props| each_column_props.fetch(:type, :text) }
53
+ .collect { |type| String }
54
+
55
+ tree_view.set_model(Gtk::ListStore.new(*list_store_types))
56
+
57
+ @columns_props.each do |each_column_props|
58
+ add_column_with_props(each_column_props)
59
+ end
60
+ end
61
+
62
+ def add_column_with_props(props)
63
+ column_type = props.fetch(:type, :text)
64
+ column_index = tree_view.columns.size
65
+
66
+ renderer = Gtk::CellRendererText.new
67
+
68
+ col = Gtk::TreeViewColumn.new(props[:label], renderer, column_type => column_index)
69
+
70
+ tree_view.append_column(col)
71
+ end
72
+
73
+ # Hooking GUI signals
74
+
75
+ def subscribe_to_ui_events()
76
+ tree_view.selection.signal_connect('changed') { |tree_selection|
77
+ on_selection_changed(tree_selection)
78
+ }
79
+
80
+ tree_view.signal_connect('row-activated') {
81
+ @on_selection_action.call(self) unless @on_selection_action.nil?
82
+ }
83
+ end
84
+
85
+ # Accessing
86
+
87
+ def list_store()
88
+ tree_view.model
89
+ end
90
+
91
+ def tree_view()
92
+ @tree_view
93
+ end
94
+
95
+ ##
96
+ # Returns the rows contents of the list.
97
+ # For testing and debugging only.
98
+ #
99
+ def rows()
100
+ list_store.collect { |store, path, iter|
101
+ iter[0]
102
+ }
103
+ end
104
+
105
+ # Styles
106
+
107
+ def show_headers=(boolean)
108
+ tree_view.headers_visible = boolean
109
+ end
110
+
111
+ def show_headers?()
112
+ tree_view.headers_visible?
113
+ end
114
+
115
+ def clickable_headers=(boolean)
116
+ tree_view.headers_clickable = boolean
117
+ end
118
+
119
+ def clickable_headers?()
120
+ tree_view.headers_clickable?
121
+ end
122
+
123
+ # Handlers
124
+
125
+ def on_selection_changed(tree_selection)
126
+ indices = []
127
+ items = []
128
+
129
+ tree_selection.each do |tree_store, tree_path, iter|
130
+ index = tree_path_to_index(tree_path)
131
+
132
+ indices << index
133
+ items << @get_item_block.call(index)
134
+ end
135
+
136
+ @on_selection_changed_block.call(
137
+ selection_items: items,
138
+ selection_indices: indices
139
+ )
140
+ end
141
+
142
+ # Actions
143
+
144
+ def clear_items()
145
+ list_store.clear
146
+ end
147
+
148
+ # Adding
149
+
150
+ def add_items(items:, index:)
151
+ items.each_with_index do |each_item, i|
152
+ add_item(item: each_item, index: index + i)
153
+ end
154
+ end
155
+
156
+ def add_item(item:, index:)
157
+ iter = list_store.insert(index)
158
+
159
+ set_item_column_values(item: item, iter: iter)
160
+ end
161
+
162
+ # Updating
163
+
164
+ def update_items(items:, indices:)
165
+ items.each_with_index do |each_item, i|
166
+ update_item(item: each_item, index: indices[i])
167
+ end
168
+ end
169
+
170
+ def update_item(item:, index:)
171
+ iter = list_store.get_iter(index.to_s)
172
+
173
+ set_item_column_values(item: item, iter: iter)
174
+ end
175
+
176
+ # Removing
177
+
178
+ def remove_items(items:, indices:)
179
+ items.each_with_index do |each_item, i|
180
+ remove_item(item: each_item, index: indices[i])
181
+ end
182
+ end
183
+
184
+ def remove_item(item:, index:)
185
+ iter = list_store.get_iter(index.to_s)
186
+
187
+ list_store.remove(iter)
188
+ end
189
+
190
+ def set_item_column_values(item:, iter:)
191
+ @columns_props.each_with_index { |column, column_index|
192
+ iter[column_index] = column.display_text_of(item)
193
+ }
194
+ end
195
+
196
+ # Querying
197
+
198
+ def selection_indices()
199
+ indices = []
200
+
201
+ tree_view.selection.each { |list, tree_path, iter|
202
+ indices << tree_path_to_index(tree_path)
203
+ }
204
+
205
+ indices
206
+ end
207
+
208
+ def set_selection_indices(indices)
209
+ if indices.empty?
210
+ tree_view.unselect_all
211
+ return
212
+ end
213
+
214
+ path = Gtk::TreePath.new(
215
+ indices.join(':')
216
+ )
217
+
218
+ tree_view.selection.select_path(path)
219
+
220
+ tree_view.scroll_to_cell(path, nil, false, 0.0, 0.0)
221
+ end
222
+
223
+ # Utility methods
224
+
225
+ def tree_path_to_index(tree_path)
226
+ tree_path.to_s
227
+ .to_i
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,46 @@
1
+ module Sirens
2
+ class MenuView < View
3
+
4
+ # Initializing
5
+
6
+ def initialize(menu_handle: Gtk::Menu.new)
7
+ @main_handle = menu_handle
8
+ end
9
+
10
+ # Adding
11
+
12
+ def item(label:, enabled: true, action:)
13
+ menu_item_handle = Gtk::MenuItem.new(label: label)
14
+ menu_item_handle.sensitive = enabled
15
+
16
+ menu_item_handle.signal_connect('activate') { |props|
17
+ action.call
18
+ }
19
+
20
+ @main_handle.append(menu_item_handle)
21
+ end
22
+
23
+ def separator()
24
+ @main_handle.append(Gtk::SeparatorMenuItem.new)
25
+ end
26
+
27
+ ##
28
+ # Subscribes this View to the events/signals emitted by the GUI handle(s) of interest.
29
+ # When an event/signal is received calls the proper event_handler provided by the PrimitiveComponent,
30
+ # if one was given.
31
+ #
32
+ def subscribe_to_ui_events()
33
+ end
34
+
35
+ # Asking
36
+
37
+ def empty?()
38
+ main_handle.children.empty?
39
+ end
40
+
41
+ def open(props)
42
+ main_handle.show_all
43
+ main_handle.popup(nil, nil, props[:button], props[:time])
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,27 @@
1
+ module Sirens
2
+ class NotebookView < View
3
+
4
+ # Initializing
5
+
6
+ def initialize_handles()
7
+ @main_handle = Gtk::Notebook.new
8
+ end
9
+
10
+ def subscribe_to_ui_events()
11
+ end
12
+
13
+ # Styles
14
+
15
+ def set_tab_label_at(index:, text:)
16
+ page_handle = main_handle.children[index]
17
+
18
+ main_handle.set_tab_label_text(page_handle, text)
19
+ end
20
+
21
+ # Querying
22
+
23
+ def tab_label_at(index:)
24
+ main_handle.get_tab_label_text(main_handle.children[index])
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module Sirens
2
+ class PanedView < View
3
+
4
+ # Initializing
5
+
6
+ def initialize(orientation:, on_size_allocation:)
7
+ @orientation = orientation
8
+ @on_size_allocation = on_size_allocation
9
+
10
+ super()
11
+ end
12
+
13
+ def initialize_handles()
14
+ @main_handle = Gtk::Paned.new(@orientation)
15
+ end
16
+
17
+ def subscribe_to_ui_events()
18
+ main_handle.signal_connect('size-allocate') {
19
+ @on_size_allocation.call(
20
+ width: main_handle.allocation.width,
21
+ height: main_handle.allocation.height
22
+ )
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,67 @@
1
+ module Sirens
2
+ class RadioButtonView < View
3
+
4
+ # Class methods
5
+
6
+ class << self
7
+ ##
8
+ # Answer the styles accepted by this view.
9
+ #
10
+ def view_accepted_styles()
11
+ super() + [:label].freeze
12
+ end
13
+ end
14
+
15
+ # Initializing
16
+
17
+ def initialize(previous_button:, on_toggled:)
18
+ @previous_button = previous_button.main_handle unless previous_button.nil?
19
+
20
+ @on_toggled_block = on_toggled
21
+
22
+ super()
23
+ end
24
+
25
+ def initialize_handles()
26
+ @main_handle = Gtk::RadioButton.new(member: @previous_button)
27
+ end
28
+
29
+ def subscribe_to_ui_events()
30
+ main_handle.signal_connect('clicked') {
31
+ on_toggled
32
+ }
33
+ end
34
+
35
+ # Styles
36
+
37
+ def label=(value)
38
+ main_handle.label = value
39
+ end
40
+
41
+ def label()
42
+ main_handle.label
43
+ end
44
+
45
+ # Actions
46
+
47
+ def click()
48
+ main_handle.clicked
49
+ end
50
+
51
+ # Querying
52
+
53
+ def get_value()
54
+ main_handle.active?
55
+ end
56
+
57
+ def set_value(boolean)
58
+ main_handle.active = boolean
59
+ end
60
+
61
+ # Events
62
+
63
+ def on_toggled()
64
+ @on_toggled_block.call(state: get_value)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ module Sirens
2
+ class StackView < View
3
+
4
+ # Initializing
5
+
6
+ def initialize(orientation)
7
+ @orientation = orientation
8
+
9
+ super()
10
+ end
11
+
12
+ def initialize_handles()
13
+ @main_handle = Gtk::Box.new(@orientation, 0)
14
+ end
15
+
16
+ def subscribe_to_ui_events()
17
+ end
18
+
19
+ ##
20
+ # Adds a child_view.
21
+ #
22
+ def add_view(view, expand: true, fill: true, padding: 0)
23
+ main_handle.pack_start(view.main_handle, expand: expand, fill: fill, padding: padding)
24
+ end
25
+ end
26
+ end