README.markdown in glimmer-0.5.7 vs README.markdown in glimmer-0.5.8
- old
+ new
@@ -1,6 +1,6 @@
-# Glimmer 0.5.7 Beta (JRuby Desktop UI DSL + Data-Binding)
+# Glimmer 0.5.8 Beta (JRuby Desktop UI DSL + Data-Binding)
[![Coverage Status](https://coveralls.io/repos/github/AndyObtiva/glimmer/badge.svg?branch=master)](https://coveralls.io/github/AndyObtiva/glimmer?branch=master)
Glimmer is a native-UI 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 platform-native Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support to greatly facilitate synchronizing the UI with domain models. As a result, that achieves true decoupling of object oriented components, enabling developers to solve business problems without worrying about UI concerns, or alternatively drive development UI-first, and then write clean business components test-first afterwards.
## Examples
@@ -65,10 +65,62 @@
![Tic Tac Toe](images/glimmer-tic-tac-toe.png)
NOTE: Glimmer is in beta mode. Please help make better by adopting for small or low risk projects and providing feedback.
+## Table of Contents
+
+<!-- TOC START min:1 max:3 link:true asterisk:false update:true -->
+- [Glimmer 0.5.8 Beta (JRuby Desktop UI DSL + Data-Binding)](#glimmer-058-beta-jruby-desktop-ui-dsl--data-binding)
+ - [Examples](#examples)
+ - [Hello World](#hello-world)
+ - [Tic Tac Toe](#tic-tac-toe)
+ - [Table of Contents](#table-of-contents)
+ - [Background](#background)
+ - [Platform Support](#platform-support)
+ - [Pre-requisites](#pre-requisites)
+ - [Setup](#setup)
+ - [Option 1: Direct Install](#option-1-direct-install)
+ - [Option 2: Bundler](#option-2-bundler)
+ - [Glimmer Command](#glimmer-command)
+ - [Basic Usage](#basic-usage)
+ - [Advanced Usage](#advanced-usage)
+ - [Girb (Glimmer irb) Command](#girb-glimmer-irb-command)
+ - [Glimmer DSL Syntax](#glimmer-dsl-syntax)
+ - [Widgets](#widgets)
+ - [Widget Styles](#widget-styles)
+ - [Widget Properties](#widget-properties)
+ - [Layouts](#layouts)
+ - [Layout Data](#layout-data)
+ - [Data-Binding](#data-binding)
+ - [Observer](#observer)
+ - [Custom Widgets](#custom-widgets)
+ - [Custom Shells](#custom-shells)
+ - [Miscellaneous](#miscellaneous)
+ - [Glimmer Style Guide](#glimmer-style-guide)
+ - [Samples](#samples)
+ - [SWT Reference](#swt-reference)
+ - [SWT Packages](#swt-packages)
+ - [Logging](#logging)
+ - [Raw JRuby Command](#raw-jruby-command)
+ - [Mac Support](#mac-support)
+ - [Packaging & Distribution](#packaging--distribution)
+ - [Defaults](#defaults)
+ - [javapackager Extra Arguments](#javapackager-extra-arguments)
+ - [Mac Application Distribution](#mac-application-distribution)
+ - [Self Signed Certificate](#self-signed-certificate)
+ - [Gotchas](#gotchas)
+ - [Resources](#resources)
+ - [Feature Suggestions](#feature-suggestions)
+ - [Change Log](#change-log)
+ - [Contributing](#contributing)
+ - [Contributors](#contributors)
+ - [License](#license)
+<!-- TOC END -->
+
+
+
## Background
Ruby is a dynamically-typed object-oriented language, which provides great productivity gains due to its powerful expressive syntax and dynamic nature. While it is proven by the Ruby on Rails framework for web development, it currently lacks a robust platform-independent framework for building desktop applications. Given that Java libraries can now be utilized in Ruby code through JRuby, Eclipse technologies, such as SWT, JFace, and RCP can help fill the gap of desktop application development with Ruby.
## Platform Support
@@ -109,18 +161,18 @@
### Option 1: Direct Install
Run this command to install directly:
```
-jgem install glimmer -v 0.5.7
+jgem install glimmer -v 0.5.8
```
### Option 2: Bundler
Add the following to `Gemfile`:
```
-gem 'glimmer', '~> 0.5.7'
+gem 'glimmer', '~> 0.5.8'
```
And, then run:
```
jruby -S bundle install
@@ -184,10 +236,12 @@
```
bin/girb
```
+Watch out for hands-on examples in this README indicated by "you may copy/paste in [`girb`](#girb-glimmer-irb-command)"
+
## Glimmer DSL Syntax
Glimmer DSL syntax consists of static keywords and dynamic keywords to build and bind user-interface objects.
Static keywords are pre-identified keywords in the Glimmer DSL, such as `shell`, `rgb`, and `bind`.
@@ -228,11 +282,11 @@
- `tree` instantiates `org.eclipse.swt.widgets.Tree`
- `combo` instantiates `org.eclipse.swt.widgets.Combo`
- `list` instantiates `org.eclipse.swt.widgets.List`
Every **widget** is sufficiently declared by name, but may optionally be accompanied with:
-- SWT **style** ***argument*** wrapped by parenthesis according to [Glimmer coding style](#glimmer-coding-style) (see [next section](#widget-styles) for details).
+- SWT **style** ***argument*** wrapped by parenthesis according to [Glimmer Style Guide](#glimmer-coding-style) (see [next section](#widget-styles) for details).
- Ruby block containing **properties** (widget attributes) and **content** (nested widgets)
For example, if we were to revisit `samples/hello_world.rb` above (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
```ruby
@@ -255,16 +309,26 @@
text "Hello, World!" # text property of label
}
# ...
```
-The first line declares a **property** called `text`, which sets the title of the shell (window) to `"Glimmer"`. **Properties** always have ***arguments*** (not wrapped by parenthesis according to [Glimmer coding style](#glimmer-coding-style)), such as the text `"Glimmer"` in this case, and do **NOT** have a ***block*** (this distinguishes them from **widget** declarations).
+The first line declares a **property** called `text`, which sets the title of the shell (window) to `"Glimmer"`. **Properties** always have ***arguments*** (not wrapped by parenthesis according to [Glimmer Style Guide](#glimmer-coding-style)), such as the text `"Glimmer"` in this case, and do **NOT** have a ***block*** (this distinguishes them from **widget** declarations).
The second line declares the `label` **widget**, which is followed by a Ruby **content** ***block*** that contains its `text` **property** with value `"Hello, World!"`
-Note that The `shell` widget is always the outermost widget containing all others in a Glimmer desktop windowed application.
+The **widget** ***block*** may optionally receive an argument representing the widget proxy object that the block content is for. This is useful in rare cases when the content code needs to refer to parent widget during declaration. You may leave that argument out most of the time and only add when absolutely needed.
+Example:
+
+```ruby
+shell {|shell_proxy|
+ #...
+}
+```
+
+Remember that The `shell` widget is always the outermost widget containing all others in a Glimmer desktop windowed application.
+
After it is declared, a `shell` must be opened with the `#open` method, which can be called on the block directly as in the example above, or by capturing `shell` in a `@shell` variable (shown in example below), and calling `#open` on it independently (recommended in actual apps)
```ruby
@shell = shell {
# properties and content
@@ -313,10 +377,12 @@
Underneath both types, there can be a 3rd menu type called Drop Down.
Glimmer provides special support for Drop Down menus as it automatically instantiates associated Cascade menu items and wires together with proper parenting, swt styles, and calling setMenu.
+The ampersand symbol indicates the keyboard shortcut key for the menu item (e.g. '&Help' can be triggered on Windows by hitting ALT+H)
+
Example [Menu Bar] (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
```ruby
shell {
menu_bar {
@@ -460,11 +526,11 @@
SWT widgets receive `SWT` styles in their constructor as per this guide:
https://wiki.eclipse.org/SWT_Widget_Style_Bits
-Glimmer DSL facilitates that by passing symbols representing `SWT` constants as widget method arguments (i.e. inside widget `()` parentheses according to [Glimmer coding style](#glimmer-coding-style). See example below) in lower case version (e.g. `SWT::MULTI` becomes `:multi`).
+Glimmer DSL facilitates that by passing symbols representing `SWT` constants as widget method arguments (i.e. inside widget `()` parentheses according to [Glimmer Style Guide](#glimmer-coding-style). See example below) in lower case version (e.g. `SWT::MULTI` becomes `:multi`).
These styles customize widget look, feel, and behavior.
Example:
@@ -525,27 +591,10 @@
shell(:no_resize) {
# ...
}
```
-#### Shell extra attributes
-
-Shell widget can receive a hash of extra attributes as the last argument (or alone):
-- app_name: name to show for app (especially on the Mac)
-- app_version: version to have OS recognize app by
-
-Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
-
-```ruby
-shell(:no_resize, app_name: 'Glimmer Demo', app_version: '1.0') {
- text "Glimmer"
- label {
- text "Hello, World!"
- }
-}.open
-```
-
### Widget Properties
Widget properties such as text value, enablement, visibility, and layout details are set within the widget block using methods matching SWT widget property names in lower snakecase. You may refer to SWT widget guide for details on available widget properties:
https://help.eclipse.org/2019-12/topic/org.eclipse.platform.doc.isv/guide/swt_widgets_controls.htm?cp=2_0_7_0_0
@@ -1009,14 +1058,16 @@
Glimmer comes with `Observer` module, which is used internally for data-binding, but can also be used externally for custom use of the Observer Pattern. It is hidden when observing widgets, and used explicitly when observing models.
#### Observing Widgets
-Glimmer supports observing widgets with two types of syntax:
-1. `on_{swt-listener-method-name}`: where {swt-listener-method-name} is replaced with the lowercase underscored method name on an SWT listener class (e.g. `on_verify_text` for `org.eclipse.swt.events.VerifyListener#verifyText`).
+Glimmer supports observing widgets with two main types of events:
+1. `on_{swt-listener-method-name}`: where {swt-listener-method-name} is replaced with the lowercase underscored event method name on an SWT listener class (e.g. `on_verify_text` for `org.eclipse.swt.events.VerifyListener#verifyText`).
2. `on_event_{swt-event-constant}`: where {swt-event-constant} is replaced with an `org.eclipse.swt.SWT` event constant (e.g. `on_event_show` for `SWT.Show` to observe when widget becomes visible)
+Additionally, the `shell` widget supports a 3rd type on the Mac, application menu item observers (`on_about` and `on_preferences`), which you can read about under [Miscellaneous](#miscellaneous).
+
Number 1 is more commonly used in SWT applications, so make it your starting point. Number 2 covers events not found in number 1, so look into it if you don't find an SWT listener you need in number 1.
**Regarding number 1**, to figure out what the available events for an SWT widget are, check out all of its `add***Listener` API methods, and then open the listener class argument to check its "event methods".
For example, if you look at the `Button` SWT API:
@@ -1388,10 +1439,81 @@
}.open
```
### Miscellaneous
+#### Application Menu Items (About/Preferences)
+
+Mac applications always have About and Preferences menu items. Glimmer provides widget observer hooks for them on the `shell` widget:
+- `on_about`: executes code when user selects App Name -> About
+- `on_preferences`: executes code when user selects App Name -> Preferences or hits 'CMD+,' on the Mac
+
+Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
+
+```ruby
+shell { |shell_proxy|
+ text 'Application Menu Items'
+ fill_layout {
+ margin_width 15
+ margin_height 15
+ }
+ label {
+ text 'Application Menu Items'
+ font height: 30
+ }
+ on_about {
+ message_box = MessageBox.new(shell_proxy.swt_widget)
+ message_box.setText("About")
+ message_box.setMessage("About Application")
+ message_box.open
+ }
+ on_preferences {
+ preferences_dialog = shell(:dialog_trim, :application_modal) {
+ text 'Preferences'
+ row_layout {
+ type :vertical
+ margin_left 15
+ margin_top 15
+ margin_right 15
+ margin_bottom 15
+ }
+ label {
+ text 'Check one of these options:'
+ }
+ button(:radio) {
+ text 'Option 1'
+ }
+ button(:radio) {
+ text 'Option 2'
+ }
+ }
+ preferences_dialog.open
+ }
+}.open
+```
+
+#### App Name and Version
+
+Application name (shows up on the Mac in top menu bar) and version may be specified upon [packaging](#packaging--distribution) by specifying "-Bmac.CFBundleName" and "-Bmac.CFBundleVersion" options.
+
+Still, if you would like proper application name to show up on the Mac top menu bar during development, you may do so by invoking the SWT Display.setAppName method before any Display object has been instantiated (i.e. before any Glimmer widget like shell has been declared).
+
+Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
+
+```ruby
+Display.setAppName('Glimmer Demo')
+
+shell(:no_resize) {
+ text "Glimmer"
+ label {
+ text "Hello, World!"
+ }
+}.open
+```
+
+Also, you may invoke `Display.setAppVersion('1.0.0')` if needed for OS app version identification reasons during development, replacing `'1.0.0'` with your application version.
+
#### Video Widget
![Video Widget](images/glimmer-video-widget.png)
Glimmer comes with a video widget not in SWT. It comes with very basic video functionality at the moment, such as autoplay by default, displaying controls, looping, and setting background.
@@ -1508,11 +1630,11 @@
}
}
}.open
```
-## Glimmer Coding Style
+## Glimmer Style Guide
- Widgets are declared with underscored lowercase versions of their SWT names minus the SWT package name.
- Widget declarations may optionally have arguments and be followed by a block (to contain properties and content)
- Widget blocks are always declared with curly braces
- Widget arguments are always wrapped inside parentheses
@@ -1654,11 +1776,11 @@
Example:
```
jruby -J-XstartOnFirstThread -J-classpath "path_to/swt.jar" -r glimmer -S application.rb
```
-## Packaging
+## Packaging & Distribution
Glimmer apps may be packaged and distributed on the Mac, Windows, and Linux via these tools:
- Warbler (https://github.com/jruby/warbler): Enables bundling a Glimmer app into a JAR file
- javapackager (https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javapackager.html): Enables packaging a JAR file as a DMG file on Mac, EXE on Windows, and multiple Linux supported formats on Linux.
@@ -1679,27 +1801,37 @@
rake glimmer:package
```
This will generate a JAR file under `./dist` directory, which is then used to generate a DMG file (and pkg/app) under `./packages/bundles`. Both will match your application local directory name (e.g. `MathBowling.jar` and `MathBowling-1.0.dmg` for `~/code/MathBowling`)
-By default, the package only includes these directories: app, config, db, lib, script, bin, images, sounds, videos
+### Defaults
+Glimmer employs smart defaults in packaging.
+
+The package application name (shows up in top menu bar on the Mac) will be a human form of the app root directory name (e.g. "Math Bowling" for "MathBowling" or "math_bowling" app root directory name). However, application name and version may be specified explicitly via "-Bmac.CFBundleName" and "-Bmac.CFBundleVersion" options.
+
+Also, the package will only include these directories: app, config, db, lib, script, bin, images, sounds, videos
+
After running once, you will find a `config/warble.rb` file. It has the JAR packaging configuration. You may adjust included directories in it if needed, and then rerun `rake glimmer:package` and it will pick up your custom configuration. Alternatively, if you'd like to customize the included directories to begin with, don't run `rake glimmer:package` right away. Run this command first:
```
rake glimmer:package:config
```
This will generate `config/warble.rb`, which you may configure and then run `rake glimmer:package` afterwards.
-In any case, in order to pass extra options to configure Mac package and sign your Mac app to distribute on the App Store, you can read more advanced instructions for `javapackager` here:
+### javapackager Extra Arguments
+
+In order to explicitly configure javapackager, Mac package attributes, or sign your Mac app to distribute on the App Store, you can follow more advanced instructions for `javapackager` here:
- https://docs.oracle.com/javase/9/tools/javapackager.htm#JSWOR719
- https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javapackager.html
- https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/self-contained-packaging.html#BCGICFDB
- https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/self-contained-packaging.html
-Glimmer rake task allows passing extra options to javapackager via `Glimmer::Packager.javapackager_extra_args` in your application Rakefile or environment variable `JAVAPACKAGER_EXTRA_ARGS`
+The Glimmer rake task allows passing extra options to javapackager via:
+- `Glimmer::Packager.javapackager_extra_args="..."` in your application Rakefile
+- Environment variable: `JAVAPACKAGER_EXTRA_ARGS`
Example (Rakefile):
```ruby
Glimmer::Package.javapackager_extra_args = '-srcfiles "LICENSE.txt" -BlicenseFile="LICENSE.txt" -BlicenseType="MIT" -Bmac.CFBundleVersion="1.0.0" -Bmac.category="arithmetic" -Bmac.signing-key-developer-id-app="Andy Maleh"'
@@ -1714,9 +1846,27 @@
That overrides the default application display name.
### Mac Application Distribution
Recent macOS versions (starting with Catalina) have very stringent security requirements requiring all applications to be signed before running (unless the user goes to System Preferences -> Privacy -> General tab and clicks "Open Anyway" after failing to open application the first time they run it). So, to release a desktop application on the Mac, it is recommended to enroll in the [Apple Developer Program](https://developer.apple.com/programs/) to distribute on the [Mac App Store](https://developer.apple.com/distribute/) or otherwise request [app notarization from Apple](https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution) to distribute independently.
+
+Afterwards, you may add developer-id/signing-key arguments to `javapackager` via `Glimmer::Package.javapackager_extra_args` or `JAVAPACKAGER_EXTRA_ARGS` according to this webpage: https://docs.oracle.com/javase/9/tools/javapackager.htm#JSWOR719
+
+DMG signing key argument:
+```
+-Bmac.signing-key-developer-id-app="..."
+```
+
+PKG signing key argument:
+```
+-Bmac.signing-key-developer-id-installer="..."
+```
+
+Mac App Store signing key arguments:
+```
+-Bmac.signing-key-app="..."
+-Bmac.signing-key-pkg="..."
+```
### Self Signed Certificate
You may still release a signed DMG file without enrolling into the Apple Developer Program with the caveat that users will always fail in opening the app the first time, and have to go to System Preferences -> Privacy -> General tab to "Open Anyway".