glimmer 0.5.8 → 0.5.9
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 +4 -4
- data/README.markdown +138 -84
- data/bin/gladiator +6 -0
- data/lib/glimmer.rb +1 -0
- data/lib/glimmer/data_binding/list_selection_binding.rb +1 -1
- data/lib/glimmer/data_binding/widget_binding.rb +33 -33
- data/lib/glimmer/dsl/custom_widget_expression.rb +0 -1
- data/lib/glimmer/dsl/display_expression.rb +2 -0
- data/lib/glimmer/dsl/tree_items_data_binding_expression.rb +9 -10
- data/lib/glimmer/dsl/widget_listener_expression.rb +4 -3
- data/lib/glimmer/launcher.rb +8 -2
- data/lib/glimmer/swt/display_proxy.rb +25 -0
- data/lib/glimmer/swt/layout_proxy.rb +0 -1
- data/lib/glimmer/swt/shell_proxy.rb +17 -0
- data/lib/glimmer/swt/swt_proxy.rb +4 -0
- data/lib/glimmer/swt/widget_proxy.rb +444 -391
- data/lib/glimmer/ui/custom_shell.rb +1 -1
- data/lib/glimmer/ui/custom_widget.rb +38 -19
- data/lib/glimmer/ui/video.rb +0 -1
- data/samples/gladiator.rb +709 -0
- metadata +35 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1c351e3623c60e0ae9e52ce1f33b1579b5a3bb1cfc161c1eb2b6883bfe905b6
|
4
|
+
data.tar.gz: 4bb0c04faf2a1a9c68ac58f2acb386112f3706c7fae34c2e1c7dba9c99783f60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42f75cb443468b0b4f9487b333882c1517803b66ce326c63b28780c9c98e809b27ce6cd2ce9928c61dc9f399c9ac2bd859a4c1910040869963e912893f87ddca
|
7
|
+
data.tar.gz: 5b4bed4b26bc8aed20c996bf21b24bcc26860ea06433a053faf0ad011921fb63f84f963750a5a03e64b089602a27a28b6fcee72a08f09a21a4a5d26ed29b9575
|
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Glimmer 0.5.
|
1
|
+
# Glimmer 0.5.9 Beta (JRuby Desktop UI DSL + Data-Binding)
|
2
2
|
[](https://coveralls.io/github/AndyObtiva/glimmer?branch=master)
|
3
3
|
|
4
4
|
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.
|
@@ -70,7 +70,7 @@ NOTE: Glimmer is in beta mode. Please help make better by adopting for small or
|
|
70
70
|
## Table of Contents
|
71
71
|
|
72
72
|
<!-- TOC START min:1 max:3 link:true asterisk:false update:true -->
|
73
|
-
- [Glimmer 0.5.
|
73
|
+
- [Glimmer 0.5.9 Beta (JRuby Desktop UI DSL + Data-Binding)](#glimmer-058-beta-jruby-desktop-ui-dsl--data-binding)
|
74
74
|
- [Examples](#examples)
|
75
75
|
- [Hello World](#hello-world)
|
76
76
|
- [Tic Tac Toe](#tic-tac-toe)
|
@@ -163,14 +163,14 @@ Please follow these instructions to make the `glimmer` command available on your
|
|
163
163
|
|
164
164
|
Run this command to install directly:
|
165
165
|
```
|
166
|
-
jgem install glimmer -v 0.5.
|
166
|
+
jgem install glimmer -v 0.5.9
|
167
167
|
```
|
168
168
|
|
169
169
|
### Option 2: Bundler
|
170
170
|
|
171
171
|
Add the following to `Gemfile`:
|
172
172
|
```
|
173
|
-
gem 'glimmer', '~> 0.5.
|
173
|
+
gem 'glimmer', '~> 0.5.9'
|
174
174
|
```
|
175
175
|
|
176
176
|
And, then run:
|
@@ -367,84 +367,27 @@ shell {
|
|
367
367
|
}.open
|
368
368
|
```
|
369
369
|
|
370
|
-
####
|
371
|
-
|
372
|
-
Glimmer DSL provides support for SWT Menu and MenuItem widgets.
|
373
|
-
|
374
|
-
There are 2 main types of menus in SWT:
|
375
|
-
- Menu Bar (shows up on top)
|
376
|
-
- Pop Up Menu (shows up when right-clicking a widget)
|
377
|
-
|
378
|
-
Underneath both types, there can be a 3rd menu type called Drop Down.
|
379
|
-
|
380
|
-
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.
|
370
|
+
#### Display
|
381
371
|
|
382
|
-
|
383
|
-
|
384
|
-
|
372
|
+
SWT Display is a singleton in Glimmer. It is used in SWT to represent your display device, allowing you to manage UI globally
|
373
|
+
and access available monitors.
|
374
|
+
It is automatically instantiated upon first instantiation of a `shell` widget.
|
375
|
+
Alternatively, for advanced use cases, it can be created explicitly with Glimmer `display` keyword. When a `shell` is later declared, it
|
376
|
+
automatically uses the display created earlier without having to explicitly hook it.
|
385
377
|
|
386
378
|
```ruby
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
menu_item {
|
392
|
-
text "E&xit"
|
393
|
-
}
|
394
|
-
menu_item(0) {
|
395
|
-
text "&New"
|
396
|
-
}
|
397
|
-
menu(1) {
|
398
|
-
text "&Options"
|
399
|
-
menu_item(:radio) {
|
400
|
-
text "Option 1"
|
401
|
-
}
|
402
|
-
menu_item(:separator)
|
403
|
-
menu_item(:check) {
|
404
|
-
text "Option 3"
|
405
|
-
}
|
406
|
-
}
|
407
|
-
}
|
408
|
-
menu {
|
409
|
-
text "&History"
|
410
|
-
menu {
|
411
|
-
text "&Recent"
|
412
|
-
menu_item {
|
413
|
-
text "File 1"
|
414
|
-
}
|
415
|
-
menu_item {
|
416
|
-
text "File 2"
|
417
|
-
}
|
418
|
-
}
|
419
|
-
}
|
420
|
-
}
|
421
|
-
}.open
|
422
|
-
```
|
423
|
-
|
424
|
-
Example [Pop Up Menu] (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
|
425
|
-
|
426
|
-
```ruby
|
427
|
-
shell {
|
428
|
-
label {
|
429
|
-
text 'Right-Click Me'
|
430
|
-
menu {
|
431
|
-
menu {
|
432
|
-
text '&History'
|
433
|
-
menu {
|
434
|
-
text "&Recent"
|
435
|
-
menu_item {
|
436
|
-
text "File 1"
|
437
|
-
}
|
438
|
-
menu_item {
|
439
|
-
text "File 2"
|
440
|
-
}
|
441
|
-
}
|
442
|
-
}
|
443
|
-
}
|
379
|
+
@display = display {
|
380
|
+
cursor_location 300, 300
|
381
|
+
on_event_keydown {
|
382
|
+
# ...
|
444
383
|
}
|
445
|
-
|
384
|
+
# ...
|
385
|
+
}
|
386
|
+
@shell = shell { # uses display created above
|
387
|
+
}
|
446
388
|
```
|
447
|
-
|
389
|
+
The benefit of instantiating an SWT Display explicitly is to set [Properties](#widget-properties) or [Observers](#observer).
|
390
|
+
Although SWT Display is not technically a widget, it has similar APIs in SWT and similar DSL support in Glimmer.
|
448
391
|
|
449
392
|
#### SWT Proxies
|
450
393
|
|
@@ -461,7 +404,6 @@ Glimmer follows Proxy Design Pattern by having Ruby proxy wrappers for all SWT o
|
|
461
404
|
|
462
405
|
These proxy objects have an API and provide some convenience methods, some of which are mentioned below.
|
463
406
|
|
464
|
-
|
465
407
|
##### `#content { ... }`
|
466
408
|
|
467
409
|
Glimmer allows re-opening any widget and adding properties or extra content after it has been constructed already by using the `#content` method.
|
@@ -521,6 +463,86 @@ Shell widget proxy has extra methods specific to SWT Shell:
|
|
521
463
|
- `#visible?`: Returns whether a shell is visible
|
522
464
|
- `#opened_before?`: Returns whether a shell has been opened at least once before (additionally implying the SWT Event Loop has been started already)
|
523
465
|
- `#visible=`: Setting to true opens/shows shell. Setting to false hides the shell.
|
466
|
+
- `#pack`: Packs contained widgets using SWT's `Shell#pack` method
|
467
|
+
- `#pack_same_size`: Packs contained widgets without changing shell's size when widget sizes change
|
468
|
+
|
469
|
+
#### Menus
|
470
|
+
|
471
|
+
Glimmer DSL provides support for SWT Menu and MenuItem widgets.
|
472
|
+
|
473
|
+
There are 2 main types of menus in SWT:
|
474
|
+
- Menu Bar (shows up on top)
|
475
|
+
- Pop Up Menu (shows up when right-clicking a widget)
|
476
|
+
|
477
|
+
Underneath both types, there can be a 3rd menu type called Drop Down.
|
478
|
+
|
479
|
+
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.
|
480
|
+
|
481
|
+
The ampersand symbol indicates the keyboard shortcut key for the menu item (e.g. '&Help' can be triggered on Windows by hitting ALT+H)
|
482
|
+
|
483
|
+
Example [Menu Bar] (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
|
484
|
+
|
485
|
+
```ruby
|
486
|
+
shell {
|
487
|
+
menu_bar {
|
488
|
+
menu {
|
489
|
+
text "&File"
|
490
|
+
menu_item {
|
491
|
+
text "E&xit"
|
492
|
+
}
|
493
|
+
menu_item(0) {
|
494
|
+
text "&New"
|
495
|
+
}
|
496
|
+
menu(1) {
|
497
|
+
text "&Options"
|
498
|
+
menu_item(:radio) {
|
499
|
+
text "Option 1"
|
500
|
+
}
|
501
|
+
menu_item(:separator)
|
502
|
+
menu_item(:check) {
|
503
|
+
text "Option 3"
|
504
|
+
}
|
505
|
+
}
|
506
|
+
}
|
507
|
+
menu {
|
508
|
+
text "&History"
|
509
|
+
menu {
|
510
|
+
text "&Recent"
|
511
|
+
menu_item {
|
512
|
+
text "File 1"
|
513
|
+
}
|
514
|
+
menu_item {
|
515
|
+
text "File 2"
|
516
|
+
}
|
517
|
+
}
|
518
|
+
}
|
519
|
+
}
|
520
|
+
}.open
|
521
|
+
```
|
522
|
+
|
523
|
+
Example [Pop Up Menu] (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
|
524
|
+
|
525
|
+
```ruby
|
526
|
+
shell {
|
527
|
+
label {
|
528
|
+
text 'Right-Click Me'
|
529
|
+
menu {
|
530
|
+
menu {
|
531
|
+
text '&History'
|
532
|
+
menu {
|
533
|
+
text "&Recent"
|
534
|
+
menu_item {
|
535
|
+
text "File 1"
|
536
|
+
}
|
537
|
+
menu_item {
|
538
|
+
text "File 2"
|
539
|
+
}
|
540
|
+
}
|
541
|
+
}
|
542
|
+
}
|
543
|
+
}
|
544
|
+
}.open
|
545
|
+
```
|
524
546
|
|
525
547
|
### Widget Styles
|
526
548
|
|
@@ -1064,7 +1086,9 @@ Glimmer supports observing widgets with two main types of events:
|
|
1064
1086
|
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`).
|
1065
1087
|
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)
|
1066
1088
|
|
1067
|
-
Additionally,
|
1089
|
+
Additionally, there are two more types of events:
|
1090
|
+
- SWT `display` supports global listeners called filters that run on any widget. They are hooked via `on_event_{swt-event-constant}`
|
1091
|
+
- the `shell` widget supports Mac application menu item observers (`on_about` and `on_preferences`), which you can read about under [Miscellaneous](#miscellaneous).
|
1068
1092
|
|
1069
1093
|
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.
|
1070
1094
|
|
@@ -1651,21 +1675,51 @@ shell {
|
|
1651
1675
|
|
1652
1676
|
Check the [samples](samples) directory for examples on how to write Glimmer applications. To run a sample, make sure to install the `glimmer` gem first and then use the `glimmer` command to run it (alternatively, you may clone the repo, follow [CONTRIBUTING.md](CONTRIBUTING.md) instructions, and run samples locally with development glimmer command: `bin/glimmer`).
|
1653
1677
|
|
1654
|
-
|
1678
|
+
If you cloned the project and followed [CONTRIBUTING.md](CONTRIBUTING.md) instructions, you may run all samples at once via `samples/launch` command:
|
1655
1679
|
|
1656
1680
|
```
|
1681
|
+
samples/launch
|
1682
|
+
```
|
1683
|
+
|
1684
|
+
### Hello Samples
|
1685
|
+
|
1686
|
+
For "Hello, World!" type samples, check the following:
|
1687
|
+
|
1688
|
+
```
|
1689
|
+
glimmer samples/hello_world.rb
|
1690
|
+
glimmer samples/hello_browser.rb
|
1657
1691
|
glimmer samples/hello_tab.rb
|
1658
1692
|
glimmer samples/hello_combo.rb
|
1659
1693
|
glimmer samples/hello_list_single_selection.rb
|
1660
1694
|
glimmer samples/hello_list_multi_selection.rb
|
1661
|
-
glimmer samples/
|
1695
|
+
glimmer samples/hellocomputed/hello_computed.rb
|
1696
|
+
glimmer samples/video/hello_video.rb
|
1697
|
+
glimmer samples/video/hello_looped_video_with_black_background.rb
|
1698
|
+
glimmer samples/video/hello_video_observers.rb
|
1699
|
+
```
|
1700
|
+
|
1701
|
+
### Elaborate Samples
|
1702
|
+
|
1703
|
+
For more elaborate samples, check the following:
|
1704
|
+
|
1662
1705
|
```
|
1706
|
+
glimmer samples/login.rb # demonstrates basic data-binding
|
1707
|
+
glimmer samples/contactmanager/contact_manager.rb # demonstrates table data-binding
|
1708
|
+
glimmer samples/tictactoe/tic_tac_toe.rb # demonstrates a full MVC application
|
1709
|
+
glimmer samples/gladiator.rb # demonstrates a text editor with tree/list data-binding
|
1710
|
+
```
|
1711
|
+
|
1712
|
+

|
1663
1713
|
|
1664
|
-
|
1714
|
+
Gladiator (short for Glimmer Editor) is an on-going sample project with continuous development.
|
1715
|
+
It is also used as the main text editor for coding Glimmer.
|
1716
|
+
As such, it has been made available in [Glimmer's gem](https://rubygems.org/gems/glimmer) via the `gladiator` command should others find useful too.
|
1717
|
+
If you cloned this project and followed [CONTRIBUTING.md](CONTRIBUTING.md) instructions, you may invoke via `bin/gladiator` instead.
|
1665
1718
|
|
1666
|
-
|
1719
|
+
## In Production
|
1667
1720
|
|
1668
|
-
|
1721
|
+
The following production apps have been built with Glimmer:
|
1722
|
+
- [Math Bowling](https://github.com/AndyObtiva/MathBowling): an educational math game for elementary level kids
|
1669
1723
|
|
1670
1724
|
## SWT Reference
|
1671
1725
|
|
data/bin/gladiator
ADDED
data/lib/glimmer.rb
CHANGED
@@ -44,7 +44,7 @@ module Glimmer
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def evaluate_property
|
47
|
-
selection_array = @widget_proxy.swt_widget.send('selection').to_a
|
47
|
+
selection_array = @widget_proxy.swt_widget.send('selection').to_a #TODO refactor send('selection') into proper method invocation
|
48
48
|
PROPERTY_EVALUATORS[@property_type].call(selection_array)
|
49
49
|
end
|
50
50
|
end
|
@@ -1,33 +1,33 @@
|
|
1
|
-
require 'glimmer'
|
2
|
-
require_relative 'observable'
|
3
|
-
require_relative 'observer'
|
4
|
-
|
5
|
-
module Glimmer
|
6
|
-
module DataBinding
|
7
|
-
class WidgetBinding
|
8
|
-
include Glimmer
|
9
|
-
include Observable
|
10
|
-
include Observer
|
11
|
-
|
12
|
-
attr_reader :widget, :property
|
13
|
-
def initialize(model, property, translator = nil)
|
14
|
-
@widget = model
|
15
|
-
@property = property
|
16
|
-
@translator = translator || proc {|value| value}
|
17
|
-
|
18
|
-
if @widget.respond_to?(:dispose)
|
19
|
-
@widget.on_widget_disposed do |dispose_event|
|
20
|
-
unregister_all_observables
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
def call(value)
|
25
|
-
converted_value = translated_value = @translator.call(value)
|
26
|
-
@widget.set_attribute(@property, converted_value) unless evaluate_property == converted_value
|
27
|
-
end
|
28
|
-
def evaluate_property
|
29
|
-
@widget.get_attribute(@property)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
1
|
+
require 'glimmer'
|
2
|
+
require_relative 'observable'
|
3
|
+
require_relative 'observer'
|
4
|
+
|
5
|
+
module Glimmer
|
6
|
+
module DataBinding
|
7
|
+
class WidgetBinding
|
8
|
+
include Glimmer
|
9
|
+
include Observable
|
10
|
+
include Observer
|
11
|
+
|
12
|
+
attr_reader :widget, :property
|
13
|
+
def initialize(model, property, translator = nil)
|
14
|
+
@widget = model
|
15
|
+
@property = property
|
16
|
+
@translator = translator || proc {|value| value}
|
17
|
+
|
18
|
+
if @widget.respond_to?(:dispose)
|
19
|
+
@widget.on_widget_disposed do |dispose_event|
|
20
|
+
unregister_all_observables
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
def call(value)
|
25
|
+
converted_value = translated_value = @translator.call(value)
|
26
|
+
@widget.set_attribute(@property, converted_value) unless evaluate_property == converted_value
|
27
|
+
end
|
28
|
+
def evaluate_property
|
29
|
+
@widget.get_attribute(@property)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/dsl/parent_expression'
|
2
3
|
require 'glimmer/swt/display_proxy'
|
3
4
|
|
4
5
|
module Glimmer
|
5
6
|
module DSL
|
6
7
|
class DisplayExpression < StaticExpression
|
8
|
+
include ParentExpression
|
7
9
|
def interpret(parent, keyword, *args, &block)
|
8
10
|
SWT::DisplayProxy.instance(*args)
|
9
11
|
end
|
@@ -8,16 +8,15 @@ module Glimmer
|
|
8
8
|
include_package 'org.eclipse.swt.widgets'
|
9
9
|
|
10
10
|
def can_interpret?(parent, keyword, *args, &block)
|
11
|
-
keyword == "items" and
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
args[1].first.is_a?(Hash)
|
11
|
+
initial_condition = ((keyword == "items") and block.nil? and widget?(parent) and parent.swt_widget.is_a?(Tree))
|
12
|
+
return false unless initial_condition
|
13
|
+
raise Glimmer::Error, 'Tree items args must be 2' unless args.size == 2
|
14
|
+
raise Glimmer::Error, 'Tree items first arg must be a bind expression' unless args[0].is_a?(DataBinding::ModelBinding)
|
15
|
+
raise Glimmer::Error, 'Tree items data-binding initial value must not be an array yet a single item representing tree root' unless !args[0].evaluate_property.is_a?(Array)
|
16
|
+
raise Glimmer::Error, 'Tree items second arg must be an array' unless args[1].is_a?(Array)
|
17
|
+
raise Glimmer::Error, 'Tree items second arg must not be empty' unless !args[1].empty?
|
18
|
+
raise Glimmer::Error, 'Tree items second arg array elements must be of type hash' unless args[1].first.is_a?(Hash)
|
19
|
+
true
|
21
20
|
end
|
22
21
|
|
23
22
|
def interpret(parent, keyword, *args, &block)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'glimmer/dsl/expression'
|
2
|
+
require 'glimmer/swt/display_proxy'
|
2
3
|
|
3
4
|
module Glimmer
|
4
5
|
module DSL
|
@@ -8,9 +9,9 @@ module Glimmer
|
|
8
9
|
def can_interpret?(parent, keyword, *args, &block)
|
9
10
|
Glimmer.logger&.debug "keyword starts with on_: #{keyword.start_with?('on_')}"
|
10
11
|
return false unless keyword.start_with?('on_')
|
11
|
-
|
12
|
-
Glimmer.logger&.debug "parent is a widget: #{
|
13
|
-
return false unless
|
12
|
+
widget_or_display_parentage = widget?(parent) || parent.is_a?(SWT::DisplayProxy)
|
13
|
+
Glimmer.logger&.debug "parent is a widget or display: #{widget_or_display_parentage}"
|
14
|
+
return false unless widget_or_display_parentage
|
14
15
|
Glimmer.logger&.debug "block exists?: #{!block.nil?}"
|
15
16
|
raise Glimmer::Error, "Listener is missing block for keyword: #{keyword}" unless block_given?
|
16
17
|
Glimmer.logger&.debug "args are empty?: #{args.empty?}"
|