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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +6 -6
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +20 -2
- data/docs/reference/GLIMMER_SAMPLES.md +6 -2
- data/glimmer-dsl-swt.gemspec +0 -0
- data/lib/glimmer/data_binding/table_items_binding.rb +141 -16
- data/lib/glimmer/dsl/swt/font_expression.rb +1 -1
- data/lib/glimmer/swt/font_proxy.rb +13 -3
- data/lib/glimmer/swt/table_proxy.rb +8 -2
- data/samples/elaborate/meta_sample/tutorials.yml +1 -0
- data/samples/hello/hello_custom_shape.rb +10 -10
- data/samples/hello/hello_table.rb +73 -14
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90fac650eedadc1e677e27563bda759e5aa1ea7b2d5b6627129f906516c21a82
|
4
|
+
data.tar.gz: 4098c6d271799034a18747154236426cde6c7b83eca4030d5d1292f8bc0f52e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
1
|
+
4.24.3.0
|
@@ -4019,8 +4019,8 @@ shell {
|
|
4019
4019
|
text "Adult"
|
4020
4020
|
width 120
|
4021
4021
|
}
|
4022
|
-
items
|
4023
|
-
selection
|
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!
|
779
|
+
Hello, Table! Game Booked Rows
|
776
780
|
|
777
|
-
![Hello Table](/images/glimmer-hello-table-
|
781
|
+
![Hello Table game booked rows](/images/glimmer-hello-table-game-booked-rows.png)
|
778
782
|
|
779
783
|
#### Hello, Link!
|
780
784
|
|
data/glimmer-dsl-swt.gemspec
CHANGED
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(
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
@@ -36,14 +36,24 @@ module Glimmer
|
|
36
36
|
#
|
37
37
|
# Follows the Proxy Design Pattern
|
38
38
|
class FontProxy
|
39
|
-
|
40
|
-
|
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
|
-
|
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
|
@@ -25,17 +25,17 @@ require 'glimmer-dsl-swt'
|
|
25
25
|
class StickFigure
|
26
26
|
include Glimmer::UI::CustomShape
|
27
27
|
|
28
|
-
options :
|
28
|
+
options :figure_x, :figure_y, :figure_width, :figure_height
|
29
29
|
|
30
30
|
before_body do
|
31
|
-
@head_width =
|
32
|
-
@head_height =
|
33
|
-
@trunk_height =
|
34
|
-
@extremity_length =
|
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(
|
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::
|
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
|
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(
|
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
|
-
|
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
|
-
#
|
250
|
-
|
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
|
-
|
262
|
-
|
263
|
-
|
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, :
|
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.
|
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-
|
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
|