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.
- checksums.yaml +7 -0
- data/lib/components/component.rb +46 -0
- data/lib/components/component_behaviour.rb +160 -0
- data/lib/components/containers/splitter.rb +98 -0
- data/lib/components/containers/stack.rb +42 -0
- data/lib/components/containers/tabs.rb +24 -0
- data/lib/components/containers/window.rb +20 -0
- data/lib/components/primitive_component.rb +155 -0
- data/lib/components/widgets/button.rb +16 -0
- data/lib/components/widgets/checkbox.rb +39 -0
- data/lib/components/widgets/column_props.rb +23 -0
- data/lib/components/widgets/input_text.rb +27 -0
- data/lib/components/widgets/list.rb +68 -0
- data/lib/components/widgets/list_choice.rb +89 -0
- data/lib/components/widgets/radio_button.rb +33 -0
- data/lib/components/widgets/text.rb +31 -0
- data/lib/components/widgets/tree_choice.rb +82 -0
- data/lib/layouts/columns_builder.rb +63 -0
- data/lib/layouts/layout_builder.rb +203 -0
- data/lib/layouts/radio_button_group_builder.rb +28 -0
- data/lib/models/choice_model.rb +41 -0
- data/lib/models/list_model.rb +173 -0
- data/lib/models/tree_choice_model.rb +102 -0
- data/lib/models/value_model.rb +56 -0
- data/lib/models/virtual_tree_model.rb +150 -0
- data/lib/sirens/browsers/module_browser.rb +67 -0
- data/lib/sirens/browsers/object_browser.rb +103 -0
- data/lib/sirens/components/ancestors_list.rb +22 -0
- data/lib/sirens/components/class_browser.rb +38 -0
- data/lib/sirens/components/constants_list.rb +22 -0
- data/lib/sirens/components/method_source_code.rb +22 -0
- data/lib/sirens/components/methods_list.rb +63 -0
- data/lib/sirens/components/modules_list.rb +23 -0
- data/lib/sirens/components/namespaces_list.rb +21 -0
- data/lib/sirens/models/constant_model.rb +21 -0
- data/lib/sirens/models/method_model.rb +111 -0
- data/lib/sirens/models/module_browser_model.rb +225 -0
- data/lib/sirens/models/object_browser_model.rb +125 -0
- data/lib/sirens.rb +90 -0
- data/lib/views/button_view.rb +56 -0
- data/lib/views/check_button_view.rb +65 -0
- data/lib/views/entry_view.rb +25 -0
- data/lib/views/list_view.rb +230 -0
- data/lib/views/menu_view.rb +46 -0
- data/lib/views/notebook_view.rb +27 -0
- data/lib/views/paned_view.rb +26 -0
- data/lib/views/radio_button_view.rb +67 -0
- data/lib/views/stack_view.rb +26 -0
- data/lib/views/text_view.rb +112 -0
- data/lib/views/tree_view.rb +314 -0
- data/lib/views/view.rb +206 -0
- data/lib/views/window_view.rb +51 -0
- metadata +110 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cf56c70a10adabf89009041d21ca90c692fd6a6c81e1fb4c69ba3e4a47a24dbd
|
|
4
|
+
data.tar.gz: d287ee12c0382bf83b2e26d747875e74b4307b4a346638b2f5b412d97f978984
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 47c7e60f0d3667ec1631ac89a10e0ab4d39643e9d6249d03f943e5c134398bd942449c89ecd1430a23c2a58ef2d9e89c611d477e658bf0e2ea1b62fef0dff48c
|
|
7
|
+
data.tar.gz: 8bee3cb065fbe8b7039bc8d8abf7d3bc7eacd31ea406f68b065ebe5f004c40b27302d83d1b8519747f1caebf77a77b8f7a159e3e8da3922a7003ac9d48093b55
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
class Component
|
|
3
|
+
include ComponentBehaviour
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Initializing
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Initializes this component
|
|
10
|
+
#
|
|
11
|
+
def initialize(props = Hash[])
|
|
12
|
+
super(props)
|
|
13
|
+
|
|
14
|
+
build
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Configures the widget with its model, styles and child widgets but does not apply the styles yet.
|
|
19
|
+
# This method is called when opening a widget with ::open and after calling ::initialize_handles.
|
|
20
|
+
# The building of the widget includes defining its model, its style props and its event blocks,
|
|
21
|
+
# but does no apply those styles yet. The wiring and synchronization of the component to the
|
|
22
|
+
# widget is done in the ::post_build method.
|
|
23
|
+
#
|
|
24
|
+
def build()
|
|
25
|
+
set_model( props.key?(:model) ? props[:model] : default_model )
|
|
26
|
+
|
|
27
|
+
renderWith(LayoutBuilder.new(main_component: self))
|
|
28
|
+
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Hook method to allow each Component subclass to define its default styles and compose its child components.
|
|
34
|
+
# Subclasses are expected to implement this method.
|
|
35
|
+
def renderWith(layout)
|
|
36
|
+
raise RuntimeError.new("Class #{self.class.name} must implement a ::renderWith(layout) method.")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Returns the top most view of this component.
|
|
41
|
+
#
|
|
42
|
+
def main_view()
|
|
43
|
+
main_component.main_view
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
module ComponentBehaviour
|
|
3
|
+
module ClassMethods
|
|
4
|
+
# Opening
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# Todo: Opens a new window with this component. Currently only works for actual Windows.
|
|
8
|
+
#
|
|
9
|
+
def open(props = Hash[])
|
|
10
|
+
self.new(props)
|
|
11
|
+
.open
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.included(base)
|
|
16
|
+
base.extend(ClassMethods)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Initializing
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Initializes this component.
|
|
23
|
+
#
|
|
24
|
+
def initialize(props = Hash[])
|
|
25
|
+
super()
|
|
26
|
+
|
|
27
|
+
@props = Hash[]
|
|
28
|
+
@components = []
|
|
29
|
+
|
|
30
|
+
set_props(props)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Accessing
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Returns this component props.
|
|
37
|
+
#
|
|
38
|
+
def props()
|
|
39
|
+
@props
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# Applies the given props to the current component.props.
|
|
44
|
+
# The component.props that are not included in given props remain untouched.
|
|
45
|
+
#
|
|
46
|
+
def set_props(props)
|
|
47
|
+
@props.merge!(props)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Returns the child components of this component.
|
|
52
|
+
#
|
|
53
|
+
def components()
|
|
54
|
+
@components
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Returns the main child component.
|
|
59
|
+
#
|
|
60
|
+
def main_component()
|
|
61
|
+
@components.first
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# Returns a default model if none is given during the initialization of this component.
|
|
66
|
+
#
|
|
67
|
+
def default_model()
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# Returns the current model of this component.
|
|
73
|
+
#
|
|
74
|
+
def model()
|
|
75
|
+
@props[:model]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# Sets the current model of this component.
|
|
80
|
+
#
|
|
81
|
+
def set_model(new_model)
|
|
82
|
+
old_model = model
|
|
83
|
+
|
|
84
|
+
@props[:model] = new_model
|
|
85
|
+
|
|
86
|
+
on_model_changed(new_model: new_model, old_model: old_model)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def on_model_changed(new_model:, old_model:)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Child components
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
# Adds the child_component to this component.
|
|
96
|
+
#
|
|
97
|
+
def add_component(child_component)
|
|
98
|
+
components << child_component
|
|
99
|
+
|
|
100
|
+
on_component_added(child_component)
|
|
101
|
+
|
|
102
|
+
child_component
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
# Adds the child_component to this component.
|
|
107
|
+
#
|
|
108
|
+
def add_all_components(components)
|
|
109
|
+
components.each do |child_component|
|
|
110
|
+
add_component(child_component)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
##
|
|
117
|
+
# Removes the last child component and returns it.
|
|
118
|
+
#
|
|
119
|
+
def remove_last_component()
|
|
120
|
+
remove_component_at(index: components.size - 1)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# Removes the component at the index-th position.
|
|
125
|
+
#
|
|
126
|
+
def remove_component_at(index:)
|
|
127
|
+
component = components.delete_at(index)
|
|
128
|
+
|
|
129
|
+
main_view.remove_view(component.main_view)
|
|
130
|
+
|
|
131
|
+
component
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
##
|
|
135
|
+
# This method is called right after adding a child component.
|
|
136
|
+
# Subclasses may use it to perform further configuration on this component or its children.
|
|
137
|
+
#
|
|
138
|
+
def on_component_added(child_component)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
##
|
|
142
|
+
# Returns the top most view of this component.
|
|
143
|
+
# This method is required to assemble parent and child views.
|
|
144
|
+
#
|
|
145
|
+
def main_view()
|
|
146
|
+
raise RuntimeError.new("Class #{self.class.name} must implement a ::main_view() method.")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
##
|
|
150
|
+
# Todo: Opens this component in a Window.
|
|
151
|
+
# At this moment only works if the main_component is a window.
|
|
152
|
+
#
|
|
153
|
+
def open()
|
|
154
|
+
main_component.show
|
|
155
|
+
|
|
156
|
+
self
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
##
|
|
3
|
+
# Component that wraps a StackView.
|
|
4
|
+
#
|
|
5
|
+
class Splitter < PrimitiveComponent
|
|
6
|
+
|
|
7
|
+
# Class methods
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def horizontal(props = Hash[])
|
|
11
|
+
props[:orientation] = :horizontal
|
|
12
|
+
|
|
13
|
+
self.new(props)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def vertical(props = Hash[])
|
|
17
|
+
props[:orientation] = :vertical
|
|
18
|
+
|
|
19
|
+
self.new(props)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Returns a PanedView.
|
|
25
|
+
#
|
|
26
|
+
def create_view()
|
|
27
|
+
PanedView.new(
|
|
28
|
+
orientation: props.fetch(:orientation),
|
|
29
|
+
on_size_allocation: proc{ |width:, height:|
|
|
30
|
+
on_size_allocation(width: width, height: height)
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Adds the child_component to this component.
|
|
37
|
+
#
|
|
38
|
+
def add_component(child_component)
|
|
39
|
+
if components.size < 2
|
|
40
|
+
components << child_component
|
|
41
|
+
|
|
42
|
+
on_component_added(child_component)
|
|
43
|
+
|
|
44
|
+
return
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
last_child = remove_last_component
|
|
48
|
+
|
|
49
|
+
new_splitter_proportion = 1.0 - components.first.props[:splitter_proportion]
|
|
50
|
+
|
|
51
|
+
new_splitter = self.class.new(orientation: orientation)
|
|
52
|
+
|
|
53
|
+
last_child.props[:splitter_proportion] = last_child.props[:splitter_proportion] / new_splitter_proportion
|
|
54
|
+
new_splitter.add_component(last_child)
|
|
55
|
+
|
|
56
|
+
child_component.props[:splitter_proportion] = child_component.props[:splitter_proportion] / new_splitter_proportion
|
|
57
|
+
new_splitter.add_component(child_component)
|
|
58
|
+
|
|
59
|
+
components << new_splitter
|
|
60
|
+
on_component_added(new_splitter)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Asking
|
|
64
|
+
|
|
65
|
+
def orientation()
|
|
66
|
+
props[:orientation]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Events
|
|
70
|
+
|
|
71
|
+
def on_size_allocation(width:, height:)
|
|
72
|
+
components.each do |child_component|
|
|
73
|
+
size_proportion = child_component.props[:splitter_proportion]
|
|
74
|
+
|
|
75
|
+
next if size_proportion.nil?
|
|
76
|
+
|
|
77
|
+
if orientation == :vertical
|
|
78
|
+
proportional_height = height * size_proportion
|
|
79
|
+
|
|
80
|
+
if child_component.props.key?(:height)
|
|
81
|
+
proportional_height = [proportional_height, child_component.props[:height]].max
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
child_component.main_view.height = proportional_height
|
|
85
|
+
|
|
86
|
+
else
|
|
87
|
+
proportional_width = width * size_proportion
|
|
88
|
+
|
|
89
|
+
if child_component.props.key?(:width)
|
|
90
|
+
proportional_width = [proportional_width, child_component.props[:width]].max
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
child_component.main_view.width = proportional_width
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
##
|
|
3
|
+
# Component that wraps a StackView.
|
|
4
|
+
#
|
|
5
|
+
class Stack < PrimitiveComponent
|
|
6
|
+
|
|
7
|
+
# Class methods
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def horizontal(props = Hash[])
|
|
11
|
+
props[:orientation] = :horizontal
|
|
12
|
+
|
|
13
|
+
self.new(props)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def vertical(props = Hash[])
|
|
17
|
+
props[:orientation] = :vertical
|
|
18
|
+
|
|
19
|
+
self.new(props)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Returns a StackView.
|
|
25
|
+
#
|
|
26
|
+
def create_view()
|
|
27
|
+
StackView.new(props.fetch(:orientation))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Adds the child_component to this component.
|
|
32
|
+
#
|
|
33
|
+
def on_component_added(child_component)
|
|
34
|
+
view.add_view(
|
|
35
|
+
child_component.main_view,
|
|
36
|
+
expand: child_component.props.fetch(:stack_expand, true),
|
|
37
|
+
fill: child_component.props.fetch(:stack_fill, true),
|
|
38
|
+
padding: child_component.props.fetch(:stack_padding, 0)
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
##
|
|
3
|
+
# Component that wraps a NotebookView.
|
|
4
|
+
#
|
|
5
|
+
class Tabs < PrimitiveComponent
|
|
6
|
+
##
|
|
7
|
+
# Returns a StackView.
|
|
8
|
+
#
|
|
9
|
+
def create_view()
|
|
10
|
+
NotebookView.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Adds the child_component to this component.
|
|
15
|
+
#
|
|
16
|
+
def on_component_added(child_component)
|
|
17
|
+
super(child_component)
|
|
18
|
+
|
|
19
|
+
tab_label_text = child_component.props[:tab_label]
|
|
20
|
+
|
|
21
|
+
view.set_tab_label_at(index: components.size - 1, text: tab_label_text)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
##
|
|
3
|
+
# Component that wraps a WindowView.
|
|
4
|
+
#
|
|
5
|
+
class Window < PrimitiveComponent
|
|
6
|
+
##
|
|
7
|
+
# Returns a WindowView.
|
|
8
|
+
#
|
|
9
|
+
def create_view()
|
|
10
|
+
WindowView.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Makes this component visible.
|
|
15
|
+
#
|
|
16
|
+
def show()
|
|
17
|
+
view.show
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
##
|
|
3
|
+
# PrimitiveComponent is a component wrapping a PrimitiveView.
|
|
4
|
+
# A PrimitiveView implements the actual GUI binding to a Widget (a Gtk widget, for instance).
|
|
5
|
+
# Besides acting as a regular Component, PrimitiveComponent also takes care of handling the PrimitiveView.
|
|
6
|
+
#
|
|
7
|
+
class PrimitiveComponent
|
|
8
|
+
include ComponentBehaviour
|
|
9
|
+
|
|
10
|
+
# Initializing
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Initializes this component
|
|
14
|
+
#
|
|
15
|
+
def initialize(props = Hash[])
|
|
16
|
+
super(props)
|
|
17
|
+
|
|
18
|
+
@view = create_view
|
|
19
|
+
|
|
20
|
+
@updating_view = false
|
|
21
|
+
|
|
22
|
+
apply_props
|
|
23
|
+
|
|
24
|
+
sync_ui_from_model
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Applies the props to the view.
|
|
29
|
+
#
|
|
30
|
+
def apply_props()
|
|
31
|
+
if ! view.nil?
|
|
32
|
+
@view.apply_props(props)
|
|
33
|
+
|
|
34
|
+
@view.populate_popup_menu_block = proc { |menu:| populate_popup_menu(menu: menu) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
set_model( props.key?(:model) ? props[:model] : default_model )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Creates the PrimitiveView that this component wraps.
|
|
42
|
+
# This method must be implemented by each subclass.
|
|
43
|
+
#
|
|
44
|
+
def create_view()
|
|
45
|
+
raise RuntimeError.new("Class #{self.class.name} must implement a ::create_view() method.")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Accessing
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Applies the given props to the current component.props.
|
|
52
|
+
# The component.props that are not included in given props remain untouched.
|
|
53
|
+
#
|
|
54
|
+
def set_props(props)
|
|
55
|
+
super(props)
|
|
56
|
+
|
|
57
|
+
apply_props
|
|
58
|
+
|
|
59
|
+
sync_ui_from_model if props.key?(:model)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Returns this component View.
|
|
64
|
+
#
|
|
65
|
+
def view()
|
|
66
|
+
@view
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# Returns the top most view of this component.
|
|
71
|
+
#
|
|
72
|
+
def main_view()
|
|
73
|
+
view
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Child components
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# Adds the child_component to this component.
|
|
80
|
+
#
|
|
81
|
+
def on_component_added(child_component)
|
|
82
|
+
view.add_view(child_component.main_view)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Events
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# Method called when this component model changes.
|
|
89
|
+
# Unsubscribes this component from the current model events, subscribes this component to the
|
|
90
|
+
# new model events and syncs the widget with the new model.
|
|
91
|
+
#
|
|
92
|
+
def on_model_changed(old_model:, new_model:)
|
|
93
|
+
old_model.delete_observer(self) if old_model.respond_to?(:delete_observer)
|
|
94
|
+
|
|
95
|
+
subscribe_to_model_events
|
|
96
|
+
|
|
97
|
+
sync_ui_from_model
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# Subscribes this component to the model events
|
|
102
|
+
#
|
|
103
|
+
def subscribe_to_model_events()
|
|
104
|
+
model.add_observer(self, :on_value_changed) if model.respond_to?(:add_observer)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
##
|
|
108
|
+
# Hook method called when the model value changes.
|
|
109
|
+
# Note that the model remains the same, what changed is the value the model holds.
|
|
110
|
+
# Subclasses may use this method to update other aspects of its model or perform actions.
|
|
111
|
+
#
|
|
112
|
+
def on_value_changed(announcement)
|
|
113
|
+
sync_ui_from_model
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
##
|
|
117
|
+
# Populate the popup menu.
|
|
118
|
+
#
|
|
119
|
+
def populate_popup_menu(menu:)
|
|
120
|
+
return if props[:popup_menu].nil?
|
|
121
|
+
|
|
122
|
+
props[:popup_menu].call(menu: menu, menu_owner: self)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Actions
|
|
126
|
+
|
|
127
|
+
##
|
|
128
|
+
# Synchronizes the view to the models current state.
|
|
129
|
+
#
|
|
130
|
+
def sync_ui_from_model()
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##
|
|
134
|
+
# Returns true if this component is currently updating the view.
|
|
135
|
+
#
|
|
136
|
+
def is_updating_view?()
|
|
137
|
+
@updating_view
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
##
|
|
141
|
+
# Flags that this component is updating the view during the evaluation of the given &block.
|
|
142
|
+
#
|
|
143
|
+
def while_updating_view(&block)
|
|
144
|
+
updating = is_updating_view?
|
|
145
|
+
|
|
146
|
+
@updating_view = true
|
|
147
|
+
|
|
148
|
+
begin
|
|
149
|
+
block.call
|
|
150
|
+
ensure
|
|
151
|
+
@updating_view = updating
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
class Checkbox < PrimitiveComponent
|
|
3
|
+
##
|
|
4
|
+
# Returns a CheckButtonView.
|
|
5
|
+
#
|
|
6
|
+
def create_view()
|
|
7
|
+
CheckButtonView.new(on_toggled: proc{ |state:| on_toggled(state: state) })
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# Returns a default model if none is given during the initialization of this component.
|
|
12
|
+
#
|
|
13
|
+
def default_model()
|
|
14
|
+
ValueModel.on(false)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Actions
|
|
18
|
+
|
|
19
|
+
def click()
|
|
20
|
+
view.click
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def sync_ui_from_model()
|
|
24
|
+
view.set_value(model.value) unless view.nil?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Events
|
|
28
|
+
|
|
29
|
+
def on_value_changed(announcement)
|
|
30
|
+
view.set_value(announcement.new_value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def on_toggled(state:)
|
|
34
|
+
return if model.nil?
|
|
35
|
+
|
|
36
|
+
model.set_value(state)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
class ColumnProps
|
|
3
|
+
def initialize(props = Hash[])
|
|
4
|
+
@props = props
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
attr_reader :props
|
|
8
|
+
|
|
9
|
+
def fetch(key, absent_value)
|
|
10
|
+
@props.fetch(key, absent_value)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def [](key)
|
|
14
|
+
@props[key]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def display_text_of(item)
|
|
18
|
+
return item.to_s if ! @props.key?(:get_text_block)
|
|
19
|
+
|
|
20
|
+
@props[:get_text_block].call(item)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Sirens
|
|
2
|
+
class InputText < PrimitiveComponent
|
|
3
|
+
##
|
|
4
|
+
# Returns a TextView.
|
|
5
|
+
#
|
|
6
|
+
def create_view()
|
|
7
|
+
EntryView.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# Returns a default model if none is given during the initialization of this component.
|
|
12
|
+
#
|
|
13
|
+
def default_model()
|
|
14
|
+
ValueModel.on('')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def sync_ui_from_model()
|
|
18
|
+
view.set_text(model.value) unless view.nil?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Events
|
|
22
|
+
|
|
23
|
+
def on_value_changed(announcement)
|
|
24
|
+
view.set_text(announcement.new_value)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|