glimmer 0.5.8 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Coverage Status](https://coveralls.io/repos/github/AndyObtiva/glimmer/badge.svg?branch=master)](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
|
+
![Gladiator](images/glimmer-gladiator.png)
|
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?}"
|