glimmer 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c6aff23e9890326138ca130e2e7bb80d2ff62d9586d3ff9e62cfcb97dab0c18
4
- data.tar.gz: '038211b85b37a102b05006b5961ec60ad20c62eca31bd15f833065170d9b6b20'
3
+ metadata.gz: fbe97823fd25586221485191db661a4cb6fe71d8d9be9e89b60d617d5f496540
4
+ data.tar.gz: d81b11d52ce3f0fe1fdb46d9f1a6c286ccd95c3021118f71b4f72d7724cd0f41
5
5
  SHA512:
6
- metadata.gz: 7fea559224aa5069c03dfebdcbd4981ed7c6296d171098077164019e9c3fa8fd053fcfe0fcaf7161b03d0ad3a1dbda0af4c719629fd55a9af9868760a9b398e4
7
- data.tar.gz: 2abec0e6d750fc5ed6417ea79c18aa102c8d2d75ee3c253a2ecec1f0e01c22793e03dc7ff25b10a99c4b81d1a907712e7f558e85158ffa675bcfe24928ec7ff7
6
+ metadata.gz: 930a0914fc83db952df2eba9321779ee34a3d2819a0dabb05a31615b97b1eb57ff222321bd9db9fa4d6950e0f4e68f6455a66223ac1a1126a1c72be75a8a8b46
7
+ data.tar.gz: 5ab308d9b3403a9876d8f40f8a51d277cf0c88527f257977f87a21fc530a95a0d3e92d64a6b4025a56b2ed857f3d6b1c4d0d3df10bed7999c25cf90e589d6934
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
- # Glimmer 0.8.1 Beta (Ruby Desktop Development GUI Library)
1
+ # Glimmer 0.8.2 Beta (Ruby Desktop Development GUI Library)
2
2
  [![Gem Version](https://badge.fury.io/rb/glimmer.svg)](http://badge.fury.io/rb/glimmer)
3
3
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer)
4
- [![Test Coverage](https://api.codeclimate.com/v1/badges/38fbc278022862794414/test_coverage)](https://codeclimate.com/github/AndyObtiva/glimmer/test_coverage)
5
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/38fbc278022862794414/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer/maintainability)
6
5
 
7
6
  Glimmer is a native-GUI cross-platform desktop development library written in Ruby. Glimmer's main innovation is a JRuby DSL that enables productive and efficient authoring of desktop application user-interfaces while relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support to greatly facilitate synchronizing the GUI with domain models. As a result, that achieves true decoupling of object oriented components, enabling developers to solve business problems without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models test-first afterwards.
@@ -71,11 +70,11 @@ Glimmer app:
71
70
 
72
71
  ![Tic Tac Toe](images/glimmer-tic-tac-toe.png)
73
72
 
74
- NOTE: Glimmer is in beta mode. Please help make better by adopting for small or low risk projects and providing feedback.
73
+ NOTE: Glimmer is in beta mode. Please help make better by [contributing](#contributing), adopting for small or low risk projects, and providing feedback.
75
74
 
76
75
  ## Table of contents
77
76
 
78
- - [Glimmer 0.8.1 Beta (Ruby Desktop Development GUI Library)](#glimmer-081-beta-ruby-desktop-development-gui-library)
77
+ - [Glimmer 0.8.2 Beta (Ruby Desktop Development GUI Library)](#glimmer-082-beta-ruby-desktop-development-gui-library)
79
78
  - [Examples](#examples)
80
79
  - [Hello, World!](#hello-world)
81
80
  - [Tic Tac Toe](#tic-tac-toe)
@@ -89,23 +88,55 @@ NOTE: Glimmer is in beta mode. Please help make better by adopting for small or
89
88
  - [Basic Usage](#basic-usage)
90
89
  - [Advanced Usage](#advanced-usage)
91
90
  - [Scaffolding](#scaffolding)
91
+ - [App](#app)
92
+ - [Custom Shell](#custom-shell)
93
+ - [Custom Widget](#custom-widget)
94
+ - [Custom Shell Gem](#custom-shell-gem)
95
+ - [Custom Widget Gem](#custom-widget-gem)
92
96
  - [Girb (Glimmer irb) Command](#girb-glimmer-irb-command)
93
97
  - [Glimmer DSL Syntax](#glimmer-dsl-syntax)
94
98
  - [Widgets](#widgets)
99
+ - [Display](#display)
100
+ - [SWT Proxies](#swt-proxies)
101
+ - [Dialog](#dialog)
102
+ - [Menus](#menus)
95
103
  - [Widget Styles](#widget-styles)
104
+ - [Explicit SWT Style Bit](#explicit-swt-style-bit)
105
+ - [Negative SWT Style Bits](#negative-swt-style-bits)
106
+ - [Extra SWT Styles](#extra-swt-styles)
96
107
  - [Widget Properties](#widget-properties)
108
+ - [Colors](#colors)
109
+ - [Fonts](#fonts)
97
110
  - [Layouts](#layouts)
98
111
  - [Layout Data](#layout-data)
99
112
  - [Data-Binding](#data-binding)
113
+ - [General Examples](#general-examples)
114
+ - [Combo](#combo)
115
+ - [List](#list)
116
+ - [Table](#table)
117
+ - [Tree](#tree)
100
118
  - [Observer](#observer)
119
+ - [Observing Widgets](#observing-widgets)
120
+ - [Observing Models](#observing-models)
101
121
  - [Custom Widgets](#custom-widgets)
122
+ - [Simple Example](#simple-example)
123
+ - [Hook Example](#hook-example)
124
+ - [Content/Options Example](#contentoptions-example)
125
+ - [Gotcha](#gotcha)
102
126
  - [Custom Shells](#custom-shells)
103
127
  - [Miscellaneous](#miscellaneous)
128
+ - [Application Menu Items (About/Preferences)](#application-menu-items-aboutpreferences)
129
+ - [App Name and Version](#app-name-and-version)
130
+ - [Multi-DSL Support](#multi-dsl-support)
131
+ - [Video Widget](#video-widget)
132
+ - [Browser Widget](#browser-widget)
104
133
  - [Glimmer Style Guide](#glimmer-style-guide)
105
134
  - [Samples](#samples)
106
135
  - [Hello Samples](#hello-samples)
107
136
  - [Elaborate Samples](#elaborate-samples)
108
137
  - [External Samples](#external-samples)
138
+ - [Glimmer Calculator](#glimmer-calculator)
139
+ - [Gladiator](#gladiator)
109
140
  - [In Production](#in-production)
110
141
  - [SWT Reference](#swt-reference)
111
142
  - [SWT Packages](#swt-packages)
@@ -154,7 +185,7 @@ https://www.eclipse.org/swt/faq.php
154
185
 
155
186
  - SWT 4.15 (comes included in Glimmer gem)
156
187
  - JRuby 9.2.11.1 (supporting Ruby 2.5.x syntax) (find at [https://www.jruby.org/download](https://www.jruby.org/download))
157
- - Java SE Runtime Environment 7 or higher (find at [https://www.oracle.com/java/technologies/javase-downloads.html](https://www.oracle.com/java/technologies/javase-downloads.html))
188
+ - JDK 8 - 10 (find at [https://www.oracle.com/java/technologies/javase-downloads.html](https://www.oracle.com/java/technologies/javase-downloads.html))
158
189
  - (Optional) RVM is needed for [Scaffolding](#scaffolding) only (find at [https://rvm.io/](https://rvm.io/))
159
190
 
160
191
  On **Mac** and **Linux**, an easy way to obtain JRuby is through [RVM](http://rvm.io) by running:
@@ -173,7 +204,7 @@ Please follow these instructions to make the `glimmer` command available on your
173
204
 
174
205
  Run this command to install directly:
175
206
  ```
176
- jgem install glimmer -v 0.8.1
207
+ jgem install glimmer -v 0.8.2
177
208
  ```
178
209
 
179
210
  `jgem` is JRuby's version of `gem` command.
@@ -184,7 +215,7 @@ Otherwise, you may also run `jruby -S gem install ...`
184
215
 
185
216
  Add the following to `Gemfile`:
186
217
  ```
187
- gem 'glimmer', '~> 0.8.1'
218
+ gem 'glimmer', '~> 0.8.2'
188
219
  ```
189
220
 
190
221
  And, then run:
@@ -1099,7 +1130,7 @@ https://help.eclipse.org/2019-12/nftopic/org.eclipse.platform.doc.isv/reference/
1099
1130
 
1100
1131
  Data-binding is done with `bind` command following widget property to bind and taking model and bindable attribute as arguments.
1101
1132
 
1102
- #### General data-binding examples:
1133
+ #### General Examples
1103
1134
 
1104
1135
  `text bind(contact, :first_name)`
1105
1136
 
@@ -1270,7 +1301,62 @@ The Glimmer code is not much different from above except for passing the `:multi
1270
1301
 
1271
1302
  Note that in all the data-binding examples above, there was also an observer attached to the `button` widget to trigger an action on the model, which in turn triggers a data-binding update on the `list` or `combo`. Observers will be discussed in more details in the [next section](#observer).
1272
1303
 
1273
- You may learn more about Glimmer's data-binding syntax by reading the [Eclipse Zone Tutorial](http://eclipse.dzone.com/articles/an-introduction-glimmer) mentioned in resources and opening up the samples under the [samples](samples) directory.
1304
+ You may learn more about Glimmer's data-binding syntax by reading the code under the [samples](samples) directory.
1305
+
1306
+ #### Table
1307
+
1308
+ The SWT Tree widget renders a multi-column data table, such as a contact listing or a sales report.
1309
+
1310
+ To data-bind a Table, you need the main model, the collection property, and the text display attribute for each table column.
1311
+
1312
+ This involves using the `bind` keyword mentioned above in addition to a special `column_properties` keyword that takes the table column text attribute methods.
1313
+
1314
+ It assumes you have defined the table columns via `table_column` widget.
1315
+
1316
+ Example:
1317
+
1318
+ ```ruby
1319
+ shell {
1320
+ @table = table {
1321
+ table_column {
1322
+ text "Name"
1323
+ width 120
1324
+ }
1325
+ table_column {
1326
+ text "Age"
1327
+ width 120
1328
+ }
1329
+ table_column {
1330
+ text "Adult"
1331
+ width 120
1332
+ }
1333
+ items bind(group, :people), column_properties(:name, :age, :adult)
1334
+ selection bind(group, :selected_person)
1335
+ }
1336
+ }
1337
+ ```
1338
+
1339
+ The code above includes two data-bindings:
1340
+ - 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.
1341
+ - 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)
1342
+
1343
+ Additionally, Table `items` data-binding automatically stores each node model unto the SWT TableItem object via `setData` method. This enables things like searchability.
1344
+
1345
+ The table widget in Glimmer is represented by a subclass of `WidgetProxy` called `TableProxy`.
1346
+ TableProxy includes a `search` method that takes a block to look for a table item.
1347
+
1348
+ Example:
1349
+
1350
+ ```ruby
1351
+ found_array = @table.search { |table_item| table_item.getData == company.owner }
1352
+ ```
1353
+
1354
+ 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.
1355
+
1356
+ 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)`.
1357
+ This automatically leverages the SWT TableEditor custom class behind the scenes, displaying a text widget to the user to change the selected or
1358
+ passed table item text into something else.
1359
+ It automatically persists the change to `items` data-bound model on ENTER/FOCUS-OUT or cancels on ESC/NO-CHANGE.
1274
1360
 
1275
1361
  #### Tree
1276
1362
 
@@ -1486,7 +1572,9 @@ Glimmer supports creating custom widgets with minimal code, which automatically
1486
1572
 
1487
1573
  Simply create a new class that includes `Glimmer::UI::CustomWidget` and put Glimmer DSL code in its `#body` block (its return value is stored in `#body_root` attribute). Glimmer will then automatically recognize this class by convention when it encounters a keyword matching the class name converted to underscored lowercase (and namespace double-colons `::` replaced with double-underscores `__`)
1488
1574
 
1489
- #### Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1575
+ #### Simple Example
1576
+
1577
+ (you may copy/paste in [`girb`](#girb-glimmer-irb-command))
1490
1578
 
1491
1579
  Definition:
1492
1580
  ```ruby
@@ -1512,7 +1600,9 @@ shell {
1512
1600
 
1513
1601
  As you can see, `RedLabel` became Glimmer DSL keyword: `red_label`
1514
1602
 
1515
- #### Another Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1603
+ #### Hook Example
1604
+
1605
+ (you may copy/paste in [`girb`](#girb-glimmer-irb-command))
1516
1606
 
1517
1607
  Definition:
1518
1608
  ```ruby
@@ -1561,7 +1651,9 @@ Additionally, custom widgets can call the following class methods:
1561
1651
  - `::options(*option_names)`: declares a list of options by taking an option name array (symbols/strings). This generates option attribute accessors (e.g. `options :orientation, :bg_color` generates `#orientation`, `#orientation=(v)`, `#bg_color`, and `#bg_color=(v)` attribute accessors)
1562
1652
  - `::option(option_name, default: nil)`: declares a single option taking option name and default value as arguments (also generates attribute accessors just like `::options`)
1563
1653
 
1564
- #### Content/Options Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
1654
+ #### Content/Options Example
1655
+
1656
+ (you may copy/paste in [`girb`](#girb-glimmer-irb-command))
1565
1657
 
1566
1658
  Definition:
1567
1659
  ```ruby
@@ -2007,15 +2099,15 @@ glimmer samples/elaborate/tic_tac_toe.rb # demonstrates a full MVC application
2007
2099
 
2008
2100
  ### External Samples
2009
2101
 
2010
- #### [Glimmer Calculator](https://github.com/AndyObtiva/glimmer-cs-calculator)
2102
+ #### Glimmer Calculator
2011
2103
 
2012
- ![Glimmer Calculator](https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-calculator/v1.0.0/glimmer-cs-calculator-screenshot.png)
2104
+ [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-calculator/v1.0.0/glimmer-cs-calculator-screenshot.png" />](https://github.com/AndyObtiva/glimmer-cs-calculator)
2013
2105
 
2014
2106
  [Glimmer Calculator](https://github.com/AndyObtiva/glimmer-cs-calculator) is a basic calculator sample project demonstrating data-binding and TDD (test-driven-development) with Glimmer following the MVP pattern (Model-View-Presenter).
2015
2107
 
2016
- #### [Gladiator](https://github.com/AndyObtiva/glimmer-cs-gladiator)
2108
+ #### Gladiator
2017
2109
 
2018
- ![Gladiator](https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/v0.1.5/images/glimmer-gladiator.png)
2110
+ [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer-cs-gladiator/v0.1.5/images/glimmer-gladiator.png" />](https://github.com/AndyObtiva/glimmer-cs-gladiator)
2019
2111
 
2020
2112
  [Gladiator](https://github.com/AndyObtiva/glimmer-cs-gladiator) (short for Glimmer Editor) is a Glimmer sample project under on-going development.
2021
2113
  You may check it out to learn how to build a Glimmer Custom Shell gem.
@@ -2200,6 +2292,8 @@ The Glimmer rake task allows passing extra options to javapackager via:
2200
2292
  Example (Rakefile):
2201
2293
 
2202
2294
  ```ruby
2295
+ require 'glimmer/rake_task'
2296
+
2203
2297
  Glimmer::Package.javapackager_extra_args = '-BlicenseType="MIT" -Bmac.category="public.app-category.business" -Bmac.signing-key-developer-id-app="Andy Maleh"'
2204
2298
  ```
2205
2299
 
@@ -2283,10 +2377,11 @@ Exec failed with code 2 command [[/usr/bin/SetFile, -c, icnC, /var/folders/4_/g1
2283
2377
  ## Resources
2284
2378
 
2285
2379
  * [Code Master Blog](http://andymaleh.blogspot.com/search/label/Glimmer)
2286
- * [Eclipse Zone Tutorial](http://eclipse.dzone.com/articles/an-introduction-glimmer)
2287
- * [InfoQ Article](http://www.infoq.com/news/2008/02/glimmer-jruby-swt)
2288
- * [RubyConf 2008 Video](https://confreaks.tv/videos/rubyconf2008-desktop-development-with-glimmer)
2289
2380
  * [JRuby Cookbook by Justin Edelson & Henry Liu](http://shop.oreilly.com/product/9780596519650.do)
2381
+ * [MountainWest RubyConf 2011 Video](https://confreaks.tv/videos/mwrc2011-whatever-happened-to-desktop-development-in-ruby)
2382
+ * [RubyConf 2008 Video](https://confreaks.tv/videos/rubyconf2008-desktop-development-with-glimmer)
2383
+ * [InfoQ Article](http://www.infoq.com/news/2008/02/glimmer-jruby-swt)
2384
+ * [DZone Tutorial](https://dzone.com/articles/an-introduction-glimmer)
2290
2385
 
2291
2386
  ## Help
2292
2387
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.1
1
+ 0.8.2
@@ -16,6 +16,11 @@ module Glimmer
16
16
  @table = parent
17
17
  @model_binding = model_binding
18
18
  @column_properties = column_properties
19
+ if @table.respond_to?(:column_properties=)
20
+ @table.column_properties = @column_properties
21
+ else # assume custom widget
22
+ @table.body_root.column_properties = @column_properties
23
+ end
19
24
  call(@model_binding.evaluate_property)
20
25
  model = model_binding.base_model
21
26
  observe(model, model_binding.property_name_expression)
@@ -24,23 +29,27 @@ module Glimmer
24
29
  end
25
30
  end
26
31
 
27
- def call(model_collection=nil)
28
- if model_collection and model_collection.is_a?(Array)
29
- # TODO clean observer registrations
30
- observe(model_collection, @column_properties)
31
- @model_collection = model_collection
32
+ def call(new_model_collection=nil)
33
+ if new_model_collection and new_model_collection.is_a?(Array)
34
+ observe(new_model_collection, @column_properties)
35
+ @model_collection = new_model_collection
32
36
  end
33
37
  populate_table(@model_collection, @table, @column_properties)
34
38
  end
35
39
 
36
40
  def populate_table(model_collection, parent, column_properties)
41
+ selected_table_item_models = parent.swt_widget.getSelection.map(&:getData)
37
42
  parent.swt_widget.removeAll
38
43
  model_collection.each do |model|
39
44
  table_item = TableItem.new(parent.swt_widget, SWT::SWTProxy[:none])
40
45
  for index in 0..(column_properties.size-1)
41
46
  table_item.setText(index, model.send(column_properties[index]).to_s)
42
47
  end
48
+ table_item.setData(model)
43
49
  end
50
+ selected_table_items = parent.search {|item| selected_table_item_models.include?(item.getData) }
51
+ selected_table_items = [parent.swt_widget.getItems.first].to_java(TableItem) if selected_table_items.empty? && !parent.swt_widget.getItems.empty?
52
+ parent.swt_widget.setSelection(selected_table_items) unless selected_table_items.empty?
44
53
  end
45
54
  end
46
55
  end
@@ -0,0 +1,29 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/parent_expression'
3
+ require 'glimmer/dsl/top_level_expression'
4
+ require 'glimmer/swt/shell_proxy'
5
+ require 'glimmer/swt/message_box_proxy'
6
+ require 'glimmer/swt/swt_proxy'
7
+
8
+ module Glimmer
9
+ module DSL
10
+ module SWT
11
+ class MessageBoxExpression < StaticExpression
12
+ include TopLevelExpression
13
+ include ParentExpression
14
+
15
+ include_package 'org.eclipse.swt.widgets'
16
+
17
+ def can_interpret?(parent, keyword, *args, &block)
18
+ keyword == 'message_box'
19
+ end
20
+
21
+ def interpret(parent, keyword, *args, &block)
22
+ potential_parent = args.first
23
+ parent = args.shift if potential_parent.is_a?(Shell) || (potential_parent.respond_to?(:swt_widget) && potential_parent.swt_widget.is_a?(Shell))
24
+ Glimmer::SWT::MessageBoxProxy.new(parent, Glimmer::SWT::SWTProxy[args])
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -32,3 +32,4 @@ end
32
32
 
33
33
  require 'glimmer/swt/widget_proxy'
34
34
  require 'glimmer/swt/tree_proxy'
35
+ require 'glimmer/swt/table_proxy'
@@ -2,6 +2,54 @@ module Glimmer
2
2
  module Package
3
3
  class << self
4
4
  attr_accessor :javapackager_extra_args
5
+
6
+ def config
7
+ project_name = File.basename(File.expand_path('.'))
8
+ if !File.exists?('config/warble.rb')
9
+ puts 'Generating JAR configuration (config/warble.rb) to use with Warbler...'
10
+ system('mkdir -p config')
11
+ system('warble config')
12
+ new_config = File.read('config/warble.rb').split("\n").inject('') do |output, line|
13
+ if line.include?('config.dirs =')
14
+ line = line.sub('# ', '').sub(/=[^=\n]+$/, '= %w(app config db lib script bin docs fonts icons images sounds videos)')
15
+ end
16
+ if line.include?('config.includes =')
17
+ line = line.sub('# ', '').sub(/=[^=\n]+$/, "= FileList['LICENSE.txt', 'VERSION']")
18
+ end
19
+ if line.include?('config.autodeploy_dir =')
20
+ line = line.sub('# ', '')
21
+ end
22
+ output + "\n" + line
23
+ end
24
+ File.write('config/warble.rb', new_config)
25
+ end
26
+ end
27
+
28
+ def jar
29
+ system('mkdir -p dist')
30
+ puts "Generating JAR with Warbler..."
31
+ system('warble')
32
+ end
33
+
34
+ def native
35
+ require 'facets/string/titlecase'
36
+ require 'facets/string/underscore'
37
+ project_name = File.basename(File.expand_path('.'))
38
+ version_file = File.expand_path('./VERSION')
39
+ version = (File.read(version_file).strip if File.exists?(version_file) && File.file?(version_file)) rescue nil
40
+ license_file = File.expand_path('./LICENSE.txt')
41
+ license = (File.read(license_file).strip if File.exists?(license_file) && File.file?(license_file)) rescue nil
42
+ human_name = project_name.underscore.titlecase
43
+ command = "javapackager -deploy -native -outdir packages -outfile \"#{project_name}\" -srcfiles \"dist/#{project_name}.jar\" -appclass JarMain -name \"#{human_name}\" -title \"#{human_name}\" -Bmac.CFBundleName=\"#{human_name}\" -Bmac.CFBundleIdentifier=\"org.#{project_name}.application.#{project_name}\" -Bmac.category=\"public.app-category.business\" "
44
+ command += " -BjvmOptions=-XstartOnFirstThread " if OS.mac?
45
+ command += " -BappVersion=#{version} -Bmac.CFBundleVersion=#{version} " if version
46
+ command += " -srcfiles LICENSE.txt -BlicenseFile=LICENSE.txt " if license
47
+ command += " #{javapackager_extra_args} " if javapackager_extra_args
48
+ command += " #{ENV['JAVAPACKAGER_EXTRA_ARGS']} " if ENV['JAVAPACKAGER_EXTRA_ARGS']
49
+ puts "Generating DMG/PKG/APP/JNLP with javapackager..."
50
+ puts command
51
+ system command
52
+ end
5
53
  end
6
54
  end
7
55
  end
@@ -7,57 +7,26 @@ namespace :glimmer do
7
7
  namespace :package do
8
8
  desc 'Generate JAR config file'
9
9
  task :config do
10
- project_name = File.basename(File.expand_path('.'))
11
- if !File.exists?('config/warble.rb')
12
- puts 'Generating JAR configuration (config/warble.rb) to use with Warbler...'
13
- system('mkdir -p config')
14
- system('warble config')
15
- new_config = File.read('config/warble.rb').split("\n").inject('') do |output, line|
16
- if line.include?('config.dirs =')
17
- line = line.sub('# ', '').sub(/=[^=\n]+$/, '= %w(app config db lib script bin docs fonts icons images sounds videos)')
18
- end
19
- if line.include?('config.includes =')
20
- line = line.sub('# ', '').sub(/=[^=\n]+$/, "= FileList['LICENSE.txt', 'VERSION']")
21
- end
22
- if line.include?('config.autodeploy_dir =')
23
- line = line.sub('# ', '')
24
- end
25
- output + "\n" + line
26
- end
27
- File.write('config/warble.rb', new_config)
28
- end
10
+ Glimmer::Package.config
29
11
  end
30
12
 
31
13
  desc 'Generate JAR file'
32
- task :jar => 'package:config' do
33
- system('mkdir -p dist')
34
- puts "Generating JAR with Warbler..."
35
- system('warble')
14
+ task :jar do
15
+ Glimmer::Package.jar
36
16
  end
37
17
 
38
- desc 'Generate Native files (DMG/PKG/APP on the Mac)'
39
- task :native => 'package:jar' do
40
- require 'facets/string/titlecase'
41
- require 'facets/string/underscore'
42
- project_name = File.basename(File.expand_path('.'))
43
- version_file = File.expand_path('./VERSION')
44
- version = (File.read(version_file).strip if File.exists?(version_file) && File.file?(version_file)) rescue nil
45
- license_file = File.expand_path('./LICENSE.txt')
46
- license = (File.read(license_file).strip if File.exists?(license_file) && File.file?(license_file)) rescue nil
47
- human_name = project_name.underscore.titlecase
48
- command = "javapackager -deploy -native -outdir packages -outfile \"#{project_name}\" -srcfiles \"dist/#{project_name}.jar\" -appclass JarMain -name \"#{human_name}\" -title \"#{human_name}\" -BjvmOptions=-XstartOnFirstThread -Bmac.CFBundleName=\"#{human_name}\" -Bmac.CFBundleIdentifier=\"org.#{project_name}.application.#{project_name}\" -Bmac.category=\"public.app-category.business\" "
49
- command += " -BappVersion=#{version} -Bmac.CFBundleVersion=#{version} " if version
50
- command += " -srcfiles LICENSE.txt -BlicenseFile=LICENSE.txt " if license
51
- command += " #{Glimmer::Package.javapackager_extra_args} " if Glimmer::Package.javapackager_extra_args
52
- command += " #{ENV['JAVAPACKAGER_EXTRA_ARGS']} " if ENV['JAVAPACKAGER_EXTRA_ARGS']
53
- puts "Generating DMG/PKG/APP/JNLP with javapackager..."
54
- puts command
55
- system command
18
+ desc 'Generate Native files (DMG/PKG/APP on the Mac, EXE on Windows, RPM/DEB on Linux)'
19
+ task :native do
20
+ Glimmer::Package.native
56
21
  end
57
22
  end
58
23
 
59
24
  desc 'Package app for distribution (generating config, jar, and native files)'
60
- task :package => 'package:native'
25
+ task :package do
26
+ Rake::Task['glimmer:package:config'].execute
27
+ Rake::Task['glimmer:package:jar'].execute
28
+ Rake::Task['glimmer:package:native'].execute
29
+ end
61
30
 
62
31
 
63
32
  desc 'Scaffold a Glimmer application directory structure to begin building a new app'
@@ -0,0 +1,48 @@
1
+ require 'glimmer/swt/swt_proxy'
2
+ require 'glimmer/swt/widget_proxy'
3
+ require 'glimmer/swt/display_proxy'
4
+ require 'glimmer/swt/shell_proxy'
5
+
6
+ module Glimmer
7
+ module SWT
8
+ # Proxy for org.eclipse.swt.widgets.Shell
9
+ #
10
+ # Follows the Proxy Design Pattern
11
+ class MessageBoxProxy
12
+ include_package 'org.eclipse.swt.widgets'
13
+
14
+ attr_reader :swt_widget
15
+
16
+ def initialize(parent, style)
17
+ parent = parent.swt_widget if parent.respond_to?(:swt_widget) && parent.swt_widget.is_a?(Shell)
18
+ @swt_widget = MessageBox.new(parent, style)
19
+ end
20
+
21
+ def open
22
+ @swt_widget.open
23
+ end
24
+
25
+ # TODO refactor the following methods to put in a JavaBean mixin or somethin (perhaps contribute to OSS project too)
26
+
27
+ def attribute_setter(attribute_name)
28
+ "set#{attribute_name.to_s.camelcase(:upper)}"
29
+ end
30
+
31
+ def attribute_getter(attribute_name)
32
+ "get#{attribute_name.to_s.camelcase(:upper)}"
33
+ end
34
+
35
+ def has_attribute?(attribute_name, *args)
36
+ @swt_widget.respond_to?(attribute_setter(attribute_name), args)
37
+ end
38
+
39
+ def set_attribute(attribute_name, *args)
40
+ @swt_widget.send(attribute_setter(attribute_name), *args) unless @swt_widget.send(attribute_getter(attribute_name)) == args.first
41
+ end
42
+
43
+ def get_attribute(attribute_name)
44
+ @swt_widget.send(attribute_getter(attribute_name))
45
+ end
46
+ end
47
+ end
48
+ end
@@ -102,24 +102,19 @@ module Glimmer
102
102
 
103
103
  def pack_same_size
104
104
  bounds = @swt_widget.getBounds
105
- width = @swt_widget.getBounds.width
106
- height = @swt_widget.getBounds.height
107
- x = @swt_widget.getBounds.x
108
- y = @swt_widget.getBounds.y
109
- if OS.windows?
105
+ if OS.mac?
106
+ @swt_widget.pack
107
+ @swt_widget.setBounds(bounds)
108
+ elsif OS.windows? || OS::Underlying.windows?
110
109
  minimum_size = @swt_widget.getMinimumSize
111
110
  @swt_widget.setMinimumSize(bounds.width, bounds.height)
112
- listener = on_control_resized {
113
- @swt_widget.setSize(bounds.width, bounds.height)
114
- @swt_widget.setLocation(bounds.x, bounds.y)
115
- }
111
+ listener = on_control_resized { @swt_widget.setBounds(bounds) }
116
112
  @swt_widget.pack
117
113
  @swt_widget.removeControlListener(listener.swt_listener)
118
114
  @swt_widget.setMinimumSize(minimum_size)
119
- else
120
- @swt_widget.pack
121
- @swt_widget.setSize(width, height)
122
- @swt_widget.setLocation(x, y)
115
+ elsif OS.linux?
116
+ @swt_widget.layout(true, true)
117
+ @swt_widget.setBounds(bounds)
123
118
  end
124
119
  end
125
120
 
@@ -0,0 +1,150 @@
1
+ require 'glimmer/swt/widget_proxy'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ class TableProxy < Glimmer::SWT::WidgetProxy
6
+ include Glimmer
7
+
8
+ module TableListenerEvent
9
+ def table_item
10
+ table_item_and_column_index[:table_item]
11
+ end
12
+
13
+ def column_index
14
+ table_item_and_column_index[:column_index]
15
+ end
16
+
17
+ private
18
+
19
+ def table_item_and_column_index
20
+ @table_item_and_column_index ||= find_table_item_and_column_index
21
+ end
22
+
23
+ def find_table_item_and_column_index
24
+ {}.tap do |result|
25
+ if respond_to?(:x) && respond_to?(:y)
26
+ result[:table_item] = widget.getItems.detect do |ti|
27
+ result[:column_index] = widget.getColumnCount.times.to_a.detect do |ci|
28
+ ti.getBounds(ci).contains(x, y)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ attr_reader :table_editor, :table_editor_text_proxy
37
+ attr_accessor :column_properties
38
+
39
+ def initialize(underscored_widget_name, parent, args)
40
+ super
41
+ @table_editor = TableEditor.new(swt_widget)
42
+ @table_editor.horizontalAlignment = SWTProxy[:left]
43
+ @table_editor.grabHorizontal = true
44
+ @table_editor.minimumHeight = 20
45
+ end
46
+
47
+ # Performs a search for table items matching block condition
48
+ # If no condition block is passed, returns all table items
49
+ # Returns a Java TableItem array to easily set as selection on org.eclipse.swt.Table if needed
50
+ def search(&condition)
51
+ swt_widget.getItems.select {|item| condition.nil? || condition.call(item)}.to_java(TableItem)
52
+ end
53
+
54
+ # Returns all table items including descendants
55
+ def all_table_items
56
+ search
57
+ end
58
+
59
+ def widget_property_listener_installers
60
+ super.merge({
61
+ Java::OrgEclipseSwtWidgets::Table => {
62
+ selection: lambda do |observer|
63
+ on_widget_selected { |selection_event|
64
+ observer.call(@swt_widget.getSelection)
65
+ }
66
+ end
67
+ },
68
+ })
69
+ end
70
+
71
+ def edit_in_progress?
72
+ !!@edit_in_progress
73
+ end
74
+
75
+ def edit_selected_table_item(column_index, before_write: nil, after_write: nil, after_cancel: nil)
76
+ edit_table_item(swt_widget.getSelection.first, column_index, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
77
+ end
78
+
79
+ def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)
80
+ return if table_item.nil?
81
+ content {
82
+ @table_editor_text_proxy = text {
83
+ focus true
84
+ text table_item.getText(column_index)
85
+ action_taken = false
86
+ cancel = lambda {
87
+ @table_editor_text_proxy.swt_widget.dispose
88
+ @table_editor_text_proxy = nil
89
+ after_cancel&.call
90
+ @edit_in_progress = false
91
+ }
92
+ action = lambda { |event|
93
+ if !action_taken && !@edit_in_progress
94
+ action_taken = true
95
+ @edit_in_progress = true
96
+ new_text = @table_editor_text_proxy.swt_widget.getText
97
+ if new_text == table_item.getText(column_index)
98
+ cancel.call
99
+ else
100
+ before_write&.call
101
+ table_item.setText(column_index, new_text)
102
+ model = table_item.getData
103
+ model.send("#{column_properties[column_index]}=", new_text) # makes table update itself, so must search for selected table item again
104
+ edited_table_item = search { |ti| ti.getData == model }.first
105
+ swt_widget.showItem(edited_table_item)
106
+ @table_editor_text_proxy.swt_widget.dispose
107
+ @table_editor_text_proxy = nil
108
+ after_write&.call(edited_table_item)
109
+ @edit_in_progress = false
110
+ end
111
+ end
112
+ }
113
+ on_focus_lost(&action)
114
+ on_key_pressed { |key_event|
115
+ if key_event.keyCode == swt(:cr)
116
+ action.call(key_event)
117
+ elsif key_event.keyCode == swt(:esc)
118
+ cancel.call
119
+ end
120
+ }
121
+ }
122
+ @table_editor_text_proxy.swt_widget.selectAll
123
+ }
124
+ @table_editor.setEditor(@table_editor_text_proxy.swt_widget, table_item, column_index)
125
+ end
126
+
127
+ def add_listener(underscored_listener_name, &block)
128
+ enhanced_block = lambda do |event|
129
+ event.extend(TableListenerEvent)
130
+ block.call(event)
131
+ end
132
+ super(underscored_listener_name, &enhanced_block)
133
+ end
134
+
135
+ private
136
+
137
+ def property_type_converters
138
+ super.merge({
139
+ selection: lambda do |value|
140
+ if value.is_a?(Array)
141
+ search {|ti| value.include?(ti.getData) }
142
+ else
143
+ search {|ti| ti.getData == value}
144
+ end
145
+ end,
146
+ })
147
+ end
148
+ end
149
+ end
150
+ end
@@ -95,7 +95,7 @@ module Glimmer
95
95
  }
96
96
  @tree_editor_text_proxy.swt_widget.selectAll
97
97
  }
98
- @tree_editor.setEditor(@tree_editor_text_proxy.swt_widget, tree_item);
98
+ @tree_editor.setEditor(@tree_editor_text_proxy.swt_widget, tree_item)
99
99
  end
100
100
 
101
101
  private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-03 00:00:00.000000000 Z
11
+ date: 2020-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +164,10 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: 0.8.1
167
- description: Ruby Desktop Development GUI Library
167
+ description: "Ruby Desktop Development GUI Library (JRuby on SWT). \n\nChanges: \n\
168
+ - `message_box` DSL keyword\n- Table single/multi selection databinding\n- Table\
169
+ \ cell editing databinding\n- Enhance table listener events with table_item and\
170
+ \ column_index methods\n- Fix `Glimmer::SWT::ShellProxy#pack_same_size` for Linux\n"
168
171
  email: andy.am@gmail.com
169
172
  executables:
170
173
  - glimmer
@@ -225,6 +228,7 @@ files:
225
228
  - lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb
226
229
  - lib/glimmer/dsl/swt/menu_bar_expression.rb
227
230
  - lib/glimmer/dsl/swt/menu_expression.rb
231
+ - lib/glimmer/dsl/swt/message_box_expression.rb
228
232
  - lib/glimmer/dsl/swt/observe_expression.rb
229
233
  - lib/glimmer/dsl/swt/property_expression.rb
230
234
  - lib/glimmer/dsl/swt/rgb_expression.rb
@@ -259,10 +263,12 @@ files:
259
263
  - lib/glimmer/swt/layout_data_proxy.rb
260
264
  - lib/glimmer/swt/layout_proxy.rb
261
265
  - lib/glimmer/swt/menu_proxy.rb
266
+ - lib/glimmer/swt/message_box_proxy.rb
262
267
  - lib/glimmer/swt/packages.rb
263
268
  - lib/glimmer/swt/shell_proxy.rb
264
269
  - lib/glimmer/swt/swt_proxy.rb
265
270
  - lib/glimmer/swt/tab_item_proxy.rb
271
+ - lib/glimmer/swt/table_proxy.rb
266
272
  - lib/glimmer/swt/tree_proxy.rb
267
273
  - lib/glimmer/swt/widget_listener_proxy.rb
268
274
  - lib/glimmer/swt/widget_proxy.rb