glimmer-dsl-swt 4.24.2.3 → 4.24.3.0

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: 774fc1f559ec5f11db66bdb42369c85e7df2a50f9f7f361e293a16c173ca394b
4
- data.tar.gz: 5f45c3421a272bd377d3d8cb2457008e5ff2c5533ff3dcd0d25ae540cb549520
3
+ metadata.gz: 90fac650eedadc1e677e27563bda759e5aa1ea7b2d5b6627129f906516c21a82
4
+ data.tar.gz: 4098c6d271799034a18747154236426cde6c7b83eca4030d5d1292f8bc0f52e2
5
5
  SHA512:
6
- metadata.gz: 31ad8918c664072c497d08183dfc9662dda92548cd2afe876d962219e364dbb9bde7efa75ea509e03df84fd2f91561d2d753d15d54e1f405502097b3c1036b0b
7
- data.tar.gz: 9c14b3e9a70f70c63e95858eec0ee229ed46ff89b1217f715ac93b9388108f70ea9b428da127ad63eee0d356762e1fa7fe07c3481a819e698629703a37f3b735
6
+ metadata.gz: 97d0b7a8a715410c6772b4cbb8cd45052c5d0db5e3c7b6f78a62fd9d8f23536dc467727b4441e0585f339674e63d4f9c3e622cdaea04a968e80ffde5ea6ea5f6
7
+ data.tar.gz: 159d537c854c56d6502a8ed248f5b54fe76590a411d5013d5f40844dd816c1212e49692e42b882c7262267de859580491ce4c9f015972f4b0baaea5169a0dddd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.24.3.0
4
+
5
+ - Support `table` `items` data-binding of table row cell `background`, `foreground`, `font`, `image` to model attributes by convention based on specified `column_properties` (e.g. for `column_properties` model `name` attribute, automatically assume model `name_background` provides `[r, g, b]` array of color)
6
+ - Update Hello, Table! sample to demonstrate data-binding `table` `items` `background`, `foreground`, `font`, `image` to model attributes by convention, and to add `booked` attribute on `BaseballGame` to disable Book button when already booked
7
+ - Update Hello, Table! sample to add `booked` attribute to `BaseballGame` to disable Book button when already booked
8
+ - Update Hello, Table! sample to enable booking by hitting the ENTER keyboard button
9
+ - Optimize `table` data-binding performance by not recreating table-items when the table grows or stays at the same size, and by not updating a table item (row) when no changes have occurred (detect through diffing)
10
+ - Update `font` keyword and `FontProxy` to support lightweight creation/caching/sharing following Flyweight Design Pattern
11
+
3
12
  ## 4.24.2.3
4
13
 
