glimmer-dsl-swt 4.24.3.0 → 4.24.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90fac650eedadc1e677e27563bda759e5aa1ea7b2d5b6627129f906516c21a82
4
- data.tar.gz: 4098c6d271799034a18747154236426cde6c7b83eca4030d5d1292f8bc0f52e2
3
+ metadata.gz: 81eb61402ae45b2e3782b9c10dc6b0374e39fb7f74351d2ed940719fbd6e4ec3
4
+ data.tar.gz: dfa93b670ddc363dd2dc602920d5e24510202b179f7e7740ee8abc50fc91eee4
5
5
  SHA512:
6
- metadata.gz: 97d0b7a8a715410c6772b4cbb8cd45052c5d0db5e3c7b6f78a62fd9d8f23536dc467727b4441e0585f339674e63d4f9c3e622cdaea04a968e80ffde5ea6ea5f6
7
- data.tar.gz: 159d537c854c56d6502a8ed248f5b54fe76590a411d5013d5f40844dd816c1212e49692e42b882c7262267de859580491ce4c9f015972f4b0baaea5169a0dddd
6
+ metadata.gz: 46bee26330ce88284c85f263b0db58dda6dfb76cd2d2f37938c881f6567d74cd0a514565625a6c21da53b91e119fd31185dda8b22626e357fb79612e9013f6fe
7
+ data.tar.gz: '049762158e8e4015ec1a157edd148212078a106b753b9ad4f6111ab49746fe2934471382b4c5c20d9ee00a9abca8d8c22866c1c3ecd7aa733ccc5aeb28eb6c7b'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.24.4.0
4
+
5
+ - Save `WidgetBinding` instances on `WidgetProxy` objects via `widget_bindings` attribute
6
+ - Support specifying `@children_owner` in any custom widget for which adding children will not add them under the `body_root` (e.g. a composite wrapping a table will designate the table as the `@children_owner` for adding `table_column`s)
7
+ - Add explicit `shell_proxy` method to `Glimmer::UI::CustomWidget` that delegates to `body_root` to avoid annoying false negative error every time that method is called
8
+ - Optimize `table` data-binding performance for single-model update scenarios
9
+ - Fix issue with data-binding a table as the body root of a custom widget when customizing column_attributes
10
+
11
+ ## 4.24.3.2
12
+
13
+ - Have `table` data-binding infer model attribute names from column names by convention (no need to specify `column_properties`)
14
+ - Support `table` data-binding `column_properties` mapping of column names to model attribute names via a `Hash`
15
+ - 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
16
+ - Handle boundary condition of font height reaching 0 on repeated zoom out of `code_text`
17
+ - Battleship Video Tutorial in Glimmer Meta-Sample
18
+
19
+ ## 4.24.3.1
20
+
21
+ - `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).
22
+
3
23
  ## 4.24.3.0
4
24
 
5
25
  - 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)
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.3.0
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.4.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)
@@ -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.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.
24
+ [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.24.4.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.3.0
341
+ jgem install glimmer-dsl-swt -v 4.24.4.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.3.0'
369
+ gem 'glimmer-dsl-swt', '~> 4.24.4.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.3.0
392
+ Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.24.4.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.3.0
1
+ 4.24.4.0
@@ -54,9 +54,11 @@ This guide should help you get started with Glimmer DSL for SWT. For more advanc
54
54
  - [Combo](#combo)
55
55
  - [List](#list)
56
56
  - [Table](#table)
57
+ - [Table Item Properties](#table-item-properties)
57
58
  - [Table Selection](#table-selection)
58
59
  - [Table Editing](#table-editing)
59
60
  - [Table Sorting](#table-sorting)
61
+ - [Refined Table with Pagination](#refined-table-with-pagination)
60
62
  - [Tree](#tree)
61
63
  - [DateTime](#datetime)
62
64
  - [Observer](#observer)
@@ -3996,13 +3998,13 @@ You may learn more about Glimmer's data-binding syntax by reading the code under
3996
3998
 
3997
3999
  The SWT Tree widget renders a multi-column data table, such as a contact listing or a sales report.
3998
4000
 
3999
- To data-bind a Table, you need the main model, the collection property, and the text display attribute for each table column.
4001
+ 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
4002
 
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.
4003
+ 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
4004
 
4003
- It assumes you have defined the table columns via `table_column` widget.
4005
+ It assumes you have already defined table columns via the `table_column` `table`-nested widget.
4004
4006
 
4005
- Example:
4007
+ Example (automatically inferring table items' [rows'] model attributes by convention from column names):
4006
4008
 
4007
4009
  ```ruby
