glimmer 0.3.1 → 0.3.2
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 +4 -4
- data/README.markdown +82 -6
- data/lib/command_handlers/combo_selection_data_binding_command_handler.rb +0 -1
- data/lib/command_handlers/list_selection_data_binding_command_handler.rb +0 -1
- data/lib/command_handlers/models/list_selection_binding.rb +3 -1
- data/lib/command_handlers/models/model_binding.rb +5 -6
- data/lib/command_handlers/models/observable_array.rb +1 -2
- data/lib/command_handlers/models/observable_model.rb +4 -1
- data/lib/command_handlers/models/observer.rb +8 -0
- data/lib/command_handlers/models/r_widget.rb +5 -4
- data/lib/command_handlers/models/table_items_binding.rb +5 -5
- data/lib/command_handlers/models/tree_items_binding.rb +5 -6
- data/lib/command_handlers/models/widget_binding.rb +3 -1
- data/lib/glimmer.rb +12 -5
- data/lib/swt_packages.rb +11 -0
- metadata +2 -2
- data/lib/command_handlers/models/r_widget_packages.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1cfa3ffb6be614db3b3e6509edf06c483067889a384c0ffbe94cfb27eea3c73
|
4
|
+
data.tar.gz: 4e30d971345d5df61a8ffcd7d736cc71cf2e7992dfe75fba39763ecba1bcbc6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be20760fda63f6b5458fd00ddcdd1f008057a3b376ad11dbaaa9ee488c0ec72cf67d9322b9f6673d23ff8c49679dc636ef98b17db0a8092fdabf41010f400074
|
7
|
+
data.tar.gz: 221280c0420afd17a8f843b2691b445ee2da99240d7b916e4f3af52eec1772458aa846393db9dbc6c44ba8ee1874b53ad517a946ffb05a39653fd669cd771163
|
data/README.markdown
CHANGED
@@ -5,9 +5,11 @@ Glimmer is a cross-platform Ruby desktop development library. Glimmer's main inn
|
|
5
5
|
|
6
6
|
You may learn more by reading this article: [Eclipse Zone Tutorial](http://eclipse.dzone.com/articles/an-introduction-glimmer)
|
7
7
|
|
8
|
-
##
|
8
|
+
## Examples
|
9
9
|
|
10
|
-
|
10
|
+
### Hello World
|
11
|
+
|
12
|
+
Glimmer code (from `samples/hello_world.rb`):
|
11
13
|
```ruby
|
12
14
|
include Glimmer
|
13
15
|
|
@@ -21,13 +23,47 @@ shell {
|
|
21
23
|
|
22
24
|
Run:
|
23
25
|
```
|
24
|
-
glimmer hello_world.rb
|
26
|
+
glimmer samples/hello_world.rb
|
25
27
|
```
|
26
28
|
|
27
29
|
Glimmer app:
|
28
30
|
|
29
|
-

|
32
|
+
|
33
|
+
### Tic Tac Toe
|
30
34
|
|
35
|
+
Glimmer code (from `samples/tictactoe/tic_tac_toe.rb`):
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
shell {
|
39
|
+
text "Tic-Tac-Toe"
|
40
|
+
composite {
|
41
|
+
layout GridLayout.new(3,true)
|
42
|
+
(1..3).each { |row|
|
43
|
+
(1..3).each { |column|
|
44
|
+
button {
|
45
|
+
layout_data GridData.new(:fill.swt_constant, :fill.swt_constant, true, true)
|
46
|
+
text bind(@tic_tac_toe_board.box(row, column), :sign)
|
47
|
+
enabled bind(@tic_tac_toe_board.box(row, column), :empty)
|
48
|
+
on_widget_selected {
|
49
|
+
@tic_tac_toe_board.mark_box(row, column)
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
```
|
57
|
+
|
58
|
+
Run:
|
59
|
+
|
60
|
+
```
|
61
|
+
glimmer samples/tictactoe/tic_tac_toe.rb
|
62
|
+
```
|
63
|
+
|
64
|
+
Glimmer app:
|
65
|
+
|
66
|
+

|
31
67
|
|
32
68
|
## Resources
|
33
69
|
|
@@ -66,14 +102,14 @@ Please follow these instructions to make the `glimmer` command available on your
|
|
66
102
|
|
67
103
|
Run this command to install directly:
|
68
104
|
```
|
69
|
-
jgem install glimmer -v 0.3.
|
105
|
+
jgem install glimmer -v 0.3.2
|
70
106
|
```
|
71
107
|
|
72
108
|
### Option 2: Bundler
|
73
109
|
|
74
110
|
Add the following to `Gemfile`:
|
75
111
|
```
|
76
|
-
gem 'glimmer', '~> 0.3.
|
112
|
+
gem 'glimmer', '~> 0.3.2'
|
77
113
|
```
|
78
114
|
|
79
115
|
And, then run:
|
@@ -148,6 +184,43 @@ The fifth example demonstrates nested indexed computed value data binding whereb
|
|
148
184
|
|
149
185
|
You may learn more about Glimmer's syntax by reading the Eclipse Zone Tutorial mentioned in resources and opening up the samples under the `samples` folder.
|
150
186
|
|
187
|
+
### Observer/Observable
|
188
|
+
|
189
|
+
Glimmer comes with the two classes `Observer`/`Observable`, which are used internally for data-binding, but can also be used externally for custom use of the Observer Pattern.
|
190
|
+
|
191
|
+
In summary, the class that needs to observe an object, must include Observer and implement `#update(changed_value)` method. The class to be observed doesn't need to do anything. It will automatically be enhanced by Glimmer for observation.
|
192
|
+
|
193
|
+
Observers can be a good mechanism for displaying dialog messages with Glimmer (using SWT's `MessageBox`).
|
194
|
+
|
195
|
+
Look at `samples/tictactoe/tic_tac_toe.rb` for an `Observer` dialog message example.
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
observe(@tic_tac_toe_board, "game_status")
|
199
|
+
```
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
def update(game_status)
|
203
|
+
display_win_message if game_status == TicTacToeBoard::WIN
|
204
|
+
display_draw_message if game_status == TicTacToeBoard::DRAW
|
205
|
+
end
|
206
|
+
|
207
|
+
def display_win_message
|
208
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
209
|
+
end
|
210
|
+
|
211
|
+
def display_draw_message
|
212
|
+
display_game_over_message("Draw!")
|
213
|
+
end
|
214
|
+
|
215
|
+
def display_game_over_message(message)
|
216
|
+
message_box = MessageBox.new(@shell.widget)
|
217
|
+
message_box.setText("Game Over")
|
218
|
+
message_box.setMessage(message)
|
219
|
+
message_box.open
|
220
|
+
@tic_tac_toe_board.reset
|
221
|
+
end
|
222
|
+
```
|
223
|
+
|
151
224
|
## Samples
|
152
225
|
|
153
226
|
Check the "samples" folder for examples on how to write Glimmer applications. To run them, make sure to install the `glimmer` gem first and then use the `glimmer` command.
|
@@ -232,6 +305,9 @@ These features have been suggested. You might see them in a future version of Gl
|
|
232
305
|
a new component and extend the DSL with it
|
233
306
|
- **Nested indexed property data binding**: a complementary feature to nested property data binding that binds to a collection element by index (e.g. `bind(user, 'addresses[1].street')`)
|
234
307
|
- **bind_collection**: an iterator that enables spawning widgets based on a variable collection (e.g. `bind_collection('user.addresses') { |address| address_widget {...} }` spawns 3 `AddressWidget`s if `user.addresses` is set with 3 addresses; and replaces with 2 `AddressWidget`s if `user.addresses` is reset with 2 addresses only). Needs further thought on naming and functionality.
|
308
|
+
- Automatic relayout of "glimmer components" when disposing one or as an option
|
309
|
+
- Consider using Ruby Refinements for Glimmer
|
310
|
+
|
235
311
|
|
236
312
|
## Contributors
|
237
313
|
|
@@ -22,7 +22,6 @@ class ComboSelectionDataBindingCommandHandler
|
|
22
22
|
widget_binding = WidgetBinding.new(parent, "items")
|
23
23
|
widget_binding.update(model_binding.evaluate_options_property)
|
24
24
|
model = model_binding.base_model
|
25
|
-
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
26
25
|
widget_binding.observe(model, model_binding.options_property_name)
|
27
26
|
|
28
27
|
widget_binding = WidgetBinding.new(parent, "text")
|
@@ -23,7 +23,6 @@ class ListSelectionDataBindingCommandHandler
|
|
23
23
|
widget_binding = WidgetBinding.new(parent, "items")
|
24
24
|
widget_binding.update(model_binding.evaluate_options_property)
|
25
25
|
model = model_binding.base_model
|
26
|
-
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
27
26
|
#TODO make this options observer dependent and all similar observers in widget specific data binding handlers
|
28
27
|
widget_binding.observe(model, model_binding.options_property_name)
|
29
28
|
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require_relative 'observable'
|
1
2
|
require_relative 'observer'
|
2
3
|
require_relative 'block_observer'
|
3
4
|
|
4
5
|
class ModelBinding
|
6
|
+
include Observable
|
5
7
|
include Observer
|
6
8
|
|
7
9
|
attr_reader :property_type, :binding_options
|
@@ -110,7 +112,6 @@ class ModelBinding
|
|
110
112
|
elsif nested_property?
|
111
113
|
add_nested_observers(observer)
|
112
114
|
else
|
113
|
-
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
114
115
|
observer.observe(model, property_name)
|
115
116
|
observer.add_dependent([self, nil] => [observer, model, property_name])
|
116
117
|
end
|
@@ -124,7 +125,6 @@ class ModelBinding
|
|
124
125
|
elsif nested_property?
|
125
126
|
nested_property_observers_for(observer).clear
|
126
127
|
else
|
127
|
-
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
128
128
|
observer.unobserve(model, property_name)
|
129
129
|
end
|
130
130
|
end
|
@@ -155,12 +155,11 @@ class ModelBinding
|
|
155
155
|
parent_property_name = nil if parent_property_name.to_s.start_with?('[')
|
156
156
|
unless model.nil?
|
157
157
|
if property_indexed?(property_name)
|
158
|
-
|
159
|
-
nested_property_observer.observe(model)
|
158
|
+
# TODO figure out a way to deal with this more uniformly
|
159
|
+
nested_property_observer.observe(model)
|
160
160
|
parent_observer.add_dependent([parent_model, parent_property_name] => [nested_property_observer, model, nil])
|
161
161
|
else
|
162
|
-
|
163
|
-
nested_property_observer.observe(model, property_name) unless model.has_observer?(nested_property_observer, property_name)
|
162
|
+
nested_property_observer.observe(model, property_name)
|
164
163
|
parent_observer.add_dependent([parent_model, parent_property_name] => [nested_property_observer, model, property_name])
|
165
164
|
end
|
166
165
|
end
|
@@ -7,10 +7,10 @@ module ObservableArray
|
|
7
7
|
include Observable
|
8
8
|
|
9
9
|
def add_observer(observer, element_properties=nil)
|
10
|
+
return observer if has_observer?(observer) && element_properties.nil?
|
10
11
|
property_observer_list << observer
|
11
12
|
[element_properties].flatten.compact.each do |property|
|
12
13
|
each do |element|
|
13
|
-
element.extend(ObservableModel) unless element.is_a?(ObservableModel)
|
14
14
|
observer.observe(element, property)
|
15
15
|
end
|
16
16
|
end
|
@@ -21,7 +21,6 @@ module ObservableArray
|
|
21
21
|
property_observer_list.delete(observer)
|
22
22
|
[element_properties].flatten.compact.each do |property|
|
23
23
|
each do |element|
|
24
|
-
element.extend(ObservableModel) unless element.is_a?(ObservableModel)
|
25
24
|
observer.unobserve(element, property)
|
26
25
|
end
|
27
26
|
end
|
@@ -54,6 +54,7 @@ module ObservableModel
|
|
54
54
|
|
55
55
|
def add_property_writer_observers(property_name)
|
56
56
|
property_writer_name = "#{property_name}="
|
57
|
+
method(property_writer_name)
|
57
58
|
ensure_array_object_observer(property_name, send(property_name))
|
58
59
|
begin
|
59
60
|
method("__original_#{property_writer_name}")
|
@@ -69,6 +70,9 @@ module ObservableModel
|
|
69
70
|
end
|
70
71
|
end_eval
|
71
72
|
end
|
73
|
+
rescue => e
|
74
|
+
# ignore writing if no property writer exists
|
75
|
+
Glimmer.logger.debug "No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
72
76
|
end
|
73
77
|
|
74
78
|
def unregister_dependent_observers(property_name, old_value)
|
@@ -81,7 +85,6 @@ module ObservableModel
|
|
81
85
|
|
82
86
|
def ensure_array_object_observer(property_name, object, old_object = nil)
|
83
87
|
return unless object.is_a?(Array)
|
84
|
-
object.extend(ObservableArray) unless object.is_a?(ObservableArray)
|
85
88
|
array_object_observer = array_object_observer_for(property_name)
|
86
89
|
array_object_observer.observe(object)
|
87
90
|
property_observer_list(property_name).each do |observer|
|
@@ -25,6 +25,14 @@ module Observer
|
|
25
25
|
# registers observer in an observable on a property (optional)
|
26
26
|
# observer maintains registration list to unregister later
|
27
27
|
def register(observable, property = nil)
|
28
|
+
unless observable.is_a?(Observable)
|
29
|
+
# TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
|
30
|
+
if observable.is_a?(Array)
|
31
|
+
observable.extend(ObservableArray)
|
32
|
+
else
|
33
|
+
observable.extend(ObservableModel)
|
34
|
+
end
|
35
|
+
end
|
28
36
|
observable.add_observer(*[self, property].compact)
|
29
37
|
[observable, property].tap do |registration|
|
30
38
|
self.registrations << registration
|
@@ -1,9 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative "r_widget_listener"
|
2
|
+
require_relative "r_runnable"
|
3
3
|
|
4
4
|
class RWidget
|
5
|
-
|
6
|
-
|
5
|
+
include_package 'org.eclipse.swt'
|
6
|
+
include_package 'org.eclipse.swt.widgets'
|
7
|
+
include_package 'org.eclipse.swt.layout'
|
7
8
|
include Parent
|
8
9
|
|
9
10
|
attr_reader :widget
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'observable_array'
|
2
|
+
require_relative 'observable_model'
|
3
|
+
require_relative 'observable'
|
4
|
+
require_relative 'observer'
|
4
5
|
|
5
6
|
class TableItemsBinding
|
6
7
|
include Glimmer
|
8
|
+
include Observable
|
7
9
|
include Observer
|
8
10
|
include_package 'org.eclipse.swt'
|
9
11
|
include_package 'org.eclipse.swt.widgets'
|
@@ -14,7 +16,6 @@ class TableItemsBinding
|
|
14
16
|
@column_properties = column_properties
|
15
17
|
update(@model_binding.evaluate_property)
|
16
18
|
model = model_binding.base_model
|
17
|
-
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
18
19
|
observe(model, model_binding.property_name_expression)
|
19
20
|
add_contents(@table) {
|
20
21
|
on_widget_disposed { |dispose_event|
|
@@ -24,7 +25,6 @@ class TableItemsBinding
|
|
24
25
|
end
|
25
26
|
def update(model_collection=nil)
|
26
27
|
if model_collection and model_collection.is_a?(Array)
|
27
|
-
model_collection.extend(ObservableArray) unless model_collection.is_a?(ObservableArray)
|
28
28
|
observe(model_collection, @column_properties)
|
29
29
|
@model_collection = model_collection
|
30
30
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'observable_array'
|
2
|
+
require_relative 'observable_model'
|
3
|
+
require_relative 'observable'
|
4
|
+
require_relative 'observer'
|
4
5
|
|
5
6
|
class TreeItemsBinding
|
6
7
|
include Glimmer
|
8
|
+
include Observable
|
7
9
|
include Observer
|
8
10
|
include_package 'org.eclipse.swt'
|
9
11
|
include_package 'org.eclipse.swt.widgets'
|
@@ -14,7 +16,6 @@ class TreeItemsBinding
|
|
14
16
|
@tree_properties = [tree_properties].flatten.first.to_h
|
15
17
|
update(@model_binding.evaluate_property)
|
16
18
|
model = model_binding.base_model
|
17
|
-
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
18
19
|
observe(model, model_binding.property_name_expression)
|
19
20
|
add_contents(@tree) {
|
20
21
|
on_widget_disposed { |dispose_event|
|
@@ -24,7 +25,6 @@ class TreeItemsBinding
|
|
24
25
|
end
|
25
26
|
def update(model_tree_root_node=nil)
|
26
27
|
if model_tree_root_node and model_tree_root_node.respond_to?(@tree_properties[:children])
|
27
|
-
model_tree_root_node.extend(ObservableModel) unless model_tree_root_node.is_a?(ObservableModel)
|
28
28
|
observe(model_tree_root_node, @tree_properties[:text])
|
29
29
|
observe(model_tree_root_node, @tree_properties[:children])
|
30
30
|
@model_tree_root_node = model_tree_root_node
|
@@ -39,7 +39,6 @@ class TreeItemsBinding
|
|
39
39
|
table_item = TreeItem.new(parent, SWT::NONE)
|
40
40
|
table_item.setText((model_tree_node && model_tree_node.send(tree_properties[:text])).to_s)
|
41
41
|
[model_tree_node && model_tree_node.send(tree_properties[:children])].flatten.to_a.compact.each do |child|
|
42
|
-
child.extend(ObservableModel) unless child.is_a?(ObservableModel)
|
43
42
|
observe(child, @tree_properties[:text])
|
44
43
|
populate_tree_node(child, table_item, tree_properties)
|
45
44
|
end
|
data/lib/glimmer.rb
CHANGED
@@ -7,13 +7,20 @@ require "rubygems"
|
|
7
7
|
require "facets"
|
8
8
|
require "logger"
|
9
9
|
require "java"
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
require_relative "string"
|
11
|
+
require_relative "symbol"
|
12
|
+
require_relative "parent"
|
13
|
+
require_relative "swt_packages"
|
13
14
|
|
14
15
|
module Glimmer
|
15
|
-
|
16
|
-
|
16
|
+
#TODO make it configurable to include or not include
|
17
|
+
include SwtPackages
|
18
|
+
def self.included(klass)
|
19
|
+
klass.include SwtPackages
|
20
|
+
end
|
21
|
+
def self.extended(klass)
|
22
|
+
klass.include SwtPackages
|
23
|
+
end
|
17
24
|
|
18
25
|
@@parent_stack = []
|
19
26
|
@@logger = Logger.new(STDOUT).tap {|logger| logger.level = Logger::WARN}
|
data/lib/swt_packages.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# edit to add more packages and support custom widgets
|
2
|
+
module SwtPackages
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
include_package 'org.eclipse.swt'
|
6
|
+
include_package 'org.eclipse.swt.widgets'
|
7
|
+
include_package 'org.eclipse.swt.layout'
|
8
|
+
include_package 'org.eclipse.swt.graphics'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
@@ -171,7 +171,6 @@ files:
|
|
171
171
|
- lib/command_handlers/models/r_tab_item_composite.rb
|
172
172
|
- lib/command_handlers/models/r_widget.rb
|
173
173
|
- lib/command_handlers/models/r_widget_listener.rb
|
174
|
-
- lib/command_handlers/models/r_widget_packages.rb
|
175
174
|
- lib/command_handlers/models/table_items_binding.rb
|
176
175
|
- lib/command_handlers/models/tree_items_binding.rb
|
177
176
|
- lib/command_handlers/models/widget_binding.rb
|
@@ -189,6 +188,7 @@ files:
|
|
189
188
|
- lib/parent.rb
|
190
189
|
- lib/shine.rb
|
191
190
|
- lib/string.rb
|
191
|
+
- lib/swt_packages.rb
|
192
192
|
- lib/symbol.rb
|
193
193
|
- lib/xml_command_handlers.rb
|
194
194
|
- lib/xml_command_handlers/html_command_handler.rb
|