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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d35080737c8d31d9ede07328113372b4a79100d5ce2269f027e389923fbf93b5
4
- data.tar.gz: c3d8e4852e4f36cb3de1adcb2552d4562c6460e68f49c33598de5c2e36c1e486
3
+ metadata.gz: d1c351e3623c60e0ae9e52ce1f33b1579b5a3bb1cfc161c1eb2b6883bfe905b6
4
+ data.tar.gz: 4bb0c04faf2a1a9c68ac58f2acb386112f3706c7fae34c2e1c7dba9c99783f60
5
5
  SHA512:
6
- metadata.gz: 7a46acf87df92892d34477af6a0e69b8ec0fe3bfdbee4c45dd94f08a0eb6098724e785d2f2109c73663c278f7a1a5141d0b45ff26f5bfa6fd07f99653d1fc419
7
- data.tar.gz: af7430e47c5d5875bf1314bbb77055be6927baffaf4435ee25241cda4955bb1bf9c5dab29d7c07a5dde158c09ad39c2bb55b46dba9fcdbe7bd86f3c4c293cf79
6
+ metadata.gz: 42f75cb443468b0b4f9487b333882c1517803b66ce326c63b28780c9c98e809b27ce6cd2ce9928c61dc9f399c9ac2bd859a4c1910040869963e912893f87ddca
7
+ data.tar.gz: 5b4bed4b26bc8aed20c996bf21b24bcc26860ea06433a053faf0ad011921fb63f84f963750a5a03e64b089602a27a28b6fcee72a08f09a21a4a5d26ed29b9575
@@ -1,4 +1,4 @@
1
- # Glimmer 0.5.8 Beta (JRuby Desktop UI DSL + Data-Binding)
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.8 Beta (JRuby Desktop UI DSL + Data-Binding)](#glimmer-058-beta-jruby-desktop-ui-dsl--data-binding)
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.8
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.8'
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
- #### Menus
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
- The ampersand symbol indicates the keyboard shortcut key for the menu item (e.g. '&Help' can be triggered on Windows by hitting ALT+H)
383
-
384
- Example [Menu Bar] (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
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
- shell {
388
- menu_bar {
389
- menu {
390
- text "&File"
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
- }.open
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, 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).
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
- Examples:
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/contactmanager/contact_manager.rb
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
- The last example (`contact_manager.rb`) is a good sample about how to build tables with Glimmer including data-binding, filtering, and sorting. It even comes with specs in `spec/samples/contactmanager/contact_manager_presenter_spec.rb` to demonstrate how Glimmer facilitates TDD (test-driven development) with the Model View Presenter pattern (a variation on MVC) by separating testable presentation logic from the view layer with data-binding.
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
- For a more elaborate project built with Glimmer, check out this educational game:
1719
+ ## In Production
1667
1720
 
1668
- [Math Bowling](https://github.com/AndyObtiva/MathBowling)
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
 
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/glimmer/launcher'
4
+
5
+ gladiator = File.expand_path('../../samples/gladiator.rb', __FILE__)
6
+ Glimmer::Launcher.new([gladiator, '-J-Xrs'] + ARGV).launch
@@ -84,3 +84,4 @@ require 'glimmer/swt/packages'
84
84
  require 'glimmer/dsl'
85
85
  require 'glimmer/error'
86
86
  require 'glimmer/invalid_keyword_error'
87
+ require 'glimmer/ui/video'
@@ -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
@@ -3,7 +3,6 @@ require 'glimmer/dsl/expression'
3
3
  require 'glimmer/dsl/parent_expression'
4
4
  require 'glimmer/ui/custom_widget'
5
5
  require 'glimmer/ui/custom_shell'
6
- require 'glimmer/ui/video' # this is interpreted here since it's a custom widget
7
6
 
8
7
  module Glimmer
9
8
  module DSL
@@ -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
- block.nil? and
13
- widget?(parent) and
14
- parent.swt_widget.is_a?(Tree) and
15
- args.size == 2 and
16
- args[0].is_a?(DataBinding::ModelBinding) and
17
- !args[0].evaluate_property.is_a?(Array) and
18
- args[1].is_a?(Array) and
19
- !args[1].empty? and
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
- widget_parentage = widget?(parent)
12
- Glimmer.logger&.debug "parent is a widget: #{widget_parentage}"
13
- return false unless widget_parentage
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?}"