4008
4010
  shell {
@@ -4019,8 +4021,10 @@ shell {
4019
4021
  text "Adult"
4020
4022
  width 120
4021
4023
  }
4022
- items <=> [group, :people, column_properties: [:name, :age, :adult]]
4024
+
4025
+ items <=> [group, :people]
4023
4026
  selection <=> [group, :selected_person]
4027
+
4024
4028
  on_mouse_up do |event|
4025
4029
  @table.edit_table_item(event.table_item, event.column_index)
4026
4030
  end
@@ -4028,15 +4032,71 @@ shell {
4028
4032
  }
4029
4033
  ```
4030
4034
 
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)
4035
+ The code above includes two data-bindings and a listener:
4036
+ - 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.
4037
+ - 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
4038
  - 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
4039
 
4036
- Additionally, Table `items` data-binding automatically stores each node model unto the SWT TableItem object via `setData` method. This enables things like searchability.
4040
+ Example (specifying `column_attributes` explicitly because some diverge from column names):
4041
+
4042
+ ```ruby
4043
+ shell {
4044
+ @table = table {
4045
+ table_column {
4046
+ text "Full Name"
4047
+ width 120
4048
+ }
4049
+ table_column {
4050
+ text "Age in Years"
4051
+ width 120
4052
+ }
4053
+ table_column {
4054
+ text "Adult"
4055
+ width 120
4056
+ }
4057
+
4058
+ items <=> [group, :people, column_attributes: {'Full Name' => :name, 'Age in Years' => :age}]
4059
+ selection <=> [group, :selected_person]
4060
+
4061
+ on_mouse_up do |event|
4062
+ @table.edit_table_item(event.table_item, event.column_index)
4063
+ end
4064
+ }
4065
+ }
4066
+ ```
4067
+
4068
+ Example (specifying `column_attributes` explicitly because all diverge from column names):
4069
+
4070
+ ```ruby
4071
+ shell {
4072
+ @table = table {
4073
+ table_column {
4074
+ text "Full Name"
4075
+ width 120
4076
+ }
4077
+ table_column {
4078
+ text "Age in Years"
4079
+ width 120
4080
+ }
4081
+ table_column {
4082
+ text "Is Adult"
4083
+ width 120
4084
+ }
4085
+
4086
+ items <=> [group, :people, column_attributes: [:name, :age, :adult]]
4087
+ selection <=> [group, :selected_person]
4088
+
4089
+ on_mouse_up do |event|
4090
+ @table.edit_table_item(event.table_item, event.column_index)
4091
+ end
4092
+ }
4093
+ }
4094
+ ```
4095
+
4096
+ 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.
4037
4097
 
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.
4098
+ The table widget in Glimmer is represented by a subclass of `Glimmer::SWT::WidgetProxy` called `Glimmer::SWT::TableProxy`.
4099
+ `Glimmer::SWT::TableProxy` includes a `search` method that takes a block to look for a table item.
4040
4100
 
4041
4101
  Example:
4042
4102
 
@@ -4044,18 +4104,21 @@ Example:
4044
4104
  found_array = @table.search { |table_item| table_item.getData == company.owner }
4045
4105
  ```
4046
4106
 
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.
4107
+ 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
4108
 
4049
4109
  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
4110
  This automatically leverages the SWT TableEditor custom class behind the scenes, displaying a text widget to the user to change the selected or
4051
4111
  passed table item text into something else.
4052
4112
  It automatically persists the change to `items` data-bound model on ENTER/FOCUS-OUT or cancels on ESC/NO-CHANGE.
4053
4113
 
4114
+ Note that `table` is designed to expect about 100 rows only, not more than that, or otherwise it will not offer a user-friendly experience due to requiring users to scroll through a lot of data.
4115
+ If you need to display a table with more than 100 rows, then you need to employ pagination. That is already supported in the [Refined Table (`refined_table`)](#refined-table-with-pagination) custom widget documented below.
4116
+
4054
4117
  ##### Table Item Properties
4055
4118
 
4056
4119
  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
4120
 
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:
4121
+ 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:
4059
4122
  - `background` to `:name_background, :age_background, :adult_background` model attributes
4060
4123
  - `foreground` to `:name_foreground, :age_foreground, :adult_foreground` model attributes
4061
4124
  - `font` to `:name_font, :age_font, :adult_font` model attributes
@@ -4104,7 +4167,7 @@ shell {
4104
4167
  text "Adult"
4105
4168
  width 120
4106
4169
  }
4107
- items bind(group, :people), column_properties(:name, :age, :adult)
4170
+ items <=> [group, :people]
4108
4171
  selection bind(group, :selected_person)
4109
4172
  }
4110
4173
  }
@@ -4131,7 +4194,7 @@ shell {
4131
4194
  width 120
4132
4195
  editor :checkbox
4133
4196
  }
4134
- items bind(group, :people), column_properties(:name, :age, :adult)
4197
+ items <=> [group, :people]
4135
4198
  selection bind(group, :selected_person)
4136
4199
  }
4137
4200
  }
@@ -4170,7 +4233,7 @@ shell {
4170
4233
  # assume there is a `Person#industry_options` property method on the model to provide items to the `combo`
4171
4234
  editor :combo, :read_only # passes :ready_only SWT style to `combo` widget
4172
4235
  }