5
14
  - Default `code_text` font name in Mac is changed back to `'Courier'`
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.24.2.3
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.24.3.0
2
2
  ## JRuby Desktop Development GUI Framework
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-swt.svg)](http://badge.fury.io/rb/glimmer-dsl-swt)
4
4
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer-dsl-swt.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
@@ -12,7 +12,7 @@
12
12
 
13
13
  ![Glimmer DSL for SWT Demo of Hello, World!](/images/glimmer-dsl-swt-demo-hello-world.gif)
14
14
 
15
- [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [SWT](https://www.eclipse.org/swt/) is a native GUI (Graphical User Interface) cross-platform desktop development library written in [JRuby](https://www.jruby.org/), an OS-threaded faster [JVM](https://www.java.com/en/download/help/whatis_java.html) version of [Ruby](https://www.ruby-lang.org/en/). [Glimmer](https://github.com/AndyObtiva/glimmer)'s main innovation is a declarative [Ruby DSL](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#glimmer-dsl-syntax) (Domain Specific Language) that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust [Eclipse SWT library](https://www.eclipse.org/swt/). [Glimmer](https://rubygems.org/gems/glimmer) additionally innovates by having built-in [data-binding](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#data-binding) support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models afterwards. Not only does Glimmer provide a large set of GUI [widgets](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#widgets), but it also supports drawing Canvas Graphics like [Shapes](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-shape-dsl) and [Animations](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-animation-dsl). To get started quickly, [Glimmer](https://rubygems.org/gems/glimmer) offers [scaffolding](docs/reference/GLIMMER_COMMAND.md#scaffolding) options for [Apps](#in-production), [Gems](docs/reference/GLIMMER_COMMAND.md#custom-shell-gem), and [Custom Widgets](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#custom-widgets). [Glimmer](https://rubygems.org/gems/glimmer) also includes native-executable [packaging](docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in [Ruby](https://www.ruby-lang.org/en/) as truly native DMG/PKG/APP files on the [Mac](https://www.apple.com/ca/macos), MSI/EXE files on [Windows](https://www.microsoft.com/en-ca/windows), and DEB/RPM files on [Linux](https://www.linux.org/). [Glimmer](https://github.com/AndyObtiva/glimmer) was the [first Ruby gem](https://rubygems.org/gems/glimmer) to bring [SWT](https://www.eclipse.org/swt/) (Standard Widget Toolkit) to [Ruby](https://www.ruby-lang.org/en/), thanks to creator [Andy Maleh](https://andymaleh.blogspot.com/), EclipseCon/EclipseWorld/RubyConf speaker.
15
+ [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [SWT](https://www.eclipse.org/swt/) (formerly [Glimmer](https://github.com/AndyObtiva/glimmer)) is a native GUI (Graphical User Interface) cross-platform desktop development library written in [JRuby](https://www.jruby.org/), an OS-threaded faster [JVM](https://www.java.com/en/download/help/whatis_java.html) version of [Ruby](https://www.ruby-lang.org/en/). [Glimmer](https://github.com/AndyObtiva/glimmer)'s main innovation is a declarative [Ruby DSL](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#glimmer-dsl-syntax) (Domain Specific Language) that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust [Eclipse SWT library](https://www.eclipse.org/swt/). [Glimmer](https://rubygems.org/gems/glimmer) additionally innovates by having built-in [data-binding](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#data-binding) support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models afterwards. Not only does Glimmer provide a large set of GUI [widgets](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#widgets), but it also supports drawing Canvas Graphics like [Shapes](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-shape-dsl) and [Animations](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-animation-dsl). To get started quickly, [Glimmer](https://rubygems.org/gems/glimmer) offers [scaffolding](docs/reference/GLIMMER_COMMAND.md#scaffolding) options for [Apps](#in-production), [Gems](docs/reference/GLIMMER_COMMAND.md#custom-shell-gem), and [Custom Widgets](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#custom-widgets). [Glimmer](https://rubygems.org/gems/glimmer) also includes native-executable [packaging](docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in [Ruby](https://www.ruby-lang.org/en/) as truly native DMG/PKG/APP files on the [Mac](https://www.apple.com/ca/macos), MSI/EXE files on [Windows](https://www.microsoft.com/en-ca/windows), and DEB/RPM files on [Linux](https://www.linux.org/). [Glimmer](https://github.com/AndyObtiva/glimmer) was the [first Ruby gem](https://rubygems.org/gems/glimmer) to bring [SWT](https://www.eclipse.org/swt/) (Standard Widget Toolkit) to [Ruby](https://www.ruby-lang.org/en/), thanks to creator [Andy Maleh](https://andymaleh.blogspot.com/), EclipseCon/EclipseWorld/RubyConf speaker.
16
16
 
17
17
  [<img src="https://covers.oreillystatic.com/images/9780596519650/lrg.jpg" width=105 /><br />
18
18
  Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) and [Chalmers/Gothenburg University Software Engineering Master's Lecture Material](http://www.cse.chalmers.se/~bergert/slides/guest_lecture_DSLs.pdf)
@@ -21,7 +21,7 @@ Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) an
21
21
 
22
22
  ![Eclipse SWT RCP NASA Mars Rover](/images/glimmer-eclipse-swt-rcp-nasa-mars-rover.png)
23
23
 
24
- [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.24.2.3 includes [SWT 4.24](https://download.eclipse.org/eclipse/downloads/drops4/R-4.24-202206070700/), which was released on June 7, 2022. Gem version numbers are in sync with the SWT library versions. The first two digits represent the SWT version number. The last two digits represent the minor and patch versions of Glimmer DSL for SWT.
24
+ [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.24.3.0 includes [SWT 4.24](https://download.eclipse.org/eclipse/downloads/drops4/R-4.24-202206070700/), which was released on June 7, 2022. Gem version numbers are in sync with the SWT library versions. The first two digits represent the SWT version number. The last two digits represent the minor and patch versions of Glimmer DSL for SWT.
25
25
 
26
26
  **Starting in version 4.20.0.0, [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) comes with the new [***Shine***](/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#shine) syntax** for highly intuitive and visually expressive View/Model Attribute Mapping, relying on `<=>` for bidirectional (two-way) data-binding and `<=` for unidirectional (one-way) data-binding, providing an alternative to the `bind` keyword. That was [originally conceived back in 2007](https://andymaleh.blogspot.com/2007/12/data-shining-in-glimmer.html).
27
27
 
@@ -338,7 +338,7 @@ jgem install glimmer-dsl-swt
338
338
 
339
339
  Or this command if you want a specific version:
340
340
  ```
341
- jgem install glimmer-dsl-swt -v 4.24.2.3
341
+ jgem install glimmer-dsl-swt -v 4.24.3.0
342
342
  ```
343
343
 
344
344
  `jgem` is JRuby's version of `gem` command.
@@ -366,7 +366,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u
366
366
 
367
367
  Add the following to `Gemfile`:
368
368
  ```
369
- gem 'glimmer-dsl-swt', '~> 4.24.2.3'
369
+ gem 'glimmer-dsl-swt', '~> 4.24.3.0'
370
370
  ```
371
371
 
372
372
  And, then run:
@@ -389,7 +389,7 @@ glimmer
389
389
  ```
390
390
 
391
391
  ```
392
- Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.24.2.3
392
+ Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.24.3.0
393
393
 
394
394
  Usage: glimmer [--bundler] [--pd] [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-jruby-option]...] (application.rb or task[task_args]) [[application2.rb]...]
395
395
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.24.2.3
1
+ 4.24.3.0
@@ -4019,8 +4019,8 @@ shell {
4019
4019
  text "Adult"
4020
4020
  width 120
4021
4021
  }
4022
- items bind(group, :people), column_properties(:name, :age, :adult)
4023
- selection bind(group, :selected_person)
4022
+ items <=> [group, :people, column_properties: [:name, :age, :adult]]
4023
+ selection <=> [group, :selected_person]
4024
4024
  on_mouse_up do |event|
4025
4025
  @table.edit_table_item(event.table_item, event.column_index)
4026
4026
  end
@@ -4051,6 +4051,24 @@ This automatically leverages the SWT TableEditor custom class behind the scenes,
4051
4051
  passed table item text into something else.
4052
4052
  It automatically persists the change to `items` data-bound model on ENTER/FOCUS-OUT or cancels on ESC/NO-CHANGE.
4053
4053
 
4054
+ ##### Table Item Properties
4055
+
4056
+ When data-binding a `table`'s `items`, extra [`TableItem` properties](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) are data-bound automatically by convention for `background` color, `foreground` color, `font`, and `image` if corresponding properties (attributes) are available on the model.
4057
+
4058
+ That means that if `column_properties` were `[:name, :age, :adult]`, then the following [`TableItem` properties](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) are also data-bound by convention:
4059
+ - `background` to `:name_background, :age_background, :adult_background` model attributes
4060
+ - `foreground` to `:name_foreground, :age_foreground, :adult_foreground` model attributes
4061
+ - `font` to `:name_font, :age_font, :adult_font` model attributes
4062
+ - `image` to `:name_image, :age_image, :adult_image` model attributes
4063
+
4064
+ Here are the expected values for each [`TableItem` property](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html):
4065
+ - `background`: Standard color symbol/string (e.g. `:red`), rgb array (e.g. `[24, 21, 239]`), or rgba array (e.g. `[128, 0, 128, 50]`)
4066
+ - `foreground`: Standard color symbol/string (e.g. `:red`), rgb array (e.g. `[24, 21, 239]`), or rgba array (e.g. `[128, 0, 128, 50]`)
4067
+ - `font`: font data hash having `:name`, `:height`, and/or `:style` keys (e.g. `{name: 'Courier New', height: 25, style: [:bold, :italic]}`)
4068
+ - `image`: image URL with or without image options (e.g. `'/usr/image1.png'` or `['/usr/image1.png', width: 20, height: 20]`)
4069
+
4070
+ ![Hello Table game booked rows](/images/glimmer-hello-table-game-booked-rows.png)
4071
+
4054
4072
  ##### Table Selection
4055
4073
 
4056
4074
  Table Selection data-binding is simply done via the `selection` property.
@@ -768,13 +768,17 @@ Hello, Table! Playoff Type Changed
768
768
 
769
769
  ![Hello Table](/images/glimmer-hello-table-playoff-type-changed.png)
770
770
 
771
+ Hello, Table! Context Menu
772
+
773
+ ![Hello Table](/images/glimmer-hello-table-context-menu.png)
774
+
771
775
  Hello, Table! Game Booked
772
776
 
773
777
  ![Hello Table](/images/glimmer-hello-table-game-booked.png)
774
778
 
775
- Hello, Table! Context Menu
779
+ Hello, Table! Game Booked Rows
776
780
 
777
- ![Hello Table](/images/glimmer-hello-table-context-menu.png)
781
+ ![Hello Table game booked rows](/images/glimmer-hello-table-game-booked-rows.png)
778
782
 
779
783
  #### Hello, Link!
780
784
 
Binary file
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'set'
23
+
22
24
  require 'glimmer/data_binding/observable_array'
23
25
  require 'glimmer/data_binding/observable_model'
24
26
  require 'glimmer/data_binding/observable'
@@ -33,6 +35,8 @@ module Glimmer
33
35
  include DataBinding::Observer
34
36
  include_package 'org.eclipse.swt'
35
37
  include_package 'org.eclipse.swt.widgets'
38
+
39
+ TABLE_ITEM_PROPERTIES = %w[background foreground font image]
36
40
 
37
41
  def initialize(parent, model_binding, column_properties = nil)
38
42
  @table = parent
@@ -56,40 +60,161 @@ module Glimmer
56
60
  end
57
61
  end
58
62
 
59
- def call(new_model_collection=nil, internal_sort: false)
63
+ def call(*args)
64
+ options = args.last.is_a?(Hash) ? args.pop : {}
65
+ internal_sort = options[:internal_sort] || false
66
+ new_model_collection = args.first
60
67
  Glimmer::SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @model_binding.binding_options[:sync_exec], override_async_exec: @model_binding.binding_options[:async_exec]) do
61
68
  new_model_collection = model_binding_evaluated_property = @model_binding.evaluate_property unless internal_sort # this ensures applying converters (e.g. :on_read)
62
- table_cells = @table.swt_widget.items.map {|item| @table.column_properties.size.times.map {|i| item.get_text(i)} }
63
- model_cells = new_model_collection.to_a.map {|m| @table.cells_for(m)}
64
- return if table_cells == model_cells
65
- if new_model_collection and new_model_collection.is_a?(Array)
66
- @table_items_observer_registration&.unobserve
67
- @table_items_observer_registration = observe(new_model_collection, @column_properties)
68
- add_dependent(@table_observer_registration => @table_items_observer_registration)
69
- @model_collection = new_model_collection
69
+ return if same_table_data?(new_model_collection)
70
+ if same_model_collection?(new_model_collection)
71
+ new_model_collection_attribute_values = model_collection_attribute_values(new_model_collection)
72
+ @table.swt_widget.items.each_with_index do |table_item, row_index|
73
+ next if new_model_collection_attribute_values[row_index] == @last_model_collection_attribute_values[row_index]
74
+ model = table_item.get_data
75
+ (0..(@column_properties.size-1)).each do |column_index|
76
+ new_model_attribute_values_for_index = model_attribute_values_for_index(new_model_collection_attribute_values[row_index], column_index)
77
+ last_model_attribute_values_for_index = model_attribute_values_for_index(@last_model_collection_attribute_values[row_index], column_index)
78
+ next if new_model_attribute_values_for_index == last_model_attribute_values_for_index
79
+ model_attribute = @column_properties[column_index]
80
+ update_table_item_properties_from_model(table_item, row_index, column_index, model, model_attribute)
81
+ end
82
+ end
83
+ @last_model_collection_attribute_values = new_model_collection_attribute_values
84
+ else
85
+ if new_model_collection and new_model_collection.is_a?(Array)
86
+ remove_dependent(@table_observer_registration => @table_items_observer_registration) if @table_items_observer_registration
87
+ @table_items_observer_registration&.unobserve
88
+ # TODO observe and update table items piecemeal per model instead of passing @column_properties
89
+ # TODO ensure unobserving models when they are no longer part of the table
90
+ @table_items_observer_registration = observe(new_model_collection, @column_properties)
91
+ add_dependent(@table_observer_registration => @table_items_observer_registration)
92
+ @table_items_property_observer_registration ||= {}
93
+ if !same_model_collection_with_different_sort?(new_model_collection)
94
+ TABLE_ITEM_PROPERTIES.each do |table_item_property|
95
+ remove_dependent(@table_observer_registration => @table_items_property_observer_registration[table_item_property]) if @table_items_property_observer_registration[table_item_property]
96
+ @table_items_property_observer_registration[table_item_property]&.unobserve
97
+ property_properties = @column_properties.map {|property| "#{property}_#{table_item_property}" }
98
+ @table_items_property_observer_registration[table_item_property] = observe(new_model_collection, property_properties)
99
+ add_dependent(@table_observer_registration => @table_items_property_observer_registration[table_item_property])
100
+ end
101
+ end
102
+ @model_collection = new_model_collection
103
+ end
104
+ populate_table(@model_collection, @table, @column_properties, internal_sort: internal_sort)
70
105
  end
71
- populate_table(@model_collection, @table, @column_properties, internal_sort: internal_sort)
72
106
  end
73
107
  end
74
108
 
75
109
  def populate_table(model_collection, parent, column_properties, internal_sort: false)
76
110
  selected_table_item_models = parent.swt_widget.getSelection.map(&:get_data)
77
111
  parent.finish_edit!
78
- parent.swt_widget.items.each(&:dispose)
79
- parent.swt_widget.removeAll
80
- model_collection.each do |model|
81
- table_item = TableItem.new(parent.swt_widget, SWT::SWTProxy[:none])
82
- for index in 0..(column_properties.size-1)
83
- table_item.setText(index, model.send(column_properties[index]).to_s)
112
+ dispose_start_index = @last_model_collection_attribute_values &&
113
+ (model_collection.count < @last_model_collection_attribute_values.count) &&
114
+ (@last_model_collection_attribute_values.count - (@last_model_collection_attribute_values.count - model_collection.count))
115
+ if dispose_start_index
116
+ table_items_to_dispose = parent.swt_widget.items[dispose_start_index..-1]
117
+ parent.swt_widget.remove(dispose_start_index, (@last_model_collection_attribute_values.count-1))
118
+ table_items_to_dispose.each(&:dispose)
119
+ end
120
+ model_collection.each_with_index do |model, row_index|
121
+ table_item_exists = @last_model_collection_attribute_values &&
122
+ @last_model_collection_attribute_values.count > 0 &&
123
+ row_index < @last_model_collection_attribute_values.count
124
+ table_item = table_item_exists ? parent.swt_widget.items[row_index] : TableItem.new(parent.swt_widget, SWT::SWTProxy[:none])
125
+ (0..(column_properties.size-1)).each do |column_index|
126
+ model_attribute = column_properties[column_index]
127
+ update_table_item_properties_from_model(table_item, row_index, column_index, model, model_attribute)
84
128
  end
85
129
  table_item.set_data(model)
86
130
  end
131
+ @last_model_collection_attribute_values = model_collection_attribute_values(model_collection)
87
132
  selected_table_items = parent.search {|item| selected_table_item_models.include?(item.get_data) }
88
133
  parent.swt_widget.setSelection(selected_table_items)
89
134
  sorted_model_collection = parent.sort!(internal_sort: internal_sort)
90
135
  call(sorted_model_collection, internal_sort: true) if @read_only_sort && !internal_sort && !sorted_model_collection.nil?
91
136
  parent.swt_widget.redraw if parent&.swt_widget&.respond_to?(:redraw)
92
137
  end
138
+
139
+ def update_table_item_properties_from_model(table_item, row_index, column_index, model, model_attribute)
140
+ Glimmer::SWT::DisplayProxy.instance.sync_exec do
141
+ old_table_item_values = @last_model_collection_attribute_values &&
142
+ @last_model_collection_attribute_values[row_index] &&
143
+ model_attribute_values_for_index(@last_model_collection_attribute_values[row_index], column_index)
144
+ text_value = model.send(model_attribute).to_s
145
+ old_table_item_value = old_table_item_values && old_table_item_values[0]
146
+ table_item.set_text(column_index, text_value) if old_table_item_value.nil? || text_value != old_table_item_value
147
+ TABLE_ITEM_PROPERTIES.each do |table_item_property|
148
+ if model.respond_to?("#{model_attribute}_#{table_item_property}")
149
+ table_item_value = model.send("#{model_attribute}_#{table_item_property}")
150
+ old_table_item_value = old_table_item_values && old_table_item_values[1 + TABLE_ITEM_PROPERTIES.index(table_item_property)]
151
+ if old_table_item_value.nil? || (table_item_value != old_table_item_value)
152
+ table_item_value = Glimmer::SWT::ColorProxy.create(*table_item_value).swt_color if table_item_value && %w[background foreground].include?(table_item_property.to_s)
153
+ table_item_value = Glimmer::SWT::FontProxy.create(table_item_value).swt_font if table_item_value && table_item_property.to_s == 'font'
154
+ table_item_value = Glimmer::SWT::ImageProxy.create(*table_item_value).swt_image if table_item_value && table_item_property.to_s == 'image'
155
+ table_item.send("set_#{table_item_property}", column_index, table_item_value)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def same_table_data?(new_model_collection)
163
+ (["text"] + TABLE_ITEM_PROPERTIES).all? do |table_item_property|
164
+ table_cells = @table.swt_widget.items.map do |item|
165
+ model = item.get_data
166
+ @table.column_properties.each_with_index.map do |column_property, i|
167
+ model_attribute = "#{column_property}"
168
+ model_attribute = "#{model_attribute}_#{table_item_property}" if TABLE_ITEM_PROPERTIES.include?(table_item_property)
169
+ item.send("get_#{table_item_property}", i) if model.respond_to?(model_attribute)
170
+ end
171
+ end
172
+ model_cells = new_model_collection.to_a.map do |m|
173
+ @table.cells_for(m, table_item_property: table_item_property)
174
+ end
175
+ model_cells = model_cells.map do |row|
176
+ row.map do |model_cell|
177
+ if model_cell
178
+ if %w[background foreground].include?(table_item_property.to_s)
179
+ Glimmer::SWT::ColorProxy.create(*model_cell).swt_color
180
+ elsif table_item_property.to_s == 'font'
181
+ Glimmer::SWT::FontProxy.create(model_cell).swt_font
182
+ elsif table_item_property.to_s == 'image'
183
+ Glimmer::SWT::ImageProxy.create(*model_cell).swt_image
184
+ else
185
+ model_cell
186
+ end
187
+ end
188
+ end
189
+ end
190
+ table_cells == model_cells
191
+ end
192
+ end
193
+
194
+ def same_model_collection?(new_model_collection)
195
+ new_model_collection == table_item_model_collection
196
+ end
197
+
198
+ def same_model_collection_with_different_sort?(new_model_collection)
199
+ Set.new(new_model_collection) == Set.new(table_item_model_collection)
200
+ end
201
+
202
+ def table_item_model_collection
203
+ @table.swt_widget.items.map(&:get_data)
204
+ end
205
+
206
+ def model_collection_attribute_values(model_collection)
207
+ model_collection.map do |model|
208
+ (["text"] + TABLE_ITEM_PROPERTIES).map do |table_item_property|
209
+ @table.cells_for(model, table_item_property: table_item_property)
210
+ end
211
+ end
212
+ end
213
+
214
+ def model_attribute_values_for_index(model_attribute_values, index)
215
+ model_attribute_values.map {|attribute_values| attribute_values[index]}
216
+ end
217
+
93
218
  end
94
219
  end
95
220
  end
@@ -41,7 +41,7 @@ module Glimmer
41
41
  end
42
42
 
43
43
  def interpret(parent, keyword, *args, &block)
44
- Glimmer::SWT::FontProxy.new(*args)
44
+ Glimmer::SWT::FontProxy.create(*args)
45
45
  end
46
46
  end
47
47
  end
@@ -36,14 +36,24 @@ module Glimmer
36
36
  #
37
37
  # Follows the Proxy Design Pattern
38
38
  class FontProxy
39
- ERROR_INVALID_FONT_STYLE = " is an invalid font style! Valid values are :normal, :bold, and :italic"
40
- FONT_STYLES = [:normal, :bold, :italic]
39
+ class << self
40
+ def create(*args)
41
+ flyweight_font_proxies[args] ||= new(*args)
42
+ end
43
+
44
+ # Flyweight Design Pattern memoization cache. Can be cleared if memory is needed.
45
+ def flyweight_font_proxies
46
+ @flyweight_font_proxies ||= {}
47
+ end
48
+ end
41
49
 
42
50
  include_package 'org.eclipse.swt.graphics'
51
+
52
+ ERROR_INVALID_FONT_STYLE = " is an invalid font style! Valid values are :normal, :bold, and :italic"
53
+ FONT_STYLES = [:normal, :bold, :italic]
43
54
 
44
55
  attr_reader :widget_proxy, :swt_font, :font_properties
45
56
 
46
-
47
57
  # Builds a new font proxy from passed in widget_proxy and font_properties hash,
48
58
  #
49
59
  # It begins with existing SWT widget font and amends it with font properties.
@@ -419,8 +419,14 @@ module Glimmer
419
419
  @editor = args
420
420
  end
421
421
 
422
- def cells_for(model)
423
- column_properties.map {|property| model.send(property)}
422
+ def cells_for(model, table_item_property: :text)
423
+ if table_item_property.to_s == 'text'
424
+ column_properties.map {|column_property| model.send(column_property)}
425
+ else
426
+ column_properties.map do |column_property|
427
+ model.send("#{column_property}_#{table_item_property}") if model.respond_to?("#{column_property}_#{table_item_property}")
428
+ end
429
+ end
424
430
  end
425
431
 
426
432
  def cells
@@ -28,3 +28,4 @@ Hello, Canvas Transform!: ePIAF5EMsE0
28
28
  Parking: kw-6icVgDR4
29
29
  Hello, Custom Widget!: aJHLo5yLDZc
30
30
  Hello, Custom Shell!: c8Eb8GWM_XQ
31
+ Hello, Custom Shape!: H3J8ecp30Ak
@@ -25,17 +25,17 @@ require 'glimmer-dsl-swt'
25
25
  class StickFigure
26
26
  include Glimmer::UI::CustomShape
27
27
 
28
- options :x, :y, :width, :height
28
+ options :figure_x, :figure_y, :figure_width, :figure_height
29
29
 
30
30
  before_body do
31
- @head_width = width*0.2
32
- @head_height = height*0.2
33
- @trunk_height = height*0.4
34
- @extremity_length = height*0.4
31
+ @head_width = figure_width*0.2
32
+ @head_height = figure_height*0.2
33
+ @trunk_height = figure_height*0.4
34
+ @extremity_length = figure_height*0.4
35
35
  end
36
36
 
37
37
  body {
38
- shape(x + @head_width/2.0 + @extremity_length, y) {
38
+ shape(figure_x + @head_width/2.0 + @extremity_length, figure_y) {
39
39
  oval(0, 0, @head_width, @head_height)
40
40
  line(@head_width/2.0, @head_height, @head_width/2.0, @head_height + @trunk_height)
41
41
  line(@head_width/2.0, @head_height + @trunk_height, @head_width/2.0 + @extremity_length, @head_height + @trunk_height + @extremity_length)
@@ -47,7 +47,7 @@ class StickFigure
47
47
  end
48
48
 
49
49
  class HelloCustomShape
50
- include Glimmer::UI::CustomShell
50
+ include Glimmer::UI::Application
51
51
 
52
52
  WIDTH = 220
53
53
  HEIGHT = 235
@@ -60,12 +60,12 @@ class HelloCustomShape
60
60
  @canvas = canvas {
61
61
  background :white
62
62
 
63
- 15.times { |n|
63
+ 15.times do |n|
64
64
  x_location = (rand*WIDTH/2).to_i%WIDTH + (rand*15).to_i
65
65
  y_location = (rand*HEIGHT/2).to_i%HEIGHT + (rand*15).to_i
66
66
  foreground_color = rgb(rand*255, rand*255, rand*255)
67
67
 
68
- a_stick_figure = stick_figure(x: x_location, y: y_location, width: 35+n*2, height: 35+n*2) {
68
+ a_stick_figure = stick_figure(figure_x: x_location, figure_y: y_location, figure_width: 35+n*2, figure_height: 35+n*2) {
69
69
  foreground foreground_color
70
70
  drag_and_move true
71
71
 
@@ -74,7 +74,7 @@ class HelloCustomShape
74
74
  a_stick_figure.foreground = rgb(rand*255, rand*255, rand*255)
75
75
  end
76
76
  }
77
- }
77
+ end
78
78
  }
79
79
  }
80
80
  }
@@ -89,6 +89,7 @@ class HelloTable
89
89
  def playoff_type=(new_playoff_type)
90
90
  @playoff_type = new_playoff_type
91
91
  self.schedule=(all_playoff_games[@playoff_type])
92
+ self.selected_game = schedule.first unless selected_game.nil?
92
93
  end
93
94
 
94
95
  def playoff_type_options
@@ -118,15 +119,24 @@ class HelloTable
118
119
  'St Louis Cardinals' => 'Busch Stadium',
119
120
  }
120
121
 
121
- attr_accessor :date_time, :home_team, :away_team, :ballpark, :promotion
122
+ ATTRIBUTES = [:game_date, :game_time, :home_team, :away_team, :ballpark, :promotion]
123
+ ATTRIBUTES_BACKGROUND = ATTRIBUTES.map {|attribute| "#{attribute}_background"}
124
+ ATTRIBUTES_FOREGROUND = ATTRIBUTES.map {|attribute| "#{attribute}_foreground"}
125
+ ATTRIBUTES_FONT = ATTRIBUTES.map {|attribute| "#{attribute}_font"}
126
+ ATTRIBUTES_IMAGE = ATTRIBUTES.map {|attribute| "#{attribute}_image"}
122
127
 
128
+ attr_accessor *([:booked, :date_time] + ATTRIBUTES + ATTRIBUTES_BACKGROUND + ATTRIBUTES_FOREGROUND + ATTRIBUTES_FONT + ATTRIBUTES_IMAGE)
129
+ alias booked? booked
130
+
123
131
  def initialize(date_time, home_team, away_team, promotion = 'N/A')
124
132
  self.date_time = date_time
125
133
  self.home_team = home_team
126
134
  self.away_team = away_team
127
135
  self.promotion = promotion
136
+ self.ballpark_image = [File.expand_path('hello_table/baseball_park.png', __dir__), width: 20, height: 20]
137
+ self.booked = false
138
+
128
139
  observe(self, :date_time) do |new_value|
129
- notify_observers(:game_date)
130
140
  notify_observers(:game_time)
131
141
  end
132
142
  end
@@ -177,8 +187,42 @@ class HelloTable
177
187
  end
178
188
 
179
189
  def book!
190
+ self.booked = true
191
+ self.background = :dark_green
192
+ self.foreground = :white
193
+ self.font = {style: :italic}
180
194
  "Thank you for booking #{to_s}"
181
195
  end
196
+
197
+ # Sets background for all attributes
198
+ def background=(color)
199
+ self.game_date_background = color
200
+ self.game_time_background = color
201
+ self.home_team_background = color
202
+ self.away_team_background = color
203
+ self.ballpark_background = color
204
+ self.promotion_background = color
205
+ end
206
+
207
+ # Sets foreground for all attributes
208
+ def foreground=(color)
209
+ self.game_date_foreground = color
210
+ self.game_time_foreground = color
211
+ self.home_team_foreground = color
212
+ self.away_team_foreground = color
213
+ self.ballpark_foreground = color
214
+ self.promotion_foreground = color
215
+ end
216
+
217
+ # Sets font for all attributes
218
+ def font=(font_properties)
219
+ self.game_date_font = font_properties
220
+ self.game_time_font = font_properties
221
+ self.home_team_font = font_properties
222
+ self.away_team_font = font_properties
223
+ self.ballpark_font = font_properties
224
+ self.promotion_font = font_properties
225
+ end
182
226
  end
183
227
 
184
228
  include Glimmer::UI::CustomShell
@@ -246,8 +290,27 @@ class HelloTable
246
290
  # default text editor is used here
247
291
  }
248
292
 
249
- # Data-bind table items (rows) to a model collection property, specifying column properties ordering per nested model
250
- items <=> [BaseballGame, :schedule, column_properties: [:game_date, :game_time, :ballpark, :home_team, :away_team, :promotion]]
293
+ # This is a contextual pop up menu that shows up when right-clicking table rows
294
+ menu {
295
+ menu_item {
296
+ text 'Book'
297
+
298
+ on_widget_selected do
299
+ book_selected_game
300
+ end
301
+ }
302
+ }
303
+
304
+ # Data-bind table items (rows) to a model collection (BaseballGame.schedule),
305
+ # mapping columns in declaration order to row model properties (attributes)
306
+ # By convention, every column property can be accompanied by extra properties
307
+ # with the following suffixes: `_background`, `_foreground`, `_font`, and `_image`
308
+ # For example, for `game_date`, model could also implement these related properties:
309
+ # `game_date_background`, `game_date_foreground`, `game_date_font`, `game_date_image`
310
+ # That is done in order to let the table widget set extra properties if needed.
311
+ items <=> [BaseballGame, :schedule,
312
+ column_properties: [:game_date, :game_time, :ballpark, :home_team, :away_team, :promotion]
313
+ ]
251
314
 
252
315
  # Data-bind table selection
253
316
  selection <=> [BaseballGame, :selected_game]
@@ -258,22 +321,16 @@ class HelloTable
258
321
  # Sort by these additional properties after handling sort by the column the user clicked
259
322
  additional_sort_properties :date, :time, :home_team, :away_team, :ballpark, :promotion
260
323
 
261
- menu {
262
- menu_item {
263
- text 'Book'
264
-
265
- on_widget_selected do
266
- book_selected_game
267
- end
268
- }
269
- }
324
+ on_key_pressed do |key_event|
325
+ book_selected_game if key_event.keyCode == swt(:cr)
326
+ end
270
327
  }
271
328
 
272
329
  button {
273
330
  text 'Book Selected Game'
274
331
  layout_data :center, :center, true, false
275
332
  font height: 14
276
- enabled <= [BaseballGame, :selected_game]
333
+ enabled <= [BaseballGame, 'selected_game.booked', on_read: ->(value) { value == false }]
277
334
 
278
335
  on_widget_selected do
279
336
  book_selected_game
@@ -283,6 +340,8 @@ class HelloTable
283
340
  }
284
341
 
285
342
  def book_selected_game
343
+ return if BaseballGame.selected_game.booked?
344
+
286
345
  message_box {
287
346
  text 'Baseball Game Booked!'
288
347
  message BaseballGame.selected_game.book!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.24.2.3
4
+ version: 4.24.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-26 00:00:00.000000000 Z
11
+ date: 2022-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement