glimmer-dsl-swt 4.24.2.3 → 4.24.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: 774fc1f559ec5f11db66bdb42369c85e7df2a50f9f7f361e293a16c173ca394b
4
- data.tar.gz: 5f45c3421a272bd377d3d8cb2457008e5ff2c5533ff3dcd0d25ae540cb549520
3
+ metadata.gz: 89250fa7cc394da176eb7cd91a17c7ad388607c69927a7e22b6b1be62333a0b8
4
+ data.tar.gz: e7e09c62b782c682c0abdb8722001c8925268cfe4bab49b536eb58f3f32fb697
5
5
  SHA512:
6
- metadata.gz: 31ad8918c664072c497d08183dfc9662dda92548cd2afe876d962219e364dbb9bde7efa75ea509e03df84fd2f91561d2d753d15d54e1f405502097b3c1036b0b
7
- data.tar.gz: 9c14b3e9a70f70c63e95858eec0ee229ed46ff89b1217f715ac93b9388108f70ea9b428da127ad63eee0d356762e1fa7fe07c3481a819e698629703a37f3b735
6
+ metadata.gz: 136c2625e94629b690a325bdc3c8669a36c612f9f651b04faa5be3dcbcc86b57ae5345c23fcce1b10656b9dca5e8a4e96a318147907785a5bff18eac3dd4b130
7
+ data.tar.gz: 6d1c069b332ccd3139cf0c6377dd64b5341ccd84cc4dda3c72f5255c0eaeff0639bbfcdea35cb6b66baa84fb9ed1093143cafb4897f6ba2b2198dd494e0033c3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.24.3.2
4
+
5
+ - Have `table` data-binding infer model attribute names from column names by convention (no need to specify `column_properties`)
6
+ - Support `table` data-binding `column_properties` mapping of column names to model attribute names via a `Hash`
7
+ - Support `table` data-binding alias of `column_attributes` in place of `column_properties` because the word 'attribute' is more Ruby-idiomatic than 'property' in the Ruby world
8
+ - Handle boundary condition of font height reaching 0 on repeated zoom out of `code_text`
9
+ - Battleship Video Tutorial in Glimmer Meta-Sample
10
+
11
+ ## 4.24.3.1
12
+
13
+ - `code_text` default behavior support of zoom in (CMD+= on Mac, CTRL+= on Win/Linux), zoom out (CMD+- on Mac, CTRL+- on Win/Linux), and restore original font height (CMD+0 on Mac, CTRL+0 on Win/Linux).
14
+
15
+ ## 4.24.3.0
16
+
17
+ - 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)
18
+ - 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
19
+ - Update Hello, Table! sample to add `booked` attribute to `BaseballGame` to disable Book button when already booked
20
+ - Update Hello, Table! sample to enable booking by hitting the ENTER keyboard button
21
+ - 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)
22
+ - Update `font` keyword and `FontProxy` to support lightweight creation/caching/sharing following Flyweight Design Pattern
23
+
3
24
  ## 4.24.2.3
4
25
 
5
26
  - 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.2
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.2 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.2
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.2'
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.2
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.2
@@ -3996,13 +3996,13 @@ You may learn more about Glimmer's data-binding syntax by reading the code under
3996
3996
 
3997
3997
  The SWT Tree widget renders a multi-column data table, such as a contact listing or a sales report.
3998
3998
 
3999
- To data-bind a Table, you need the main model, the collection property, and the text display attribute for each table column.
3999
+ To data-bind a Table, you need the main model and the collection property. The text for each row cell will be inferred from column names as underscored model attributes. For example, for a column named "Full Name", it is assumed by convention that the model has a `full_name` attribute.
4000
4000
 
4001
- This involves using the `bind` keyword mentioned above in addition to a special `column_properties` keyword that takes the table column text attribute methods.
4001
+ Data-binding involves using the `<=` operator (one-way data-binding) or `<=>` operator (two-way data-binding), and an optional `column_attributes` kwarg (alias: `column_properties`) that takes an array that maps table columns to model attributes or a hash that maps column name strings to model attributes.
4002
4002
 
4003
- It assumes you have defined the table columns via `table_column` widget.
4003
+ It assumes you have already defined table columns via the `table_column` `table`-nested widget.
4004
4004
 
4005
- Example:
4005
+ Example (automatically inferring table items' [rows'] model attributes by convention from column names):
4006
4006
 
4007
4007
  ```ruby
4008
4008
  shell {
@@ -4019,8 +4019,10 @@ 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
+
4023
+ items <=> [group, :people]
4024
+ selection <=> [group, :selected_person]
4025
+
4024
4026
  on_mouse_up do |event|
4025
4027
  @table.edit_table_item(event.table_item, event.column_index)
4026
4028
  end
@@ -4028,15 +4030,71 @@ shell {
4028
4030
  }
4029
4031
  ```
4030
4032
 
