glimmer 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc35b055fcf86d7c93b264b409424039c63c0361f0a7b587e9db0f2071e7809e
4
- data.tar.gz: 3ab0eec08e13367c717ee74a984fea0ee49bbd309fd2fd3348fb40e70b156b2c
3
+ metadata.gz: c1cfa3ffb6be614db3b3e6509edf06c483067889a384c0ffbe94cfb27eea3c73
4
+ data.tar.gz: 4e30d971345d5df61a8ffcd7d736cc71cf2e7992dfe75fba39763ecba1bcbc6d
5
5
  SHA512:
6
- metadata.gz: '059e99839505e645cc41cd13d0adc2f04680643dd7d45d6b6ecb0e9e2fec7823f330f0962756f745ba9ca564c945fb97480e988d21efd732fb3ec36185c8dc89'
7
- data.tar.gz: eb9f191f5aa31e9d716b787bb1b54d0792fb2aaaf080f8f37b7dd17e0ada300192986910b8fe3bcf777a1da7382cf5bd8dd3c6d59bccf63703fbcb95b3fa7bc9
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
- ## Example
8
+ ## Examples
9
9
 
10
- Code (`hello_world.rb`):
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
- ![Glimmer](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-world.png)
31
+ ![Hello World](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-world.png)
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
+ ![Tic Tac Toe](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe.png)
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.1
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.1'
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,8 +1,10 @@
1
- require File.dirname(__FILE__) + "/observer"
1
+ require_relative 'observable'
2
+ require_relative 'observer'
2
3
 
3
4
  # SWT List widget selection binding
4
5
  class ListSelectionBinding
5
6
  include Glimmer
7
+ include Observable
6
8
  include Observer
7
9
 
8
10
  attr_reader :widget
@@ -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
- model.extend(ObservableArray) unless model.is_a?(ObservableArray)
159
- nested_property_observer.observe(model) unless model.has_observer?(nested_property_observer)
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
- model.extend(ObservableModel) unless model.is_a?(ObservableModel)
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
- require File.dirname(__FILE__) + "/r_widget_listener"
2
- require File.dirname(__FILE__) + "/r_runnable"
1
+ require_relative "r_widget_listener"
2
+ require_relative "r_runnable"
3
3
 
4
4
  class RWidget
5
- require File.dirname(__FILE__) + "/r_widget_packages"
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
- require File.dirname(__FILE__) + "/observable_array"
2
- require File.dirname(__FILE__) + "/observable_model"
3
- require File.dirname(__FILE__) + "/observer"
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
- require File.dirname(__FILE__) + "/observable_array"
2
- require File.dirname(__FILE__) + "/observable_model"
3
- require File.dirname(__FILE__) + "/observer"
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
@@ -1,7 +1,9 @@
1
- require File.dirname(__FILE__) + "/observer"
1
+ require_relative 'observable'
2
+ require_relative 'observer'
2
3
 
3
4
  class WidgetBinding
4
5
  include Glimmer
6
+ include Observable
5
7
  include Observer
6
8
 
7
9
  attr_reader :widget, :property
data/lib/glimmer.rb CHANGED
@@ -7,13 +7,20 @@ require "rubygems"
7
7
  require "facets"
8
8
  require "logger"
9
9
  require "java"
10
- require File.dirname(__FILE__) + "/string"
11
- require File.dirname(__FILE__) + "/symbol"
12
- require File.dirname(__FILE__) + "/parent"
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
- include_package 'org.eclipse.swt'
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}
@@ -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.1
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
@@ -1,6 +0,0 @@
1
- # edit to add more packages and support custom widgets
2
- class RWidget
3
- include_package 'org.eclipse.swt'
4
- include_package 'org.eclipse.swt.layout'
5
- include_package 'org.eclipse.swt.widgets'
6
- end