glimmer 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +71 -27
- data/lib/glimmer.rb +8 -1
- data/lib/glimmer/data_binding/model_binding.rb +6 -5
- data/lib/glimmer/data_binding/widget_binding.rb +1 -4
- data/lib/glimmer/dsl/custom_widget_expression.rb +0 -1
- data/lib/glimmer/dsl/engine.rb +2 -2
- data/lib/glimmer/dsl/expression_handler.rb +3 -3
- data/lib/glimmer/dsl/layout_data_expression.rb +0 -1
- data/lib/glimmer/dsl/layout_expression.rb +0 -1
- data/lib/glimmer/dsl/static_expression.rb +2 -2
- data/lib/glimmer/dsl/widget_expression.rb +2 -3
- data/lib/glimmer/dsl/widget_listener_expression.rb +1 -1
- data/lib/glimmer/launcher.rb +59 -11
- data/lib/glimmer/rake_task.rb +0 -1
- data/lib/glimmer/ui/custom_widget.rb +2 -1
- data/lib/glimmer/ui/video.rb +131 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e13a3990377287df2bf023f72f4c6ab4b1cb8a58b4dad96321f4ac59e9efde11
|
4
|
+
data.tar.gz: 829597311c7719af97c326fd6f456038c1df94a76d8f140dd8acc430a8a951d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 344b90942d68a6bd994b09eb0e0848f996d57da0526cf54a6fc11f9718aae850b3e53419ba8bb418470f303fda278283ae99420d6a04bbd2cbab5b22e9ad250e
|
7
|
+
data.tar.gz: 486bbbf6de699a7d3985eea76a5588a83fe32c8a1484648d68b026237390427c2e14b8083b59874f0e0a87454c8d0a05449ca12016ba950c2271d7ac0da7e960
|
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Glimmer 0.5.
|
1
|
+
# Glimmer 0.5.4 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.
|
@@ -111,19 +111,19 @@ Please follow these instructions to make the `glimmer` command available on your
|
|
111
111
|
|
112
112
|
Run this command to install directly:
|
113
113
|
```
|
114
|
-
jgem install glimmer -v 0.5.
|
114
|
+
jgem install glimmer -v 0.5.4
|
115
115
|
```
|
116
116
|
|
117
117
|
### Option 2: Bundler
|
118
118
|
|
119
119
|
Add the following to `Gemfile`:
|
120
120
|
```
|
121
|
-
gem 'glimmer', '~> 0.5.
|
121
|
+
gem 'glimmer', '~> 0.5.4'
|
122
122
|
```
|
123
123
|
|
124
124
|
And, then run:
|
125
125
|
```
|
126
|
-
bundle install
|
126
|
+
jruby -S bundle install
|
127
127
|
```
|
128
128
|
|
129
129
|
## Glimmer Command
|
@@ -153,7 +153,7 @@ bin/glimmer samples/hello_world.rb
|
|
153
153
|
### Advanced Usage
|
154
154
|
|
155
155
|
```
|
156
|
-
glimmer [[-jruby-option]...] application.rb [[application2.rb]...]
|
156
|
+
glimmer [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-jruby-option]...] application.rb [[application2.rb]...]
|
157
157
|
```
|
158
158
|
|
159
159
|
Accepts JRuby options and multiple Glimmer applications to run simultaneously, each in a JRuby thread.
|
@@ -356,7 +356,7 @@ Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
|
|
356
356
|
button {
|
357
357
|
text "Press Me"
|
358
358
|
on_widget_selected {
|
359
|
-
message_box = MessageBox.new(@shell.
|
359
|
+
message_box = MessageBox.new(@shell.swt_widget) # passing SWT Shell widget
|
360
360
|
message_box.setText("Surprise")
|
361
361
|
message_box.setMessage("You have won $1,000,000!")
|
362
362
|
message_box.open
|
@@ -481,7 +481,7 @@ In the above example, the `text` widget `enabled` property was data-bound to `#e
|
|
481
481
|
|
482
482
|
#### Colors
|
483
483
|
|
484
|
-
Colors make up a subset of widget properties. SWT accepts color objects created with RGB (Red Green Blue) or RGBA (Red Green Blue Alpha). Glimmer supports constructing color objects using the `rgb` and `rgba` DSL
|
484
|
+
Colors make up a subset of widget properties. SWT accepts color objects created with RGB (Red Green Blue) or RGBA (Red Green Blue Alpha). Glimmer supports constructing color objects using the `rgb` and `rgba` DSL keywords.
|
485
485
|
|
486
486
|
Example:
|
487
487
|
|
@@ -494,21 +494,21 @@ label {
|
|
494
494
|
# ...
|
495
495
|
```
|
496
496
|
|
497
|
-
SWT also supports standard colors available as constants under the `SWT` namespace with the `COLOR_` prefix (e.g. `SWT::COLOR_BLUE
|
497
|
+
SWT also supports standard colors available as constants under the `SWT` namespace with the `COLOR_` prefix (e.g. `SWT::COLOR_BLUE`)
|
498
498
|
|
499
|
-
Glimmer
|
499
|
+
Glimmer supports constructing colors for these constants as lowercase Ruby symbols (with or without `color_` prefix) passed to `color` DSL keyword
|
500
500
|
|
501
501
|
Example:
|
502
502
|
|
503
503
|
```ruby
|
504
504
|
# ...
|
505
505
|
label {
|
506
|
-
background :black
|
507
|
-
foreground :yellow
|
506
|
+
background color(:black)
|
507
|
+
foreground color(:yellow)
|
508
508
|
}
|
509
509
|
label {
|
510
|
-
background :color_white
|
511
|
-
foreground :color_red
|
510
|
+
background color(:color_white)
|
511
|
+
foreground color(:color_red)
|
512
512
|
}
|
513
513
|
# ...
|
514
514
|
```
|
@@ -522,9 +522,11 @@ https://help.eclipse.org/2019-12/nftopic/org.eclipse.platform.doc.isv/reference/
|
|
522
522
|
|
523
523
|
Glimmer color objects come with an instance method `#swt_color` that returns the actual SWT `Color` object wrapped by the Glimmer color object. It is useful in cases you'd like to do some custom SWT programming outside of Glimmer.
|
524
524
|
|
525
|
-
|
525
|
+
Example:
|
526
526
|
|
527
|
-
|
527
|
+
```ruby
|
528
|
+
color(:black).swt_color # returns SWT Color object
|
529
|
+
```
|
528
530
|
|
529
531
|
#### Fonts
|
530
532
|
|
@@ -976,20 +978,20 @@ shell {
|
|
976
978
|
text "Show 2nd Button"
|
977
979
|
visible true
|
978
980
|
on_event_show {
|
979
|
-
@button2.
|
981
|
+
@button2.swt_widget.setVisible(false)
|
980
982
|
}
|
981
983
|
on_widget_selected {
|
982
|
-
@button2.
|
984
|
+
@button2.swt_widget.setVisible(true)
|
983
985
|
}
|
984
986
|
}
|
985
987
|
@button2 = button {
|
986
988
|
text "Show 1st Button"
|
987
989
|
visible false
|
988
990
|
on_event_show {
|
989
|
-
@button1.
|
991
|
+
@button1.swt_widget.setVisible(false)
|
990
992
|
}
|
991
993
|
on_widget_selected {
|
992
|
-
@button1.
|
994
|
+
@button1.swt_widget.setVisible(true)
|
993
995
|
}
|
994
996
|
}
|
995
997
|
}.open
|
@@ -1077,7 +1079,7 @@ class TicTacToe
|
|
1077
1079
|
end
|
1078
1080
|
|
1079
1081
|
def display_game_over_message(message)
|
1080
|
-
message_box = MessageBox.new(@shell.
|
1082
|
+
message_box = MessageBox.new(@shell.swt_widget)
|
1081
1083
|
message_box.setText("Game Over")
|
1082
1084
|
message_box.setMessage(message)
|
1083
1085
|
message_box.open
|
@@ -1313,7 +1315,7 @@ shell { |app_shell|
|
|
1313
1315
|
|
1314
1316
|
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.
|
1315
1317
|
|
1316
|
-
|
1318
|
+
Options (passed in an options hash as arguments to video widget):
|
1317
1319
|
- `autoplay` (true [default] or false): plays video automatically as soon as loaded
|
1318
1320
|
- `controls` (true [default] or false): displays controls
|
1319
1321
|
- `looped` (true or false [default]): plays video in looped mode
|
@@ -1324,8 +1326,22 @@ Attributes (passed in an options hash as arguments to video widget):
|
|
1324
1326
|
- `offset_y` (integer [default: 0]): offset from top border. Could be a negative number if you want to show only an area of the video. Useful when fit_to_height is false to pick an area of the video to display.
|
1325
1327
|
|
1326
1328
|
Methods:
|
1327
|
-
-
|
1328
|
-
-
|
1329
|
+
- `#play`: plays video
|
1330
|
+
- `#pause`: pauses video
|
1331
|
+
- `#reload`: reloads video restarting from beginning
|
1332
|
+
- `#position`: position in seconds (and fractions)
|
1333
|
+
- `#position=`: seeks a new position in video
|
1334
|
+
- `#duration`: length of video, maximum video position possible
|
1335
|
+
- `#loaded?`: returns true when video has been initially loaded or reloaded
|
1336
|
+
- `#playing?`: returns true when video is actively playing
|
1337
|
+
- `#paused?`: returns true when video is not playing
|
1338
|
+
- `#ended?`: returns true when video has reached the end (position == duration)
|
1339
|
+
|
1340
|
+
Events (to observe):
|
1341
|
+
- `on_loaded`: invoked when video `#loaded?` becomes true
|
1342
|
+
- `on_ended`: invoked when video `#ended?` becomes true
|
1343
|
+
- `on_playing`: invoked when video `#playing?` becomes true
|
1344
|
+
- `on_paused`: invoked when video `#paused?` becomes true
|
1329
1345
|
|
1330
1346
|
Example ([samples/video/hello_video.rb](samples/video/hello_video.rb)):
|
1331
1347
|
|
@@ -1346,6 +1362,36 @@ shell {
|
|
1346
1362
|
}.open
|
1347
1363
|
```
|
1348
1364
|
|
1365
|
+
Example ([samples/video/hello_video_observers.rb](samples/video/hello_video_observers.rb)):
|
1366
|
+
|
1367
|
+
```ruby
|
1368
|
+
# ...
|
1369
|
+
def display_video_status(video, status)
|
1370
|
+
message_box = MessageBox.new(video.swt_widget.getShell)
|
1371
|
+
message_box.setText(status)
|
1372
|
+
message = "Video Position: #{video.position} seconds\n"
|
1373
|
+
message += "Video Duration: #{video.duration} seconds"
|
1374
|
+
message_box.setMessage(message)
|
1375
|
+
message_box.open
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
@shell = shell {
|
1379
|
+
minimum_size 800, 500
|
1380
|
+
@video = video(file: video_file, background: :black) {
|
1381
|
+
on_playing {
|
1382
|
+
display_video_status(@video, 'Playing')
|
1383
|
+
}
|
1384
|
+
on_paused {
|
1385
|
+
display_video_status(@video, 'Paused')
|
1386
|
+
}
|
1387
|
+
on_ended {
|
1388
|
+
display_video_status(@video, 'Ended')
|
1389
|
+
}
|
1390
|
+
}
|
1391
|
+
}
|
1392
|
+
@shell.open
|
1393
|
+
```
|
1394
|
+
|
1349
1395
|
#### Browser Widget
|
1350
1396
|
|
1351
1397
|
Glimmer supports SWT Browser widget, which can load URLs or render HTML. It can even be instrumented with JavaScript when needed (though highly discouraged in Glimmer except for rare cases when leveraging a pre-existing web codebase in a desktop app).
|
@@ -1377,7 +1423,7 @@ shell {
|
|
1377
1423
|
</html>
|
1378
1424
|
HTML
|
1379
1425
|
on_completed { # on load of the page execute this JavaScript
|
1380
|
-
@browser.
|
1426
|
+
@browser.swt_widget.execute("alert('Hello, World!');")
|
1381
1427
|
}
|
1382
1428
|
}
|
1383
1429
|
}.open
|
@@ -1539,10 +1585,8 @@ Glimmer simplifies the process for general packaging on the Mac by providing a r
|
|
1539
1585
|
|
1540
1586
|
- Create `Rakefile` in your app root directory
|
1541
1587
|
- Add the following line to it: `require 'glimmer/rake_task'`
|
1542
|
-
- Create a Ruby script under bin
|
1588
|
+
- Create a Ruby script under bin (e.g. `bin/math_bowling`) to require the application file that uses Glimmer (e.g. `'../app/my_application.rb'`):
|
1543
1589
|
```ruby
|
1544
|
-
require 'glimmer/launcher'
|
1545
|
-
require Glimmer::Launcher.swt_jar_file
|
1546
1590
|
require_relative '../app/my_application.rb'
|
1547
1591
|
```
|
1548
1592
|
|
data/lib/glimmer.rb
CHANGED
@@ -58,7 +58,7 @@ module Glimmer
|
|
58
58
|
if method_symbol.to_s.match(REGEX_METHODS_EXCLUDED)
|
59
59
|
raise InvalidKeywordError, "Glimmer excluded keyword: #{method_symbol}"
|
60
60
|
end
|
61
|
-
Glimmer.logger&.debug "keyword:
|
61
|
+
Glimmer.logger&.debug "Interpreting keyword: #{method_symbol}"
|
62
62
|
Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
|
63
63
|
rescue InvalidKeywordError => e
|
64
64
|
if !method_symbol.to_s.match(REGEX_METHODS_EXCLUDED)
|
@@ -69,8 +69,15 @@ module Glimmer
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
if ENV['GLIMMER_LOGGER_LEVEL']
|
73
|
+
Glimmer.enable_logging
|
74
|
+
Glimmer.logger.level = ENV['GLIMMER_LOGGER_LEVEL'].downcase
|
75
|
+
end
|
76
|
+
|
72
77
|
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
73
78
|
|
79
|
+
require 'glimmer/launcher'
|
80
|
+
require Glimmer::Launcher.swt_jar_file
|
74
81
|
require 'glimmer/swt/packages'
|
75
82
|
require 'glimmer/dsl'
|
76
83
|
require 'glimmer/error'
|
@@ -203,7 +203,10 @@ module Glimmer
|
|
203
203
|
end
|
204
204
|
|
205
205
|
def evaluate_property
|
206
|
-
|
206
|
+
unless model.nil?
|
207
|
+
value = invoke_property_reader(model, property_name)
|
208
|
+
convert_on_read(value)
|
209
|
+
end
|
207
210
|
end
|
208
211
|
|
209
212
|
def evaluate_options_property
|
@@ -219,16 +222,14 @@ module Glimmer
|
|
219
222
|
end
|
220
223
|
|
221
224
|
def invoke_property_reader(object, property_expression)
|
222
|
-
value = nil
|
223
225
|
if property_indexed?(property_expression)
|
224
226
|
property_method = '[]'
|
225
227
|
property_argument = property_expression[1...-1]
|
226
228
|
property_argument = property_argument.to_i if property_argument.match(/\d+/)
|
227
|
-
|
229
|
+
object.send(property_method, property_argument)
|
228
230
|
else
|
229
|
-
|
231
|
+
object.send(property_expression)
|
230
232
|
end
|
231
|
-
convert_on_read(value)
|
232
233
|
end
|
233
234
|
|
234
235
|
def invoke_property_writer(object, property_expression, value)
|
@@ -15,13 +15,10 @@ module Glimmer
|
|
15
15
|
@property = property
|
16
16
|
@translator = translator || proc {|value| value}
|
17
17
|
|
18
|
-
|
18
|
+
if @widget.respond_to?(:dispose)
|
19
19
|
@widget.on_widget_disposed do |dispose_event|
|
20
20
|
unregister_all_observables
|
21
21
|
end
|
22
|
-
rescue => e
|
23
|
-
# No Op
|
24
|
-
Glimmer.logger&.debug("#{e.message}\n#{e.backtrace.join("\n")}")
|
25
22
|
end
|
26
23
|
end
|
27
24
|
def call(value)
|
@@ -18,7 +18,6 @@ module Glimmer
|
|
18
18
|
|
19
19
|
def interpret(parent, keyword, *args, &block)
|
20
20
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
21
|
-
Glimmer.logger&.debug "Custom widget #{keyword} styles are: [" + args.inspect + "] and options are: #{options}"
|
22
21
|
UI::CustomWidget.for(keyword).new(parent, *args, options, &block)
|
23
22
|
end
|
24
23
|
|
data/lib/glimmer/dsl/engine.rb
CHANGED
@@ -58,9 +58,9 @@ module Glimmer
|
|
58
58
|
#
|
59
59
|
# For example, a shell widget would get properties set and children added
|
60
60
|
def add_content(parent, expression, &block)
|
61
|
-
parent_stack.push(parent)
|
61
|
+
parent_stack.push(parent) if expression.is_a?(ParentExpression)
|
62
62
|
expression.add_content(parent, &block) if block_given?
|
63
|
-
parent_stack.pop
|
63
|
+
parent_stack.pop if expression.is_a?(ParentExpression)
|
64
64
|
end
|
65
65
|
|
66
66
|
# Current parent while evaluating Glimmer DSL (nil if just started or done evaluatiing)
|
@@ -23,16 +23,16 @@ module Glimmer
|
|
23
23
|
# Otherwise, it forwards to the next handler configured via `#next=` method
|
24
24
|
# If there is no handler next, then it raises an error
|
25
25
|
def handle(parent, keyword, *args, &block)
|
26
|
-
Glimmer.logger&.debug "Attempting to handle #{keyword}
|
26
|
+
Glimmer.logger&.debug "Attempting to handle #{keyword} with #{@expression.class.name.split(":").last}"
|
27
27
|
if @expression.can_interpret?(parent, keyword, *args, &block)
|
28
|
-
Glimmer.logger&.debug "#{@expression.class.name} will handle expression keyword #{keyword}
|
28
|
+
Glimmer.logger&.debug "#{@expression.class.name} will handle expression keyword #{keyword}"
|
29
29
|
return @expression
|
30
30
|
elsif @next_expression_handler
|
31
31
|
return @next_expression_handler.handle(parent, keyword, *args, &block)
|
32
32
|
else
|
33
33
|
# TODO see if we need a better response here (e.g. dev mode error raising vs production mode silent failure)
|
34
34
|
message = "Glimmer keyword #{keyword} with args #{args} cannot be handled"
|
35
|
-
message += " inside parent #{parent
|
35
|
+
message += " inside parent #{parent}" if parent
|
36
36
|
message += "! Check the validity of the code."
|
37
37
|
# Glimmer.logger&.error message
|
38
38
|
raise InvalidKeywordError, message
|
@@ -19,9 +19,9 @@ module Glimmer
|
|
19
19
|
Glimmer.define_method(keyword) do |*args, &block|
|
20
20
|
parent = Glimmer::DSL::Engine.current_parent
|
21
21
|
if !static_expression.can_interpret?(parent, keyword, *args, &block)
|
22
|
-
raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args
|
22
|
+
raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{parent}"
|
23
23
|
else
|
24
|
-
Glimmer.logger&.debug "#{base.name} will handle expression keyword #{keyword}
|
24
|
+
Glimmer.logger&.debug "#{base.name} will handle expression keyword #{keyword}"
|
25
25
|
static_expression.interpret(parent, keyword, *args, &block).tap do |ui_object|
|
26
26
|
Glimmer::DSL::Engine.add_content(ui_object, static_expression, &block) unless block.nil?
|
27
27
|
end
|
@@ -6,17 +6,16 @@ module Glimmer
|
|
6
6
|
module DSL
|
7
7
|
class WidgetExpression < Expression
|
8
8
|
include ParentExpression
|
9
|
-
|
9
|
+
|
10
10
|
EXCLUDED_KEYWORDS = %w[shell display tab_item]
|
11
11
|
|
12
12
|
def can_interpret?(parent, keyword, *args, &block)
|
13
13
|
!EXCLUDED_KEYWORDS.include?(keyword) and
|
14
|
-
widget?(parent) and
|
14
|
+
widget?(parent) and #TODO change to composite?(parent)
|
15
15
|
SWT::WidgetProxy.widget_exists?(keyword)
|
16
16
|
end
|
17
17
|
|
18
18
|
def interpret(parent, keyword, *args, &block)
|
19
|
-
Glimmer.logger&.debug "widget styles are: " + args.inspect
|
20
19
|
SWT::WidgetProxy.new(keyword, parent, args)
|
21
20
|
end
|
22
21
|
end
|
@@ -14,7 +14,7 @@ module Glimmer
|
|
14
14
|
Glimmer.logger&.debug "block exists?: #{!block.nil?}"
|
15
15
|
raise Glimmer::Error, "Listener is missing block for keyword: #{keyword}" unless block_given?
|
16
16
|
Glimmer.logger&.debug "args are empty?: #{args.empty?}"
|
17
|
-
raise Glimmer::Error, "Invalid listener arguments for keyword: #{keyword}(#{args
|
17
|
+
raise Glimmer::Error, "Invalid listener arguments for keyword: #{keyword}(#{args})" unless args.empty?
|
18
18
|
result = parent.can_handle_observation_request?(keyword)
|
19
19
|
Glimmer.logger&.debug "can add listener? #{result}"
|
20
20
|
raise Glimmer::Error, "Invalid listener keyword: #{keyword}" unless result
|
data/lib/glimmer/launcher.rb
CHANGED
@@ -4,7 +4,7 @@ module Glimmer
|
|
4
4
|
class Launcher
|
5
5
|
OPERATING_SYSTEMS_SUPPORTED = ["mac", "windows", "linux"]
|
6
6
|
TEXT_USAGE = <<-MULTILINE
|
7
|
-
Usage: glimmer [[-jruby-option]...] application.rb [[application2.rb]...]
|
7
|
+
Usage: glimmer [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-jruby-option]...] application.rb [[application2.rb]...]
|
8
8
|
|
9
9
|
Runs Glimmer applications using JRuby, automatically preloading
|
10
10
|
the glimmer ruby gem and SWT jar dependency.
|
@@ -16,6 +16,10 @@ module Glimmer
|
|
16
16
|
MULTILINE
|
17
17
|
GLIMMER_LIB_LOCAL = File.expand_path(File.join(__FILE__, '..', '..', 'glimmer.rb'))
|
18
18
|
GLIMMER_LIB_GEM = 'glimmer'
|
19
|
+
GLIMMER_OPTIONS = %w[--log-level]
|
20
|
+
GLIMMER_OPTION_ENV_VAR_MAPPING = {
|
21
|
+
'--log-level' => 'GLIMMER_LOGGER_LEVEL'
|
22
|
+
}
|
19
23
|
|
20
24
|
@@mutex = Mutex.new
|
21
25
|
|
@@ -50,18 +54,25 @@ module Glimmer
|
|
50
54
|
@glimmer_lib
|
51
55
|
end
|
52
56
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
57
|
+
def glimmer_option_env_vars(glimmer_options)
|
58
|
+
glimmer_options.map do |k, v|
|
59
|
+
"#{GLIMMER_OPTION_ENV_VAR_MAPPING[k]}=#{v}"
|
60
|
+
end.join(' ')
|
56
61
|
end
|
57
|
-
end
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
def launch(application, jruby_options: [], env_vars: {}, glimmer_options: {})
|
64
|
+
jruby_options_string = jruby_options.join(' ') + ' ' if jruby_options.any?
|
65
|
+
env_vars_string = env_vars.map {|k,v| "#{k}=#{v}"}.join(' ')
|
66
|
+
env_vars_string = [env_vars_string, glimmer_option_env_vars(glimmer_options)].join(' ')
|
67
|
+
system "#{env_vars_string} jruby #{jruby_options_string}#{jruby_os_specific_options} -r #{glimmer_lib} -S #{application}"
|
63
68
|
end
|
64
|
-
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize(raw_options)
|
72
|
+
@application_paths = extract_application_paths(raw_options)
|
73
|
+
@env_vars = extract_env_vars(raw_options)
|
74
|
+
@glimmer_options = extract_glimmer_options(raw_options)
|
75
|
+
@jruby_options = raw_options
|
65
76
|
end
|
66
77
|
|
67
78
|
def launch
|
@@ -78,7 +89,12 @@ module Glimmer
|
|
78
89
|
threads = @application_paths.map do |application_path|
|
79
90
|
puts "Launching Glimmer Application: #{application_path}" unless application_path.to_s.include?('irb')
|
80
91
|
Thread.new do
|
81
|
-
self.class.launch(
|
92
|
+
self.class.launch(
|
93
|
+
application_path,
|
94
|
+
jruby_options: @jruby_options,
|
95
|
+
env_vars: @env_vars,
|
96
|
+
glimmer_options: @glimmer_options
|
97
|
+
)
|
82
98
|
end
|
83
99
|
end
|
84
100
|
threads.each(&:join)
|
@@ -87,5 +103,37 @@ module Glimmer
|
|
87
103
|
def display_usage
|
88
104
|
puts TEXT_USAGE
|
89
105
|
end
|
106
|
+
|
107
|
+
def extract_application_paths(options)
|
108
|
+
options.select do |option|
|
109
|
+
!option.start_with?('-') && !option.include?('=')
|
110
|
+
end.each do |application_path|
|
111
|
+
options.delete(application_path)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def extract_env_vars(options)
|
116
|
+
options.select do |option|
|
117
|
+
!option.start_with?('-') && option.include?('=')
|
118
|
+
end.each do |env_var|
|
119
|
+
options.delete(env_var)
|
120
|
+
end.reduce({}) do |hash, env_var_string|
|
121
|
+
match = env_var_string.match(/^([^=]+)=(.+)$/)
|
122
|
+
hash.merge(match[1] => match[2])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def extract_glimmer_options(options)
|
127
|
+
options.select do |option|
|
128
|
+
GLIMMER_OPTIONS.reduce(false) do |result, glimmer_option|
|
129
|
+
result || option.include?(glimmer_option)
|
130
|
+
end
|
131
|
+
end.each do |glimmer_option|
|
132
|
+
options.delete(glimmer_option)
|
133
|
+
end.reduce({}) do |hash, glimmer_option_string|
|
134
|
+
match = glimmer_option_string.match(/^([^=]+)=?(.*)$/)
|
135
|
+
hash.merge(match[1] => match[2])
|
136
|
+
end
|
137
|
+
end
|
90
138
|
end
|
91
139
|
end
|
data/lib/glimmer/rake_task.rb
CHANGED
@@ -18,7 +18,6 @@ namespace :glimmer do
|
|
18
18
|
end
|
19
19
|
system('mkdir -p dist')
|
20
20
|
system('warble')
|
21
|
-
puts("javapackager -deploy -native -outdir packages -outfile #{project_name} -srcdir dist -srcfiles #{project_name}.jar -appclass JarMain -name \"#{project_name}\" -title \"#{project_name}\" -BjvmOptions=-XstartOnFirstThread")
|
22
21
|
system("javapackager -deploy -native -outdir packages -outfile #{project_name} -srcdir dist -srcfiles #{project_name}.jar -appclass JarMain -name \"#{project_name}\" -title \"#{project_name}\" -BjvmOptions=-XstartOnFirstThread")
|
23
22
|
end
|
24
23
|
end
|
@@ -25,6 +25,7 @@ module Glimmer
|
|
25
25
|
split(/__/).map do |namespace|
|
26
26
|
namespace.camelcase(:upper)
|
27
27
|
end
|
28
|
+
#TODO update code to avoid using reduce and going through all of them, yet stop right when it finds something
|
28
29
|
custom_widget_class = [Object, Glimmer::UI].reduce([]) do |found, base|
|
29
30
|
if found.empty?
|
30
31
|
found << namespaces.reduce(base) do |result, namespace|
|
@@ -135,7 +136,7 @@ module Glimmer
|
|
135
136
|
end
|
136
137
|
|
137
138
|
def can_add_observer?(attribute_name)
|
138
|
-
respond_to?(attribute_name) || @body_root.can_add_observer?(attribute_name)
|
139
|
+
respond_to?(attribute_name) || respond_to?("#{attribute_name}?") || @body_root.can_add_observer?(attribute_name)
|
139
140
|
end
|
140
141
|
|
141
142
|
def add_observer(observer, attribute_name)
|
data/lib/glimmer/ui/video.rb
CHANGED
@@ -10,15 +10,6 @@ module Glimmer
|
|
10
10
|
|
11
11
|
include_package 'org.eclipse.swt.browser'
|
12
12
|
|
13
|
-
PROPERTIES_OBSERVED = [
|
14
|
-
'playing',
|
15
|
-
'paused',
|
16
|
-
'ended',
|
17
|
-
'started',
|
18
|
-
'remaining',
|
19
|
-
'current_time',
|
20
|
-
]
|
21
|
-
|
22
13
|
options :file, :url
|
23
14
|
option :autoplay, true
|
24
15
|
option :controls, true
|
@@ -70,6 +61,9 @@ module Glimmer
|
|
70
61
|
</body>
|
71
62
|
</html>
|
72
63
|
HTML
|
64
|
+
on_completed {
|
65
|
+
@completed = true
|
66
|
+
}
|
73
67
|
}
|
74
68
|
}
|
75
69
|
|
@@ -103,10 +97,137 @@ module Glimmer
|
|
103
97
|
video_action('pause')
|
104
98
|
end
|
105
99
|
|
100
|
+
def reload
|
101
|
+
video_action('load')
|
102
|
+
end
|
103
|
+
|
104
|
+
def paused?
|
105
|
+
video_attribute('paused')
|
106
|
+
end
|
107
|
+
|
108
|
+
def playing?
|
109
|
+
!paused?
|
110
|
+
end
|
111
|
+
|
112
|
+
def ended?
|
113
|
+
video_attribute('ended')
|
114
|
+
end
|
115
|
+
|
116
|
+
# Video fully loaded and ready for playback
|
117
|
+
def loaded?
|
118
|
+
!!@completed
|
119
|
+
end
|
120
|
+
|
121
|
+
def position
|
122
|
+
video_attribute('currentTime')
|
123
|
+
end
|
124
|
+
|
125
|
+
def position=(new_position)
|
126
|
+
video_attribute_set('currentTime', new_position)
|
127
|
+
end
|
128
|
+
|
129
|
+
def duration
|
130
|
+
video_attribute('duration')
|
131
|
+
end
|
132
|
+
|
133
|
+
def can_handle_observation_request?(observation_request)
|
134
|
+
result = false
|
135
|
+
if observation_request.start_with?('on_')
|
136
|
+
attribute = observation_request.sub(/^on_/, '')
|
137
|
+
result = OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING.keys.include?(attribute)
|
138
|
+
end
|
139
|
+
result || super
|
140
|
+
end
|
141
|
+
|
142
|
+
def handle_observation_request(observation_request, &block)
|
143
|
+
if observation_request.start_with?('on_')
|
144
|
+
attribute = observation_request.sub(/^on_/, '')
|
145
|
+
if attribute == 'loaded' && !@completed
|
146
|
+
super('on_completed', &block)
|
147
|
+
elsif OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING.keys.include?(attribute)
|
148
|
+
add_video_observer(block, OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING[attribute])
|
149
|
+
else
|
150
|
+
super
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
106
155
|
private
|
107
156
|
|
157
|
+
class VideoObserverBrowserFunction < BrowserFunction
|
158
|
+
def initialize(video, observer_proc, attribute)
|
159
|
+
@observer_proc = observer_proc
|
160
|
+
@attribute = attribute
|
161
|
+
name = self.class.generate_name(@attribute)
|
162
|
+
super(video.swt_widget, name)
|
163
|
+
end
|
164
|
+
|
165
|
+
def function(arguments)
|
166
|
+
@observer_proc.call
|
167
|
+
rescue => e
|
168
|
+
Glimmer.logger&.error "#{e.message}\n#{e.backtrace.join("\n")}"
|
169
|
+
ensure
|
170
|
+
nil
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
class << self
|
176
|
+
def generate_name(attribute)
|
177
|
+
"video#{attribute}#{generate_attribute_id(attribute)}"
|
178
|
+
end
|
179
|
+
|
180
|
+
def generate_attribute_id(attribute)
|
181
|
+
attribute_max_ids[attribute] = attribute_max_id(attribute) + 1
|
182
|
+
end
|
183
|
+
|
184
|
+
def attribute_max_id(attribute)
|
185
|
+
attribute_max_ids[attribute] ||= 0
|
186
|
+
end
|
187
|
+
|
188
|
+
def attribute_max_ids
|
189
|
+
@attribute_max_ids ||= {}
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
OBSERVED_ATTRIBUTE_TO_PROPERTY_MAPPING = {
|
195
|
+
'playing' => 'play',
|
196
|
+
'paused' => 'pause',
|
197
|
+
'ended' => 'ended',
|
198
|
+
'loaded' => 'canplay',
|
199
|
+
}
|
200
|
+
|
108
201
|
def video_action(action)
|
109
|
-
|
202
|
+
run_on_completed do
|
203
|
+
swt_widget.execute("document.getElementById('video').#{action}()")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def video_attribute(attribute)
|
208
|
+
swt_widget.evaluate("return document.getElementById('video').#{attribute}") if @completed
|
209
|
+
end
|
210
|
+
|
211
|
+
def video_attribute_set(attribute, value)
|
212
|
+
value = "'#{value}'" if value.is_a?(String) || value.is_a?(Symbol)
|
213
|
+
run_on_completed do
|
214
|
+
swt_widget.execute("document.getElementById('video').#{attribute} = #{value}")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def add_video_observer(observer_proc, attribute)
|
219
|
+
run_on_completed do
|
220
|
+
video_observer_browser_function = VideoObserverBrowserFunction.new(self, observer_proc, attribute)
|
221
|
+
swt_widget.execute("document.getElementById('video').addEventListener('#{attribute}', function() {#{video_observer_browser_function.getName}()})")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def run_on_completed(&block)
|
226
|
+
if @completed
|
227
|
+
block.call
|
228
|
+
else
|
229
|
+
on_completed(&block)
|
230
|
+
end
|
110
231
|
end
|
111
232
|
|
112
233
|
def browser_video_autoplay
|
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.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|