4031
- The code above includes two data-bindings:
4032
- - Table `items`, which first bind to the model collection property (group.people), and then maps each column property (name, age, adult) for displaying each table item column.
4033
- - Table `selection`, which binds the single table item selected by the user to the attribute denoted by the `bind` keyword (or binds multiple table items selected for a table with `:multi` SWT style)
4033
+ The code above includes two data-bindings and a listener:
4034
+ - Table `items`, which first data-binds to the model collection property (group.people), and then maps each column to a model attribute (name, age, adult) for displaying each table item column.
4035
+ - Table `selection`, which data-binds the single table item (row) selected by the user to the model attribute denoted by `<=>` (or data-binds multiple table items to a model attribute array value for a table with `:multi` SWT style)
4034
4036
  - The `on_mouse_up` event handler invokes `@table.edit_table_item(event.table_item, event.column_index)` to start edit mode on the clicked table item cell, and then saves or cancel depending on whether the user hits ENTER or ESC once done editing (or focus-out after either making a change or not making any changes.)
4035
4037
 
4036
- Additionally, Table `items` data-binding automatically stores each node model unto the SWT TableItem object via `setData` method. This enables things like searchability.
4038
+ Example (specifying `column_attributes` explicitly because some diverge from column names):
4039
+
4040
+ ```ruby
4041
+ shell {
4042
+ @table = table {
4043
+ table_column {
4044
+ text "Full Name"
4045
+ width 120
4046
+ }
4047
+ table_column {
4048
+ text "Age in Years"
4049
+ width 120
4050
+ }
4051
+ table_column {
4052
+ text "Adult"
4053
+ width 120
4054
+ }
4055
+
4056
+ items <=> [group, :people, column_attributes: {'Full Name' => :name, 'Age in Years' => :age}]
4057
+ selection <=> [group, :selected_person]
4058
+
4059
+ on_mouse_up do |event|
4060
+ @table.edit_table_item(event.table_item, event.column_index)
4061
+ end
4062
+ }
4063
+ }
4064
+ ```
4037
4065
 
4038
- The table widget in Glimmer is represented by a subclass of `WidgetProxy` called `TableProxy`.
4039
- TableProxy includes a `search` method that takes a block to look for a table item.
4066
+ Example (specifying `column_attributes` explicitly because all diverge from column names):
4067
+
4068
+ ```ruby
4069
+ shell {
4070
+ @table = table {
4071
+ table_column {
4072
+ text "Full Name"
4073
+ width 120
4074
+ }
4075
+ table_column {
4076
+ text "Age in Years"
4077
+ width 120
4078
+ }
4079
+ table_column {
4080
+ text "Is Adult"
4081
+ width 120
4082
+ }
4083
+
4084
+ items <=> [group, :people, column_attributes: [:name, :age, :adult]]
4085
+ selection <=> [group, :selected_person]
4086
+
4087
+ on_mouse_up do |event|
4088
+ @table.edit_table_item(event.table_item, event.column_index)
4089
+ end
4090
+ }
4091
+ }
4092
+ ```
4093
+
4094
+ Additionally, Table `items` data-binding automatically stores each row model in the [SWT `TableItem`](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) object representing it, by using the `set_data` method. This enables things like searchability.
4095
+
4096
+ The table widget in Glimmer is represented by a subclass of `Glimmer::SWT::WidgetProxy` called `Glimmer::SWT::TableProxy`.
4097
+ `Glimmer::SWT::TableProxy` includes a `search` method that takes a block to look for a table item.
4040
4098
 
4041
4099
  Example:
4042
4100
 
@@ -4044,13 +4102,31 @@ Example:
4044
4102
  found_array = @table.search { |table_item| table_item.getData == company.owner }
4045
4103
  ```
4046
4104
 
4047
- This finds a person. The array is a Java array. This enables easy passing of it to SWT `Table#setSelection` method, which expects a Java array of `TableItem` objects.
4105
+ This finds a person. The array is a Java array. This enables easy passing of it to SWT `Table#setSelection` method, which expects a Java array of [`TableItem`](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) objects.
4048
4106
 
4049
4107
  To edit a table, you must invoke `TableProxy#edit_selected_table_item(column_index, before_write: nil, after_write: nil, after_cancel: nil)` or `TableProxy#edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)`.
4050
4108
  This automatically leverages the SWT TableEditor custom class behind the scenes, displaying a text widget to the user to change the selected or
4051
4109
  passed table item text into something else.
4052
4110
  It automatically persists the change to `items` data-bound model on ENTER/FOCUS-OUT or cancels on ESC/NO-CHANGE.
4053
4111
 