4173
- items bind(group, :people), column_properties(:formatted_date, :industry)
4236
+ items <=> [group, :people, column_attributes: {'Date of Birth' => :formatted_date}]
4174
4237
  selection bind(group, :selected_person)
4175
4238
  }
4176
4239
  }
@@ -4229,7 +4292,7 @@ Example:
4229
4292
  sort { |d1, d2| d1.to_date <=> d2.to_date }
4230
4293
  }
4231
4294
  additional_sort_properties :project_name, :duration_in_hours, :name
4232
- items bind(Task, :list), column_properties(:name, :project_name, :duration, :priority, :start_date)
4295
+ items <=> [Task, :list, column_attributes: [:name, :project_name, :duration, :priority, :start_date]]
4233
4296
  # ...
4234
4297
  }
4235
4298
  # ...
@@ -4242,7 +4305,52 @@ Here is an explanation of the example above:
4242
4305
  - Task Start Date table column has a custom sort comparator block
4243
4306
  - Additional (secondary) sort properties are applied when sorting by Task, Project, or Duration in the order specified
4244
4307
 
4245
- `bind(model, :property, read_only_sort: true)` could be used with items to make sorting not propagate sorting changes to model.
4308
+ `<= [model, :property, read_only_sort: true]` could be used with items to make sorting not propagate sorting changes to model.
4309
+
4310
+ ##### Refined Table with Pagination
4311
+
4312
+ **(ALPHA FEATURE)**
4313
+
4314
+ `refined_table` is a custom widget that can handle very large amounts of data by applying pagination.
4315
+
4316
+ Just use like a standard `table`, but data-bind models to a `model_array` property instead of `items`. `refined_table` will take care of the rest.
4317
+
4318
+ Options:
4319
+ - `per_page` (default: `10`): specifies how many rows to display per page
4320
+ - `page` (default: `1` if table is filled and `0` otherwise): specifies initial page
4321
+
4322
+ Note that currently `refined_table` only supports displaying a **read-only** table (meaning it can read updates from the model, but it cannot write back to the model through table editing cells).
4323
+
4324
+ Example taken from [Hello, Refined Table!](/docs/reference/GLIMMER_SAMPLES.md#hello-refined-table):
4325
+
4326
+ ![hello refined table](/images/glimmer-hello-refined-table.png)
4327
+
4328
+ ```ruby
4329
+ #... more code precedes
4330
+
4331
+ refined_table(per_page: 20) {
4332
+ table_column {
4333
+ width 100
4334
+ text 'Date'
4335
+ }
4336
+ table_column {
4337
+ width 200
4338
+ text 'Ballpark'
4339
+ }
4340
+ table_column {
4341
+ width 150
4342
+ text 'Home Team'
4343
+ }
4344
+ table_column {
4345
+ width 150
4346
+ text 'Away Team'
4347
+ }
4348
+
4349
+ model_array <= [@baseball_season, :games, column_attributes: {'Home Team' => :home_team_name, 'Away Team' => :away_team_name}]
4350
+ }
4351
+
4352
+ #...more code follows
4353
+ ```
4246
4354
 
4247
4355
  #### Tree
4248
4356
 
@@ -4825,7 +4933,7 @@ You may see another example at the [Hello, Radio Group!](/docs/reference/GLIMMER
4825
4933
 
4826
4934
  ##### Code Text Custom Widget
4827
4935
 
4828
- `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.
4936
+ `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).
4829
4937
 
4830
4938
  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.
4831
4939
 
@@ -5151,6 +5259,9 @@ This adds some default keyboard shortcuts:
5151
5259
  - CMD+A (CTRL+A on Windows/Linux) to select all
5152
5260
  - CTRL+A on Mac to jump to beginning of line
5153
5261
  - CTRL+E on Mac to jump to end of line
5262
+ - CMD+= (CTRL+= on Windows/Linux) to zoom in (bump font height up by 1)
5263
+ - CMD+- (CTRL+- on Windows/Linux) to zoom out (bump font height down by 1)
5264
+ - CMD+0 (CTRL+0 on Windows/Linux) to restore to original font height
5154
5265
  - Attempts to add proper indentation upon adding a new line when hitting ENTER (currently supporting Ruby only)
5155
5266
 
5156
5267
  If you prefer it to be vanilla with no default key event listeners, then pass the `default_behavior: false` option.
@@ -41,6 +41,7 @@
41
41
  - [Hello, Slider!](#hello-slider)
42
42
  - [Hello, Spinner!](#hello-spinner)
43
43
  - [Hello, Table!](#hello-table)
44
+ - [Hello, Refined Table!](#hello-refined-table)
44
45
  - [Hello, Link!](#hello-link)
45
46
  - [Hello, Dialog!](#hello-dialog)
46
47
  - [Hello, Code Text!](#hello-code-text)
@@ -730,7 +731,7 @@ Hello, Spinner!
730
731
 
731
732
  #### Hello, Table!
732
733
 
733
- This sample demonstrates the use of [table](#table) widget in Glimmer, including data-binding, multi-type editing, sorting, and filtering.
734
+ 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
735
 
735
736
  Code:
736
737
 
@@ -780,6 +781,18 @@ Hello, Table! Game Booked Rows
780
781
 
781
782
  ![Hello Table game booked rows](/images/glimmer-hello-table-game-booked-rows.png)
782
783
 
784
+ #### Hello, Refined Table!
785
+
786
+ This sample demonstrates the use of the [`refined_table` widget](/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#refined-table-with-pagination), which provides a paginated `table` that can handle very large amounts of data.
787
+
788
+ Code:
789
+
790
+ [samples/hello/hello_refined_table.rb](/samples/hello/hello_refined_table.rb)
791
+
792
+ Hello, Refined Table!
793
+
794
+ ![Hello Refined Table](/images/glimmer-hello-refined-table.png)
795
+
783
796
  #### Hello, Link!
784
797
 
785
798
  This sample demonstrates the use of the `link` widget in Glimmer, including identifying which link was clicked and performing an action (displaying help) based on its location.
@@ -820,17 +833,29 @@ Code:
820
833
 
821
834
  [samples/hello/hello_code_text.rb](/samples/hello/hello_code_text.rb)
822
835
 
823
- Hello, Code Text! Ruby Language / Glimmer Theme / Show Line Numbers (default width of 4)
836
+ Hello, Code Text! HTML Language / GitHub Theme / No Line Numbers
824
837
 
825
- ![Hello Code Text Ruby](/images/glimmer-hello-code-text-ruby.png)
838
+ ![Hello Code Text HTML](/images/glimmer-hello-code-text-html.png)
826
839
 
827
840
  Hello, Code Text! JavaScript Language / Pastie Theme / Show Line Numbers (custom width of 2)
828
841
 
829
842
  ![Hello Code Text JavaScript](/images/glimmer-hello-code-text-javascript.png)
830
843
 
831
- Hello, Code Text! HTML Language / GitHub Theme / No Line Numbers
844
+ Hello, Code Text! Ruby Language / Glimmer Theme / Show Line Numbers (default width of 4)
832
845
 
833
- ![Hello Code Text HTML](/images/glimmer-hello-code-text-html.png)
846
+ ![Hello Code Text Ruby](/images/glimmer-hello-code-text-ruby.png)
847
+
848
+ Hello, Code Text! Zoom In (via keyboard shortcut CMD+= on Mac, CTRL+= on Win/Linux)
849
+
850
+ ![Hello Code Text Zoom In](/images/glimmer-hello-code-text-zoom-in.png)
851
+
852
+ Hello, Code Text! Zoom Out (via keyboard shortcut CMD+- on Mac, CTRL+- on Win/Linux)
853
+
854
+ ![Hello Code Text Zoom Out](/images/glimmer-hello-code-text-zoom-out.png)
855
+
856
+ Hello, Code Text! Restore Original Font Height (via keyboard shortcut CMD+0 on Mac, CTRL+0 on Win/Linux)
857
+
858
+ ![Hello Code Text Restore Original Font Height](/images/glimmer-hello-code-text-ruby.png)
834
859
 
835
860
  #### Hello, Canvas!
836
861
 
Binary file
@@ -39,16 +39,12 @@ module Glimmer
39
39
  TABLE_ITEM_PROPERTIES = %w[background foreground font image]
40
40
 
41
41
  def initialize(parent, model_binding, column_properties = nil)
42
- @table = parent
42
+ @table = parent.is_a?(Glimmer::SWT::TableProxy) ? parent : parent.body_root # assume custom widget in latter case
43
43
  @model_binding = model_binding
44
44
  @read_only_sort = @model_binding.binding_options[:read_only_sort]
45
- @column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
46
45
  @table.editable = false if @model_binding.binding_options[:read_only]
47
- if @table.respond_to?(:column_properties=)
48
- @table.column_properties = @column_properties
49
- else # assume custom widget
50
- @table.body_root.column_properties = @column_properties
51
- end
46
+ @table.column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
47
+ @column_properties = @table.column_properties # normalized column properties
52
48
  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
53
49
  @table.swt_widget.data = @model_binding
54
50
  @table.swt_widget.set_data('table_items_binding', self)
@@ -67,6 +63,7 @@ module Glimmer
67
63
  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
68
64
  new_model_collection = model_binding_evaluated_property = @model_binding.evaluate_property unless internal_sort # this ensures applying converters (e.g. :on_read)
69
65
  return if same_table_data?(new_model_collection)
66
+
70
67
  if same_model_collection?(new_model_collection)
71
68
  new_model_collection_attribute_values = model_collection_attribute_values(new_model_collection)
72
69
  @table.swt_widget.items.each_with_index do |table_item, row_index|
@@ -83,24 +80,38 @@ module Glimmer
83
80
  @last_model_collection_attribute_values = new_model_collection_attribute_values
84
81
  else
85
82
  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 ||= {}
83
+ @model_observer_registrations ||= {}
84
+ new_model_collection.each do |model|
85
+ @model_observer_registrations[model] ||= {}
86
+ @column_properties.each do |column_property|
87
+ old_model_observer_registration = @model_observer_registrations[model][column_property]
88
+ remove_dependent(@table_observer_registration => old_model_observer_registration) if old_model_observer_registration
89
+ old_model_observer_registration&.unobserve
90
+ model_observer_registration = observe(model, column_property)
91
+ @model_observer_registrations[model][column_property] = model_observer_registration
92
+ add_dependent(@table_observer_registration => model_observer_registration)
93
+ end
94
+ end
95
+
93
96
  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])
97
+ new_model_collection.each do |model|
98
+ TABLE_ITEM_PROPERTIES.each do |table_item_property|
99
+ @column_properties.each do |column_property|
100
+ column_property = "#{column_property}_#{table_item_property}"
101
+ old_model_observer_registration = @model_observer_registrations[model][column_property]
102
+ remove_dependent(@table_observer_registration => old_model_observer_registration) if old_model_observer_registration
103
+ old_model_observer_registration&.unobserve
104
+ model_observer_registration = observe(model, column_property)
105
+ @model_observer_registrations[model][column_property] = model_observer_registration
106
+ add_dependent(@table_observer_registration => model_observer_registration)
107
+ end
108
+ end
100
109
  end
101
110
  end
111
+
102
112
  @model_collection = new_model_collection
103
113
  end
114
+
104
115
  populate_table(@model_collection, @table, @column_properties, internal_sort: internal_sort)
105
116
  end
106
117
  end
@@ -31,7 +31,8 @@ module Glimmer
31
31
  include Observable
32
32
  include Observer
33
33
 
34
- attr_reader :widget, :property
34
+ attr_reader :widget, :property, :model_binding
35
+
35
36
  def initialize(widget, property, sync_exec: nil, async_exec: nil)
36
37
  @widget = widget
37
38
  @property = property
@@ -40,17 +41,35 @@ module Glimmer
40
41
  SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @sync_exec, override_async_exec: @async_exec) do
41
42
  if @widget.is_a?(Glimmer::SWT::WidgetProxy) && @widget.respond_to?(:on_widget_disposed)
42
43
  @widget.on_widget_disposed do |dispose_event|
43
- deregister_all_observables unless @widget.shell_proxy.last_shell_closing?
44
+ unless @widget.shell_proxy.last_shell_closing?
45
+ @widget_proxy.widget_bindings.delete(self)
46
+ deregister_all_observables
47
+ end
44
48
  end
45
49
  end
46
50
  # TODO look into hooking on_shape_disposed without slowing down shapes in samples like Tetris
47
51
  end
52
+ # TODO try to come up with a more comprehensive and cleaner solution to miscallenous objects like MessageBoxProxy with regards to @widget_proxy
53
+ @widget_proxy = widget.is_a?(Glimmer::SWT::WidgetProxy) ? widget : (widget.respond_to?(:body_root) ? widget.body_root : widget)
54
+ end
55
+
56
+ def observe(*args)
57
+ if @widget_proxy.respond_to?(:widget_bindings)
58
+ # TODO try to come up with a more comprehensive and cleaner solution to miscallenous objects like MessageBoxProxy with regards to the following code
59
+ # assumes only one observation
60
+ @model_binding = args.first if args.size == 1
61
+ @widget_proxy.widget_bindings << self
62
+ end
63
+ super
48
64
  end
49
65
 
50
66
  def call(value)
51
67
  SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @sync_exec, override_async_exec: @async_exec) do
52
68
  if @widget.respond_to?(:disposed?) && @widget.disposed?
53
- deregister_all_observables unless @widget.shell_proxy.last_shell_closing?
69
+ unless @widget.shell_proxy.last_shell_closing?
70
+ @widget_proxy.widget_bindings.delete(self)
71
+ deregister_all_observables
72
+ end
54
73
  return
55
74
  end
56
75
  # need the rescue false for a scenario with tree items not being equal to model objects raising an exception
@@ -62,7 +81,10 @@ module Glimmer
62
81
 
63
82
  def evaluate_property
64
83
  if @widget.respond_to?(:disposed?) && @widget.disposed?
65
- deregister_all_observables unless @widget.shell_proxy.last_shell_closing?
84
+ unless @widget.shell_proxy.last_shell_closing?
85
+ @widget_proxy.widget_bindings.delete(self)
86
+ deregister_all_observables
87
+ end
66
88
  return
67
89
  end
68
90
  @widget.get_attribute(@property)
@@ -26,6 +26,7 @@ require 'glimmer/dsl/top_level_expression'
26
26
  require 'glimmer/ui/custom_widget'
27
27
  require 'glimmer/ui/custom_shell'
28
28
  require 'glimmer/swt/custom/code_text'
29
+ require 'glimmer/swt/custom/refined_table'
29
30
  require 'glimmer/swt/custom/radio_group'
30
31
  require 'glimmer/swt/custom/checkbox_group'
31
32
 
@@ -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
@@ -0,0 +1,182 @@
1
+ # Copyright (c) 2007-2022 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/ui/custom_widget'
23
+
24
+ module Glimmer
25
+ module SWT
26
+ module Custom
27
+ # RefinedTable is a customization of Table with support for Filtering/Pagination
28
+ class RefinedTable
29
+ include Glimmer::UI::CustomWidget
30
+
31
+ option :per_page, default: 10
32
+ option :page, default: 0
33
+ option :model_array
34
+
35
+ attr_accessor :refined_model_array
36
+ attr_reader :table_proxy, :page_text_proxy
37
+
38
+ before_body do
39
+ self.model_array ||= []
40
+ self.refined_model_array = []
41
+ end
42
+
43
+ after_body do
44
+ Glimmer::DataBinding::Observer.proc do |new_widget_bindings|
45
+ new_widget_bindings.each do |new_widget_binding|
46
+ if new_widget_binding.property.to_s == 'model_array' && !@data_bound
47
+ @data_bound = true
48
+ model_binding = new_widget_binding.model_binding
49
+ observe(self, :model_array) do
50
+ paginate
51
+ end
52
+ @table_proxy.content {
53
+ items(dsl: true) <=> [self, :refined_model_array, model_binding.binding_options.merge(read_only: true)]
54
+ }
55
+ paginate
56
+ end
57
+ end
58
+ end.observe(body_root.widget_bindings)
59
+ end
60
+
61
+ body {
62
+ composite {
63
+ composite {
64
+ layout_data(:fill, :center, true, false)
65
+
66
+ fill_layout(:horizontal)
67
+
68
+ button {
69
+ text '<<'
70
+
71
+ on_widget_selected do
72
+ self.page = first_page
73
+ paginate
74
+ end
75
+ }
76
+
77
+ button {
78
+ text '<'
79
+
80
+ on_widget_selected do
81
+ self.page -= 1
82
+ paginate
83
+ end
84
+ }
85
+
86
+ @page_text_proxy = text(:border, :center) {
87
+ text <= [self, :page, on_read: ->(value) { "#{value} of #{page_count}" }]
88
+
89
+ on_focus_gained do
90
+ @page_text_proxy.select_all
91
+ end
92
+
93
+ on_focus_lost do
94
+ self.page = @page_text_proxy.text.to_i
95
+ paginate
96
+ end
97
+
98
+ on_key_pressed do |key_event|
99
+ if key_event.keyCode == swt(:cr)
100
+ self.page = @page_text_proxy.text.to_i
101
+ paginate
102
+ end
103
+ end
104
+ }
105
+
106
+ button {
107
+ text '>'
108
+
109
+ on_widget_selected do
110
+ self.page += 1
111
+ paginate
112
+ end
113
+ }
114
+
115
+ button {
116
+ text '>>'
117
+
118
+ on_widget_selected do
119
+ self.page = last_page
120
+ paginate
121
+ end
122
+ }
123
+ }
124
+
125
+ @children_owner = @table_proxy = table(swt_style)
126
+ }
127
+ }
128
+
129
+ def table_block=(block)
130
+ @table_proxy.content(&block)
131
+ end
132
+
133
+ def method_missing(method_name, *args, &block)
134
+ dsl_mode = @dsl_mode || args.last.is_a?(Hash) && args.last[:dsl]
135
+ if dsl_mode
136
+ args.pop if args.last.is_a?(Hash) && args.last[:dsl]
137
+ super(method_name, *args, &block)
138
+ elsif @table_proxy&.respond_to?(method_name, *args, &block)
139
+ @table_proxy&.send(method_name, *args, &block)
140
+ else
141
+ super
142
+ end
143
+ end
144
+
145
+ def respond_to?(method_name, *args, &block)
146
+ dsl_mode = @dsl_mode || args.last.is_a?(Hash) && args.last[:dsl]
147
+ if dsl_mode
148
+ args = args[0...-1] if args.last.is_a?(Hash) && args.last[:dsl]
149
+ super(method_name, *args, &block)
150
+ else
151
+ super || @table_proxy&.respond_to?(method_name, *args, &block)
152
+ end
153
+ end
154
+
155
+ def page_count
156
+ (model_array && (model_array.count / per_page.to_f).ceil) || 0
157
+ end
158
+
159
+ def corrected_page(initial_page_value = nil)
160
+ correct_page = initial_page_value || page
161
+ correct_page = [correct_page, page_count].min
162
+ correct_page = [correct_page, 1].max
163
+ correct_page = (model_array&.count.to_i > 0) ? (correct_page > 0 ? correct_page : 1) : 0
164
+ correct_page
165
+ end
166
+
167
+ def first_page
168
+ (model_array&.count.to_i > 0) ? 1 : 0
169
+ end
170
+
171
+ def last_page
172
+ page_count
173
+ end
174
+
175
+ def paginate
176
+ self.page = corrected_page(page)
177
+ self.refined_model_array = model_array[(page - 1) * per_page, per_page]
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -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
@@ -159,7 +159,8 @@ module Glimmer
159
159
  @parent_proxy = parent
160
160
  styles, extra_options = extract_args(underscored_widget_name, args)
161
161
  swt_widget_class = self.class.swt_widget_class_for(underscored_widget_name)
162
- @swt_widget = swt_widget_class.new(@parent_proxy.swt_widget, style(underscored_widget_name, styles), *extra_options)
162
+ swt_widget_producer = @parent_proxy.respond_to?(:children_owner) ? @parent_proxy.children_owner : @parent_proxy
163
+ @swt_widget = swt_widget_class.new(swt_widget_producer.swt_widget, style(underscored_widget_name, styles), *extra_options)
163
164
  else
164
165
  @swt_widget = swt_widget
165
166
  underscored_widget_name = self.class.underscored_widget_name(@swt_widget)
@@ -769,6 +770,10 @@ module Glimmer
769
770
  end
770
771
  end
771
772
  end
773
+
774
+ def widget_bindings
775
+ @widget_bindings ||= []
776
+ end
772
777
 
773
778
  def content(&block)
774
779
  auto_exec do
@@ -271,6 +271,14 @@ module Glimmer
271
271
  "#{attribute_name}="
272
272
  end
273
273
 
274
+ def shell_proxy
275
+ @body_root.shell_proxy
276
+ end
277
+
278
+ def children_owner
279
+ @children_owner || @body_root
280
+ end
281
+
274
282
  def disposed?
275
283
  swt_widget.isDisposed
276
284
  end
@@ -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)
@@ -29,3 +29,4 @@ Parking: kw-6icVgDR4
29
29
  Hello, Custom Widget!: aJHLo5yLDZc
30
30
  Hello, Custom Shell!: c8Eb8GWM_XQ
31
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
@@ -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|
@@ -0,0 +1,159 @@
1
+ # Copyright (c) 2007-2022 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-swt'
23
+ require 'date'
24
+
25
+ class HelloRefinedTable
26
+ BaseballTeam = Struct.new(:name, :town, :ballpark, keyword_init: true) do
27
+ class << self
28
+ def all
29
+ @all ||= [
30
+ {town: 'Chicago', name: 'White Sox', ballpark: 'Guaranteed Rate Field'},
31
+ {town: 'Cleveland', name: 'Indians', ballpark: 'Progressive Field'},
32
+ {town: 'Detroit', name: 'Tigers', ballpark: 'Comerica Park'},
33
+ {town: 'Kansas City', name: 'Royals', ballpark: 'Kauffman Stadium'},
34
+ {town: 'Minnesota', name: 'Twins', ballpark: 'Target Field'},
35
+ {town: 'Baltimore', name: 'Orioles', ballpark: 'Oriole Park at Camden Yards'},
36
+ {town: 'Boston', name: 'Red Sox', ballpark: 'Fenway Park'},
37
+ {town: 'New York', name: 'Yankees', ballpark: 'Comerica Park'},
38
+ {town: 'Tampa Bay', name: 'Rays', ballpark: 'Tropicana Field'},
39
+ {town: 'Toronto', name: 'Blue Jays', ballpark: 'Rogers Centre'},
40
+ {town: 'Houston', name: 'Astros', ballpark: 'Minute Maid Park'},
41
+ {town: 'Los Angeles', name: 'Angels', ballpark: 'Angel Stadium'},
42
+ {town: 'Oakland', name: 'Athletics', ballpark: 'RingCentral Coliseum'},
43
+ {town: 'Seattle', name: 'Mariners', ballpark: 'T-Mobile Park'},
44
+ {town: 'Texas', name: 'Rangers', ballpark: 'Globe Life Field'},
45
+ {town: 'Chicago', name: 'Cubs', ballpark: 'Wrigley Field'},
46
+ {town: 'Cincinnati', name: 'Reds', ballpark: 'Great American Ball Park'},
47
+ {town: 'Milwaukee', name: 'Brewers', ballpark: 'American Family Field'},
48
+ {town: 'Pittsburgh', name: 'Pirates', ballpark: 'PNC Park'},
49
+ {town: 'St. Louis', name: 'Cardinals', ballpark: 'Busch Stadium'},
50
+ {town: 'Atlanta', name: 'Braves', ballpark: 'Truist Park'},
51
+ {town: 'Miami', name: 'Marlins', ballpark: 'LoanDepot Park'},
52
+ {town: 'New York', name: 'Mets', ballpark: 'Citi Field'},
53
+ {town: 'Philadelphia', name: 'Phillies', ballpark: 'Citizens Bank Park'},
54
+ {town: 'Washington', name: 'Nationals', ballpark: 'Nationals Park'},
55
+ {town: 'Arizona', name: 'Diamondbacks', ballpark: 'Chase Field'},
56
+ {town: 'Colorado', name: 'Rockies', ballpark: 'Coors Field'},
57
+ {town: 'Los Angeles', name: 'Dodgers', ballpark: 'Dodger Stadium'},
58
+ {town: 'San Diego', name: 'Padres', ballpark: 'Petco Park'},
59
+ {town: 'San Francisco', name: 'Giants', ballpark: 'Oracle Park'},
60
+ ].map {|team_kwargs| new(team_kwargs)}
61
+ end
62
+ end
63
+
64
+ def complete_name
65
+ "#{town} #{name}"
66
+ end
67
+ end
68
+
69
+ BaseballGame = Struct.new(:date, :home_team, :away_team, keyword_init: true) do
70
+ def home_team_name
71
+ home_team.complete_name
72
+ end
73
+
74
+ def away_team_name
75
+ away_team.complete_name
76
+ end
77
+
78
+ def ballpark
79
+ home_team.ballpark
80
+ end
81
+ end
82
+
83
+ BaseballSeason = Struct.new(:year) do
84
+ def games
85
+ if @games.nil?
86
+ @games = []
87
+ baseball_team_combinations = BaseballTeam.all.combination(2).to_a
88
+ current_day = first_day
89
+ day_offset = 0
90
+ begin
91
+ if (day_offset % 7 != 6)
92
+ day_games = []
93
+ half_teams_count = BaseballTeam.all.count / 2
94
+ while day_games.uniq.count < half_teams_count
95
+ baseball_team_pair = baseball_team_combinations.sample
96
+ teams_played_so_far = day_games.map {|game| [game.home_team, game.away_team]}.flatten
97
+ unless teams_played_so_far.include?(baseball_team_pair.first) || teams_played_so_far.include?(baseball_team_pair.last)
98
+ baseball_game = BaseballGame.new(
99
+ date: current_day,
100
+ home_team: baseball_team_pair.first,
101
+ away_team: baseball_team_pair.last,
102
+ )
103
+ day_games << baseball_game
104
+ @games << baseball_game
105
+ end
106
+ end
107
+ end
108
+ day_offset += 1
109
+ current_day += 1
110
+ end while current_day != first_day_of_playoffs
111
+ end
112
+ @games
113
+ end
114
+
115
+ def first_day
116
+ @first_day ||= Date.new(year, 04, 01)
117
+ end
118
+
119
+ def first_day_of_playoffs
120
+ @last_day ||= Date.new(year, 10, 01)
121
+ end
122
+ end
123
+
124
+ include Glimmer::UI::Application
125
+
126
+ before_body do
127
+ @baseball_season = BaseballSeason.new(Time.now.year)
128
+ end
129
+
130
+ body {
131
+ shell {
132
+ text 'Hello, Refined Table!'
133
+
134
+ refined_table(per_page: 20) { # also `page: 1` by default
135
+ table_column {
136
+ width 100
137
+ text 'Date'
138
+ }
139
+ table_column {
140
+ width 200
141
+ text 'Ballpark'
142
+ }
143
+ table_column {
144
+ width 150
145
+ text 'Home Team'
146
+ }
147
+ table_column {
148
+ width 150
149
+ text 'Away Team'
150
+ }
151
+
152
+ model_array <= [@baseball_season, :games, column_attributes: {'Home Team' => :home_team_name, 'Away Team' => :away_team_name}]
153
+ }
154
+ }
155
+ }
156
+
157
+ end
158
+
159
+ HelloRefinedTable.launch
@@ -302,15 +302,16 @@ class HelloTable
302
302
  }
303
303
 
304
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:
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:
309
313
  # `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
- ]
314
+ items <=> [BaseballGame, :schedule]
314
315
 
315
316
  # Data-bind table selection
316
317
  selection <=> [BaseballGame, :selected_game]
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.3.0
4
+ version: 4.24.4.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-27 00:00:00.000000000 Z
11
+ date: 2022-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -472,6 +472,7 @@ files:
472
472
  - lib/glimmer/swt/custom/code_text.rb
473
473
  - lib/glimmer/swt/custom/drawable.rb
474
474
  - lib/glimmer/swt/custom/radio_group.rb
475
+ - lib/glimmer/swt/custom/refined_table.rb
475
476
  - lib/glimmer/swt/custom/shape.rb
476
477
  - lib/glimmer/swt/custom/shape/arc.rb
477
478
  - lib/glimmer/swt/custom/shape/cubic.rb
@@ -670,6 +671,7 @@ files:
670
671
  - samples/hello/hello_progress_bar.rb
671
672
  - samples/hello/hello_radio.rb
672
673
  - samples/hello/hello_radio_group.rb
674
+ - samples/hello/hello_refined_table.rb
673
675
  - samples/hello/hello_sash_form.rb
674
676
  - samples/hello/hello_scale.rb
675
677
  - samples/hello/hello_scrolled_composite.rb