4112
+ ##### Table Item Properties
4113
+
4114
+ 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.
4115
+
4116
+ That means that if `column_attributes` 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:
4117
+ - `background` to `:name_background, :age_background, :adult_background` model attributes
4118
+ - `foreground` to `:name_foreground, :age_foreground, :adult_foreground` model attributes
4119
+ - `font` to `:name_font, :age_font, :adult_font` model attributes
4120
+ - `image` to `:name_image, :age_image, :adult_image` model attributes
4121
+
4122
+ 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):
4123
+ - `background`: Standard color symbol/string (e.g. `:red`), rgb array (e.g. `[24, 21, 239]`), or rgba array (e.g. `[128, 0, 128, 50]`)
4124
+ - `foreground`: Standard color symbol/string (e.g. `:red`), rgb array (e.g. `[24, 21, 239]`), or rgba array (e.g. `[128, 0, 128, 50]`)
4125
+ - `font`: font data hash having `:name`, `:height`, and/or `:style` keys (e.g. `{name: 'Courier New', height: 25, style: [:bold, :italic]}`)
4126
+ - `image`: image URL with or without image options (e.g. `'/usr/image1.png'` or `['/usr/image1.png', width: 20, height: 20]`)
4127
+
4128
+ ![Hello Table game booked rows](/images/glimmer-hello-table-game-booked-rows.png)
4129
+
4054
4130
  ##### Table Selection
4055
4131
 
4056
4132
  Table Selection data-binding is simply done via the `selection` property.
@@ -4086,7 +4162,7 @@ shell {
4086
4162
  text "Adult"
4087
4163
  width 120
4088
4164
  }
4089
- items bind(group, :people), column_properties(:name, :age, :adult)
4165
+ items <=> [group, :people]
4090
4166
  selection bind(group, :selected_person)
4091
4167
  }
4092
4168
  }
@@ -4113,7 +4189,7 @@ shell {
4113
4189
  width 120
4114
4190
  editor :checkbox
4115
4191
  }
4116
- items bind(group, :people), column_properties(:name, :age, :adult)
4192
+ items <=> [group, :people]
4117
4193
  selection bind(group, :selected_person)
4118
4194
  }
4119
4195
  }
@@ -4152,7 +4228,7 @@ shell {
4152
4228
  # assume there is a `Person#industry_options` property method on the model to provide items to the `combo`
4153
4229
  editor :combo, :read_only # passes :ready_only SWT style to `combo` widget
4154
4230
  }
4155
- items bind(group, :people), column_properties(:formatted_date, :industry)
4231
+ items <=> [group, :people, column_attributes: {'Date of Birth' => :formatted_date}]
4156
4232
  selection bind(group, :selected_person)
4157
4233
  }
4158
4234
  }
@@ -4211,7 +4287,7 @@ Example:
4211
4287
  sort { |d1, d2| d1.to_date <=> d2.to_date }
4212
4288
  }
4213
4289
  additional_sort_properties :project_name, :duration_in_hours, :name
4214
- items bind(Task, :list), column_properties(:name, :project_name, :duration, :priority, :start_date)
4290
+ items <=> [Task, :list, column_attributes: [:name, :project_name, :duration, :priority, :start_date]]
4215
4291
  # ...
4216
4292
  }
4217
4293
  # ...
@@ -4224,7 +4300,7 @@ Here is an explanation of the example above:
4224
4300
  - Task Start Date table column has a custom sort comparator block
4225
4301
  - Additional (secondary) sort properties are applied when sorting by Task, Project, or Duration in the order specified
4226
4302
 
4227
- `bind(model, :property, read_only_sort: true)` could be used with items to make sorting not propagate sorting changes to model.
4303
+ `<= [model, :property, read_only_sort: true]` could be used with items to make sorting not propagate sorting changes to model.
4228
4304
 
4229
4305
  #### Tree
4230
4306
 
@@ -4807,7 +4883,7 @@ You may see another example at the [Hello, Radio Group!](/docs/reference/GLIMMER
4807
4883
 
4808
4884
  ##### Code Text Custom Widget
4809
4885
 
4810
- `code_text` is a Glimmer built-in custom widget that displays syntax highlighted code (e.g. Ruby/JavaScript/HTML code) for 204 languages (see [options](#code-text-options) for the full list) by automating customizations for the SWT [StyledText](https://help.eclipse.org/2020-09/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/custom/StyledText.html) widget.
4886
+ `code_text` is a Glimmer built-in custom widget that displays syntax highlighted code (e.g. Ruby/JavaScript/HTML code) for 204 languages (see [options](#code-text-options) for the full list) by automating customizations for the SWT [StyledText](https://help.eclipse.org/2020-09/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/custom/StyledText.html) widget, including ability to zoom font in and out, or restore original font height (more details below).
4811
4887
 
4812
4888
  To utilize, simply use `code_text` in place of the multi-line `text` and `styled_text` widgets. If you set the `code_text` `text` property value to multi-line code content (e.g. Ruby/JavaScript/HTML code), it automatically styles it with syntax highlighting.
4813
4889
 
@@ -5133,6 +5209,9 @@ This adds some default keyboard shortcuts:
5133
5209
  - CMD+A (CTRL+A on Windows/Linux) to select all
5134
5210
  - CTRL+A on Mac to jump to beginning of line
5135
5211
  - CTRL+E on Mac to jump to end of line
5212
+ - CMD+= (CTRL+= on Windows/Linux) to zoom in (bump font height up by 1)
5213
+ - CMD+- (CTRL+- on Windows/Linux) to zoom out (bump font height down by 1)
5214
+ - CMD+0 (CTRL+0 on Windows/Linux) to restore to original font height
5136
5215
  - Attempts to add proper indentation upon adding a new line when hitting ENTER (currently supporting Ruby only)
5137
5216
 
5138
5217
  If you prefer it to be vanilla with no default key event listeners, then pass the `default_behavior: false` option.
@@ -730,7 +730,7 @@ Hello, Spinner!
730
730
 
731
731
  #### Hello, Table!
732
732
 
733
- This sample demonstrates the use of [table](#table) widget in Glimmer, including data-binding, multi-type editing, sorting, and filtering.
733
+ This sample demonstrates the use of [table](/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#table) widget in Glimmer, including data-binding, multi-type editing, sorting, and filtering.
734
734
 
735
735
  Code:
736
736
 
@@ -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
 
@@ -816,17 +820,29 @@ Code:
816
820
 
817
821
  [samples/hello/hello_code_text.rb](/samples/hello/hello_code_text.rb)
818
822
 
819
- Hello, Code Text! Ruby Language / Glimmer Theme / Show Line Numbers (default width of 4)
823
+ Hello, Code Text! HTML Language / GitHub Theme / No Line Numbers
820
824
 
821
- ![Hello Code Text Ruby](/images/glimmer-hello-code-text-ruby.png)
825
+ ![Hello Code Text HTML](/images/glimmer-hello-code-text-html.png)
822
826
 
823
827
  Hello, Code Text! JavaScript Language / Pastie Theme / Show Line Numbers (custom width of 2)
824
828
 
825
829
  ![Hello Code Text JavaScript](/images/glimmer-hello-code-text-javascript.png)
826
830
 
827
- Hello, Code Text! HTML Language / GitHub Theme / No Line Numbers
831
+ Hello, Code Text! Ruby Language / Glimmer Theme / Show Line Numbers (default width of 4)
828
832
 
829
- ![Hello Code Text HTML](/images/glimmer-hello-code-text-html.png)
833
+ ![Hello Code Text Ruby](/images/glimmer-hello-code-text-ruby.png)
834
+
835
+ Hello, Code Text! Zoom In (via keyboard shortcut CMD+= on Mac, CTRL+= on Win/Linux)
836
+
837
+ ![Hello Code Text Zoom In](/images/glimmer-hello-code-text-zoom-in.png)
838
+
839
+ Hello, Code Text! Zoom Out (via keyboard shortcut CMD+- on Mac, CTRL+- on Win/Linux)
840
+
841
+ ![Hello Code Text Zoom Out](/images/glimmer-hello-code-text-zoom-out.png)
842
+
843
+ Hello, Code Text! Restore Original Font Height (via keyboard shortcut CMD+0 on Mac, CTRL+0 on Win/Linux)
844
+
845
+ ![Hello Code Text Restore Original Font Height](/images/glimmer-hello-code-text-ruby.png)
830
846
 
831
847
  #### Hello, Canvas!
832
848
 
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,17 +35,21 @@ 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
39
43
  @model_binding = model_binding
40
44
  @read_only_sort = @model_binding.binding_options[:read_only_sort]
41
- @column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
42
45
  @table.editable = false if @model_binding.binding_options[:read_only]
43
- if @table.respond_to?(:column_properties=)
44
- @table.column_properties = @column_properties
46
+ column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
47
+ if @table.is_a?(Glimmer::SWT::TableProxy)
48
+ @table.column_properties = column_properties
49
+ @column_properties = @table.column_properties # normalized column properties
45
50
  else # assume custom widget
46
51
  @table.body_root.column_properties = @column_properties
52
+ @column_properties = @table.body_root.column_properties # normalized column properties
47
53
  end
48
54
  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
49
55
  @table.swt_widget.data = @model_binding
@@ -56,40 +62,161 @@ module Glimmer
56
62
  end
57
63
  end
58
64
 
59
- def call(new_model_collection=nil, internal_sort: false)
65
+ def call(*args)
66
+ options = args.last.is_a?(Hash) ? args.pop : {}
67
+ internal_sort = options[:internal_sort] || false
68
+ new_model_collection = args.first
60
69
  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
70
  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
71
+ return if same_table_data?(new_model_collection)
72
+ if same_model_collection?(new_model_collection)
73
+ new_model_collection_attribute_values = model_collection_attribute_values(new_model_collection)
74
+ @table.swt_widget.items.each_with_index do |table_item, row_index|
75
+ next if new_model_collection_attribute_values[row_index] == @last_model_collection_attribute_values[row_index]
76
+ model = table_item.get_data
77
+ (0..(@column_properties.size-1)).each do |column_index|
78
+ new_model_attribute_values_for_index = model_attribute_values_for_index(new_model_collection_attribute_values[row_index], column_index)
79
+ last_model_attribute_values_for_index = model_attribute_values_for_index(@last_model_collection_attribute_values[row_index], column_index)
80
+ next if new_model_attribute_values_for_index == last_model_attribute_values_for_index
81
+ model_attribute = @column_properties[column_index]
82
+ update_table_item_properties_from_model(table_item, row_index, column_index, model, model_attribute)
83
+ end
84
+ end
85
+ @last_model_collection_attribute_values = new_model_collection_attribute_values
86
+ else
87
+ if new_model_collection and new_model_collection.is_a?(Array)
88
+ remove_dependent(@table_observer_registration => @table_items_observer_registration) if @table_items_observer_registration
89
+ @table_items_observer_registration&.unobserve
90
+ # TODO observe and update table items piecemeal per model instead of passing @column_properties
91
+ # TODO ensure unobserving models when they are no longer part of the table
92
+ @table_items_observer_registration = observe(new_model_collection, @column_properties)
93
+ add_dependent(@table_observer_registration => @table_items_observer_registration)
94
+ @table_items_property_observer_registration ||= {}
95
+ if !same_model_collection_with_different_sort?(new_model_collection)
96
+ TABLE_ITEM_PROPERTIES.each do |table_item_property|
97
+ remove_dependent(@table_observer_registration => @table_items_property_observer_registration[table_item_property]) if @table_items_property_observer_registration[table_item_property]
98
+ @table_items_property_observer_registration[table_item_property]&.unobserve
99
+ property_properties = @column_properties.map {|property| "#{property}_#{table_item_property}" }
100
+ @table_items_property_observer_registration[table_item_property] = observe(new_model_collection, property_properties)
101
+ add_dependent(@table_observer_registration => @table_items_property_observer_registration[table_item_property])
102
+ end
103
+ end
104
+ @model_collection = new_model_collection
105
+ end
106
+ populate_table(@model_collection, @table, @column_properties, internal_sort: internal_sort)
70
107
  end
71
- populate_table(@model_collection, @table, @column_properties, internal_sort: internal_sort)
72
108
  end
73
109
  end
74
110
 
75
111
  def populate_table(model_collection, parent, column_properties, internal_sort: false)
76
112
  selected_table_item_models = parent.swt_widget.getSelection.map(&:get_data)
77
113
  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)
114
+ dispose_start_index = @last_model_collection_attribute_values &&
115
+ (model_collection.count < @last_model_collection_attribute_values.count) &&
116
+ (@last_model_collection_attribute_values.count - (@last_model_collection_attribute_values.count - model_collection.count))
117
+ if dispose_start_index
118
+ table_items_to_dispose = parent.swt_widget.items[dispose_start_index..-1]
119
+ parent.swt_widget.remove(dispose_start_index, (@last_model_collection_attribute_values.count-1))
120
+ table_items_to_dispose.each(&:dispose)
121
+ end
122
+ model_collection.each_with_index do |model, row_index|
123
+ table_item_exists = @last_model_collection_attribute_values &&
124
+ @last_model_collection_attribute_values.count > 0 &&
125
+ row_index < @last_model_collection_attribute_values.count
126
+ table_item = table_item_exists ? parent.swt_widget.items[row_index] : TableItem.new(parent.swt_widget, SWT::SWTProxy[:none])
127
+ (0..(column_properties.size-1)).each do |column_index|
128
+ model_attribute = column_properties[column_index]
129
+ update_table_item_properties_from_model(table_item, row_index, column_index, model, model_attribute)
84
130
  end
85
131
  table_item.set_data(model)
86
132
  end
133
+ @last_model_collection_attribute_values = model_collection_attribute_values(model_collection)
87
134
  selected_table_items = parent.search {|item| selected_table_item_models.include?(item.get_data) }
88
135
  parent.swt_widget.setSelection(selected_table_items)
89
136
  sorted_model_collection = parent.sort!(internal_sort: internal_sort)
90
137
  call(sorted_model_collection, internal_sort: true) if @read_only_sort && !internal_sort && !sorted_model_collection.nil?
91
138
  parent.swt_widget.redraw if parent&.swt_widget&.respond_to?(:redraw)
92
139
  end
140
+
141
+ def update_table_item_properties_from_model(table_item, row_index, column_index, model, model_attribute)
142
+ Glimmer::SWT::DisplayProxy.instance.sync_exec do
143
+ old_table_item_values = @last_model_collection_attribute_values &&
144
+ @last_model_collection_attribute_values[row_index] &&
145
+ model_attribute_values_for_index(@last_model_collection_attribute_values[row_index], column_index)
146
+ text_value = model.send(model_attribute).to_s
147
+ old_table_item_value = old_table_item_values && old_table_item_values[0]
148
+ table_item.set_text(column_index, text_value) if old_table_item_value.nil? || text_value != old_table_item_value
149
+ TABLE_ITEM_PROPERTIES.each do |table_item_property|
150
+ if model.respond_to?("#{model_attribute}_#{table_item_property}")
151
+ table_item_value = model.send("#{model_attribute}_#{table_item_property}")
152
+ old_table_item_value = old_table_item_values && old_table_item_values[1 + TABLE_ITEM_PROPERTIES.index(table_item_property)]
153
+ if old_table_item_value.nil? || (table_item_value != old_table_item_value)
154
+ 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)
155
+ table_item_value = Glimmer::SWT::FontProxy.create(table_item_value).swt_font if table_item_value && table_item_property.to_s == 'font'
156
+ table_item_value = Glimmer::SWT::ImageProxy.create(*table_item_value).swt_image if table_item_value && table_item_property.to_s == 'image'
157
+ table_item.send("set_#{table_item_property}", column_index, table_item_value)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ def same_table_data?(new_model_collection)
165
+ (["text"] + TABLE_ITEM_PROPERTIES).all? do |table_item_property|
166
+ table_cells = @table.swt_widget.items.map do |item|
167
+ model = item.get_data
168
+ @table.column_properties.each_with_index.map do |column_property, i|
169
+ model_attribute = "#{column_property}"
170
+ model_attribute = "#{model_attribute}_#{table_item_property}" if TABLE_ITEM_PROPERTIES.include?(table_item_property)
171
+ item.send("get_#{table_item_property}", i) if model.respond_to?(model_attribute)
172
+ end
173
+ end
174
+ model_cells = new_model_collection.to_a.map do |m|
175
+ @table.cells_for(m, table_item_property: table_item_property)
176
+ end
177
+ model_cells = model_cells.map do |row|
178
+ row.map do |model_cell|
179
+ if model_cell
180
+ if %w[background foreground].include?(table_item_property.to_s)
181
+ Glimmer::SWT::ColorProxy.create(*model_cell).swt_color
182
+ elsif table_item_property.to_s == 'font'
183
+ Glimmer::SWT::FontProxy.create(model_cell).swt_font
184
+ elsif table_item_property.to_s == 'image'
185
+ Glimmer::SWT::ImageProxy.create(*model_cell).swt_image
186
+ else
187
+ model_cell
188
+ end
189
+ end
190
+ end
191
+ end
192
+ table_cells == model_cells
193
+ end
194
+ end
195
+
196
+ def same_model_collection?(new_model_collection)
197
+ new_model_collection == table_item_model_collection
198
+ end
199
+
200
+ def same_model_collection_with_different_sort?(new_model_collection)
201
+ Set.new(new_model_collection) == Set.new(table_item_model_collection)
202
+ end
203
+
204
+ def table_item_model_collection
205
+ @table.swt_widget.items.map(&:get_data)
206
+ end
207
+
208
+ def model_collection_attribute_values(model_collection)
209
+ model_collection.map do |model|
210
+ (["text"] + TABLE_ITEM_PROPERTIES).map do |table_item_property|
211
+ @table.cells_for(model, table_item_property: table_item_property)
212
+ end
213
+ end
214
+ end
215
+
216
+ def model_attribute_values_for_index(model_attribute_values, index)
217
+ model_attribute_values.map {|attribute_values| attribute_values[index]}
218
+ end
219
+
93
220
  end
94
221
  end
95
222
  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
@@ -42,6 +42,7 @@ module Glimmer
42
42
 
43
43
  REGEX_COLOR_HEX6 = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/
44
44
  FONT_NAMES_PREFERRED = ['Consolas', 'Courier', 'Monospace', 'Liberation Mono']
45
+ SHORTCUT_KEY_COMMAND = OS.mac? ? :command : :ctrl
45
46
 
46
47
  # TODO support auto language detection
47
48
 
@@ -145,7 +146,7 @@ module Glimmer
145
146
 
146
147
  body {
147
148
  if lines
148
- composite {
149
+ @composite = composite {
149
150
  grid_layout(2, false)
150
151
 
151
152
  @line_numbers_styled_text_proxy = styled_text(swt(swt(swt_style), :h_scroll!, :v_scroll!)) {
@@ -204,12 +205,18 @@ module Glimmer
204
205
  on_key_pressed { |event|
205
206
  character = event.keyCode.chr rescue nil
206
207
  case [event.stateMask, character]
207
- when [(OS.mac? ? swt(:command) : swt(:ctrl)), 'a']
208
+ when [swt(SHORTCUT_KEY_COMMAND), 'a']
208
209
  @styled_text_proxy.selectAll
209
210
  when [(swt(:ctrl) if OS.mac?), 'a']
210
211
  jump_to_beginning_of_line
211
212
  when [(swt(:ctrl) if OS.mac?), 'e']
212
213
  jump_to_end_of_line
214
+ when [swt(SHORTCUT_KEY_COMMAND), '=']
215
+ bump_font_height_up
216
+ when [swt(SHORTCUT_KEY_COMMAND), '-']
217
+ bump_font_height_down
218
+ when [swt(SHORTCUT_KEY_COMMAND), '0']
219
+ restore_font_height
213
220
  end
214
221
  }
215
222
  on_verify_text { |verify_event|
@@ -333,6 +340,36 @@ module Glimmer
333
340
  @font_name ||= all_font_names.find {|font_name| font_name.downcase.include?('mono')}
334
341
  @font_name
335
342
  end
343
+
344
+ def bump_font_height_up
345
+ @original_font_height ||= font_datum.height
346
+ new_font_height = font_datum.height + 1
347
+ update_font_height(new_font_height)
348
+ end
349
+
350
+ def bump_font_height_down
351
+ @original_font_height ||= font_datum.height
352
+ new_font_height = (font_datum.height - 1) == 0 ? font_datum.height : (font_datum.height - 1)
353
+ update_font_height(new_font_height)
354
+ end
355
+
356
+ def restore_font_height
357
+ return if @original_font_height.nil?
358
+ update_font_height(@original_font_height)
359
+ @original_font_height = nil
360
+ end
361
+
362
+ def update_font_height(new_font_height)
363
+ return if new_font_height.nil?
364
+ @styled_text_proxy.font = {name: font_datum.name, height: new_font_height, style: font_datum.style}
365
+ @line_numbers_styled_text_proxy&.font = {name: font_datum.name, height: new_font_height, style: font_datum.style}
366
+ @body_root.shell_proxy.layout(true, true)
367
+ @body_root.shell_proxy.pack_same_size
368
+ end
369
+
370
+ def font_datum
371
+ @styled_text_proxy.font.font_data.first
372
+ end
336
373
  end
337
374
  end
338
375
  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.
@@ -246,7 +246,8 @@ module Glimmer
246
246
  end
247
247
 
248
248
  attr_reader :table_editor, :table_editor_widget_proxy, :sort_property, :sort_direction, :sort_block, :sort_type, :sort_by_block, :additional_sort_properties, :editor, :editable
249
- attr_accessor :column_properties
249
+ attr_writer :column_properties
250
+ alias column_attributes= column_properties=
250
251
  alias editable? editable
251
252
 
252
253
  def initialize(underscored_widget_name, parent, args)
@@ -258,6 +259,19 @@ module Glimmer
258
259
  @table_editor.minimumHeight = 20
259
260
  self.editable = editable_style
260
261
  end
262
+
263
+ def column_properties
264
+ if @column_properties.nil?
265
+ swt_widget.columns.to_a.map(&:text).map(&:underscore)
266
+ elsif @column_properties.is_a?(Hash)
267
+ @column_properties = swt_widget.columns.to_a.map(&:text).map do |column_name|
268
+ @column_properties[column_name] || column_name.underscore
269
+ end
270
+ else
271
+ @column_properties
272
+ end
273
+ end
274
+ alias column_attributes column_properties
261
275
 
262
276
  def items
263
277
  auto_exec do
@@ -419,8 +433,14 @@ module Glimmer
419
433
  @editor = args
420
434
  end
421
435
 
422
- def cells_for(model)
423
- column_properties.map {|property| model.send(property)}
436
+ def cells_for(model, table_item_property: :text)
437
+ if table_item_property.to_s == 'text'
438
+ column_properties.map {|column_property| model.send(column_property)}
439
+ else
440
+ column_properties.map do |column_property|
441
+ model.send("#{column_property}_#{table_item_property}") if model.respond_to?("#{column_property}_#{table_item_property}")
442
+ end
443
+ end
424
444
  end
425
445
 
426
446
  def cells
@@ -144,7 +144,7 @@ class ContactManager
144
144
  width 200
145
145
  }
146
146
 
147
- items <=> [@contact_manager_presenter, :results, column_properties: [:first_name, :last_name, :email]]
147
+ items <=> [@contact_manager_presenter, :results]
148
148
 
149
149
  on_mouse_up do |event|
150
150
  table_proxy.edit_table_item(event.table_item, event.column_index)
@@ -28,3 +28,5 @@ 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
32
+ Battleship: b00OWeLZOt8
@@ -41,9 +41,11 @@ class Sample
41
41
 
42
42
  def ensure_user_glimmer_directory
43
43
  unless @ensured_glimmer_directory
44
- FileUtils.rm_rf(user_glimmer_directory)
45
- FileUtils.cp_r(glimmer_directory, user_glimmer_directory)
46
- @ensured_glimmer_directory = true
44
+ Thread.new do
45
+ FileUtils.rm_rf(user_glimmer_directory)
46
+ FileUtils.cp_r(glimmer_directory, user_glimmer_directory)
47
+ @ensured_glimmer_directory = true
48
+ end
47
49
  end
48
50
  end
49
51
 
@@ -123,11 +125,11 @@ class Sample
123
125
  end
124
126
 
125
127
  def file_relative_path
126
- file.sub(self.class.glimmer_directory, '')
128
+ file.sub(Sample.glimmer_directory, '')
127
129
  end
128
130
 
129
131
  def user_file
130
- File.join(self.class.user_glimmer_directory, file_relative_path)
132
+ File.join(Sample.user_glimmer_directory, file_relative_path)
131
133
  end
132
134
 
133
135
  def user_file_parent_directory
@@ -209,10 +211,10 @@ class SampleDirectory
209
211
  @samples.each do |sample|
210
212
  observe(sample, :selected) do |new_selected_value|
211
213
  if new_selected_value
212
- self.class.all_samples.reject {|a_sample| a_sample.name == sample.name}.each do |other_sample|
214
+ SampleDirectory.all_samples.reject {|a_sample| a_sample.name == sample.name}.each do |other_sample|
213
215
  other_sample.selected = false
214
216
  end
215
- self.class.selected_sample = sample
217
+ SampleDirectory.selected_sample = sample
216
218
  end
217
219
  end
218
220
  end
@@ -227,8 +229,8 @@ class SampleDirectory
227
229
  def selected_sample_name=(selected_name)
228
230
  @selected_sample_name = selected_name
229
231
  unless selected_name.nil?
230
- (self.class.sample_directories - [self]).each { |sample_dir| sample_dir.selected_sample_name = nil }
231
- self.class.selected_sample = samples.detect { |sample| sample.name == @selected_sample_name }
232
+ (SampleDirectory.sample_directories - [self]).each { |sample_dir| sample_dir.selected_sample_name = nil }
233
+ SampleDirectory.selected_sample = samples.detect { |sample| sample.name == @selected_sample_name }
232
234
  end
233
235
  end
234
236
 
@@ -66,7 +66,7 @@ class Tetris
66
66
  text 'Level'
67
67
  }
68
68
 
69
- items <=> [game, :high_scores, read_only_sort: true, column_properties: [:name, :score, :lines, :level]]
69
+ items <=> [game, :high_scores, read_only_sort: true]
70
70
  }
71
71
  composite {
72
72
  row_layout :horizontal
@@ -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
  }
@@ -157,19 +157,19 @@ class HelloCustomShell
157
157
  layout_data :fill, :fill, true, true
158
158
 
159
159
  table_column {
160
- text 'Date:'
160
+ text 'Date'
161
161
  width 180
162
162
  }
163
163
  table_column {
164
- text 'Subject:'
164
+ text 'Subject'
165
165
  width 180
166
166
  }
167
167
  table_column {
168
- text 'From:'
168
+ text 'From'
169
169
  width 360
170
170
  }
171
171
 
172
- items <=> [@email_system, :emails, column_properties: [:date, :subject, :from]]
172
+ items <=> [@email_system, :emails]
173
173
  selection <=> [@email_system, :selected_email]
174
174
 
175
175
  on_mouse_up do |event|
@@ -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,28 @@ 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
+ # automatically inferring model attributes from column names by convention
306
+ # (e.g. 'Home Team' column assumes a `home_team` attribute on models)
307
+ #
308
+ # By convention, every inferred model attribute can be accompanied by extra
309
+ # model attributes to set extra table properties with the following suffixes:
310
+ # `_background`, `_foreground`, `_font`, and `_image`
311
+ #
312
+ # For example, for :game_date, model could also implement these related properties:
313
+ # `game_date_background`, `game_date_foreground`, `game_date_font`, `game_date_image`
314
+ items <=> [BaseballGame, :schedule]
251
315
 
252
316
  # Data-bind table selection
253
317
  selection <=> [BaseballGame, :selected_game]
@@ -258,22 +322,16 @@ class HelloTable
258
322
  # Sort by these additional properties after handling sort by the column the user clicked
259
323
  additional_sort_properties :date, :time, :home_team, :away_team, :ballpark, :promotion
260
324
 
261
- menu {
262
- menu_item {
263
- text 'Book'
264
-
265
- on_widget_selected do
266
- book_selected_game
267
- end
268
- }
269
- }
325
+ on_key_pressed do |key_event|
326
+ book_selected_game if key_event.keyCode == swt(:cr)
327
+ end
270
328
  }
271
329
 
272
330
  button {
273
331
  text 'Book Selected Game'
274
332
  layout_data :center, :center, true, false
275
333
  font height: 14
276
- enabled <= [BaseballGame, :selected_game]
334
+ enabled <= [BaseballGame, 'selected_game.booked', on_read: ->(value) { value == false }]
277
335
 
278
336
  on_widget_selected do
279
337
  book_selected_game
@@ -283,6 +341,8 @@ class HelloTable
283
341
  }
284
342
 
285
343
  def book_selected_game
344
+ return if BaseballGame.selected_game.booked?
345
+
286
346
  message_box {
287
347
  text 'Baseball Game Booked!'
288
348
  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.2
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-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement