glimmer-dsl-opal 0.10.2 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +252 -0
  3. data/README.md +187 -1301
  4. data/VERSION +1 -1
  5. data/lib/display.rb +3 -0
  6. data/lib/glimmer-dsl-opal.rb +2 -1
  7. data/lib/glimmer-dsl-opal/ext/glimmer/dsl/engine.rb +1 -1
  8. data/lib/glimmer-dsl-opal/samples/elaborate/contact_manager.rb +15 -13
  9. data/lib/glimmer-dsl-opal/samples/elaborate/login.rb +55 -28
  10. data/lib/glimmer-dsl-opal/samples/elaborate/tic_tac_toe.rb +2 -2
  11. data/lib/glimmer-dsl-opal/samples/elaborate/weather.rb +157 -0
  12. data/lib/glimmer-dsl-opal/samples/hello/hello_button.rb +8 -8
  13. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox.rb +16 -14
  14. data/lib/glimmer-dsl-opal/samples/hello/hello_checkbox_group.rb +14 -9
  15. data/lib/glimmer-dsl-opal/samples/hello/hello_combo.rb +24 -22
  16. data/lib/glimmer-dsl-opal/samples/hello/hello_computed.rb +32 -14
  17. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_shell.rb +16 -12
  18. data/lib/glimmer-dsl-opal/samples/hello/hello_custom_widget.rb +1 -1
  19. data/lib/glimmer-dsl-opal/samples/hello/hello_date_time.rb +4 -4
  20. data/lib/glimmer-dsl-opal/samples/hello/hello_group.rb +6 -6
  21. data/lib/glimmer-dsl-opal/samples/hello/hello_list_multi_selection.rb +1 -1
  22. data/lib/glimmer-dsl-opal/samples/hello/hello_list_single_selection.rb +1 -1
  23. data/lib/glimmer-dsl-opal/samples/hello/hello_radio.rb +18 -16
  24. data/lib/glimmer-dsl-opal/samples/hello/hello_radio_group.rb +17 -12
  25. data/lib/glimmer-dsl-opal/samples/hello/hello_table.rb +4 -4
  26. data/lib/glimmer/data_binding/table_items_binding.rb +3 -2
  27. data/lib/glimmer/dsl/opal/bind_expression.rb +24 -25
  28. data/lib/glimmer/dsl/opal/custom_widget_expression.rb +8 -8
  29. data/lib/glimmer/dsl/opal/dsl.rb +4 -0
  30. data/lib/glimmer/dsl/opal/menu_expression.rb +1 -1
  31. data/lib/glimmer/dsl/opal/property_expression.rb +2 -1
  32. data/lib/glimmer/dsl/opal/shape_expression.rb +26 -0
  33. data/lib/glimmer/dsl/opal/shell_expression.rb +1 -1
  34. data/lib/{glimmer-dsl-opal/samples/hello/hello_computed/contact.rb → glimmer/dsl/opal/shine_data_binding_expression.rb} +24 -17
  35. data/lib/glimmer/dsl/opal/table_items_data_binding_expression.rb +2 -2
  36. data/lib/glimmer/dsl/opal/widget_expression.rb +1 -1
  37. data/lib/glimmer/swt/combo_proxy.rb +1 -0
  38. data/lib/glimmer/swt/composite_proxy.rb +2 -0
  39. data/lib/glimmer/swt/dialog_proxy.rb +1 -1
  40. data/lib/glimmer/swt/display_proxy.rb +63 -1
  41. data/lib/glimmer/swt/grid_layout_proxy.rb +17 -17
  42. data/lib/glimmer/swt/layout_proxy.rb +23 -3
  43. data/lib/glimmer/swt/message_box_proxy.rb +1 -1
  44. data/lib/glimmer/swt/row_layout_proxy.rb +12 -3
  45. data/lib/glimmer/swt/table_proxy.rb +19 -3
  46. data/lib/glimmer/swt/widget_proxy.rb +3 -4
  47. data/lib/glimmer/ui/custom_shell.rb +22 -5
  48. data/lib/glimmer/ui/custom_widget.rb +11 -2
  49. data/lib/net/http.rb +14 -6
  50. metadata +14 -10
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.2
1
+ 0.14.0
data/lib/display.rb CHANGED
@@ -24,8 +24,11 @@ class Display
24
24
  def setAppName(app_name)
25
25
  # No Op in Opal
26
26
  end
27
+ alias app_name= setAppName
28
+
27
29
  def setAppVersion(version)
28
30
  # No Op in Opal
29
31
  end
32
+ alias app_version= setAppVersion
30
33
  end
31
34
  end
@@ -56,6 +56,7 @@ if RUBY_ENGINE == 'opal'
56
56
  # require 'glimmer-dsl-opal/vendor/jquery-ui/jquery-ui.theme.min.css'
57
57
  require 'opal-jquery'
58
58
  require 'opal/jquery/local_storage'
59
+ require 'promise'
59
60
 
60
61
  require 'facets/hash/symbolize_keys'
61
62
  require 'glimmer-dsl-opal/ext/class'
@@ -84,7 +85,7 @@ if RUBY_ENGINE == 'opal'
84
85
  Element.alias_native :select
85
86
  Element.alias_native :dialog
86
87
 
87
- Glimmer::Config.loop_max_count = 10 # TODO disable
88
+ Glimmer::Config.loop_max_count = 250 # TODO disable
88
89
 
89
90
  original_logger_level = Glimmer::Config.logger.level
90
91
  Glimmer::Config.logger = Glimmer::Config::OpalLogger.new(STDOUT)
@@ -31,7 +31,7 @@ module Glimmer
31
31
  def interpret_expression(expression, keyword, *args, &block)
32
32
  work = lambda do
33
33
  expression.interpret(parent, keyword, *args, &block).tap do |ui_object|
34
- add_content(ui_object, expression, &block)
34
+ add_content(ui_object, expression, keyword, *args, &block)
35
35
  dsl_stack.pop
36
36
  end
37
37
  end
@@ -1,14 +1,14 @@
1
1
  require_relative "contact_manager/contact_manager_presenter"
2
2
 
3
3
  class ContactManager
4
- include Glimmer
4
+ include Glimmer::UI::CustomShell
5
5
 
6
- def initialize
6
+ before_body {
7
7
  @contact_manager_presenter = ContactManagerPresenter.new
8
8
  @contact_manager_presenter.list
9
- end
9
+ }
10
10
 
11
- def launch
11
+ body {
12
12
  shell {
13
13
  text "Contact Manager"
14
14
  composite {
@@ -28,7 +28,7 @@ class ContactManager
28
28
  }
29
29
  text {
30
30
  layout_data :fill, :center, true, false
31
- text bind(@contact_manager_presenter, :first_name)
31
+ text <=> [@contact_manager_presenter, :first_name]
32
32
  on_key_pressed {|key_event|
33
33
  @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
34
34
  }
@@ -41,7 +41,7 @@ class ContactManager
41
41
  }
42
42
  text {
43
43
  layout_data :fill, :center, true, false
44
- text bind(@contact_manager_presenter, :last_name)
44
+ text <=> [@contact_manager_presenter, :last_name]
45
45
  on_key_pressed {|key_event|
46
46
  @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
47
47
  }
@@ -54,7 +54,7 @@ class ContactManager
54
54
  }
55
55
  text {
56
56
  layout_data :fill, :center, true, false
57
- text bind(@contact_manager_presenter, :email)
57
+ text <=> [@contact_manager_presenter, :email]
58
58
  on_key_pressed {|key_event|
59
59
  @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
60
60
  }
@@ -87,7 +87,7 @@ class ContactManager
87
87
  }
88
88
  }
89
89
 
90
- table(:multi) { |table_proxy|
90
+ table(:editable, :multi) { |table_proxy|
91
91
  layout_data {
92
92
  horizontal_alignment :fill
93
93
  vertical_alignment :fill
@@ -95,6 +95,7 @@ class ContactManager
95
95
  grab_excess_vertical_space true
96
96
  height_hint 200
97
97
  }
98
+
98
99
  table_column {
99
100
  text "First Name"
100
101
  width 80
@@ -107,15 +108,16 @@ class ContactManager
107
108
  text "Email"
108
109
  width 200
109
110
  }
110
- items bind(@contact_manager_presenter, :results),
111
- column_properties(:first_name, :last_name, :email)
111
+
112
+ items <=> [@contact_manager_presenter, :results, column_attributes: [:first_name, :last_name, :email]]
113
+
112
114
  on_mouse_up { |event|
113
115
  table_proxy.edit_table_item(event.table_item, event.column_index)
114
116
  }
115
117
  }
116
118
  }
117
- }.open
118
- end
119
+ }
120
+ }
119
121
  end
120
122
 
121
- ContactManager.new.launch
123
+ ContactManager.launch
@@ -1,4 +1,25 @@
1
- require "observer"
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-swt'
2
23
 
3
24
  class LoginPresenter
4
25
 
@@ -14,29 +35,26 @@ class LoginPresenter
14
35
 
15
36
  def status=(status)
16
37
  @status = status
17
-
18
- notify_observers("logged_in")
19
- notify_observers("logged_out")
20
38
  end
21
39
 
22
40
  def valid?
23
41
  !@user_name.to_s.strip.empty? && !@password.to_s.strip.empty?
24
42
  end
25
43
 
26
- def logged_in
44
+ def logged_in?
27
45
  self.status == "Logged In"
28
46
  end
29
47
 
30
- def logged_out
31
- !self.logged_in
48
+ def logged_out?
49
+ !self.logged_in?
32
50
  end
33
51
 
34
- def login
52
+ def login!
35
53
  return unless valid?
36
54
  self.status = "Logged In"
37
55
  end
38
56
 
39
- def logout
57
+ def logout!
40
58
  self.user_name = ""
41
59
  self.password = ""
42
60
  self.status = "Logged Out"
@@ -45,19 +63,24 @@ class LoginPresenter
45
63
  end
46
64
 
47
65
  class Login
48
- include Glimmer
66
+ include Glimmer::UI::CustomShell
67
+
68
+ before_body {
69
+ @presenter = LoginPresenter.new
70
+ }
49
71
 
50
- def launch
51
- presenter = LoginPresenter.new
52
- @shell = shell {
72
+ body {
73
+ shell {
53
74
  text "Login"
75
+
54
76
  composite {
55
77
  grid_layout 2, false #two columns with differing widths
56
78
 
57
79
  label { text "Username:" } # goes in column 1
58
80
  @user_name_text = text { # goes in column 2
59
- text bind(presenter, :user_name)
60
- enabled bind(presenter, :logged_out)
81
+ text <=> [@presenter, :user_name]
82
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
83
+
61
84
  on_key_pressed { |event|
62
85
  @password_text.set_focus if event.keyCode == swt(:cr)
63
86
  }
@@ -65,40 +88,44 @@ class Login
65
88
 
66
89
  label { text "Password:" }
67
90
  @password_text = text(:password, :border) {
68
- text bind(presenter, :password)
69
- enabled bind(presenter, :logged_out)
91
+ text <=> [@presenter, :password]
92
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
93
+
70
94
  on_key_pressed { |event|
71
- presenter.login if event.keyCode == swt(:cr)
95
+ @presenter.login! if event.keyCode == swt(:cr)
72
96
  }
73
97
  }
74
98
 
75
99
  label { text "Status:" }
76
- label { text bind(presenter, :status) }
100
+ label { text <= [@presenter, :status] }
77
101
 
78
102
  button {
79
103
  text "Login"
80
- enabled bind(presenter, :logged_out)
81
- on_widget_selected { presenter.login }
104
+ enabled <= [@presenter, :logged_out?, computed_by: :status]
105
+
106
+ on_widget_selected { @presenter.login! }
82
107
  on_key_pressed { |event|
83
- presenter.login if event.keyCode == swt(:cr)
108
+ if event.keyCode == swt(:cr)
109
+ @presenter.login!
110
+ end
84
111
  }
85
112
  }
86
113
 
87
114
  button {
88
115
  text "Logout"
89
- enabled bind(presenter, :logged_in)
90
- on_widget_selected { presenter.logout }
116
+ enabled <= [@presenter, :logged_in?, computed_by: :status]
117
+
118
+ on_widget_selected { @presenter.logout! }
91
119
  on_key_pressed { |event|
92
120
  if event.keyCode == swt(:cr)
93
- presenter.logout
121
+ @presenter.logout!
94
122
  @user_name_text.set_focus
95
123
  end
96
124
  }
97
125
  }
98
126
  }
99
127
  }
100
- @shell.open
101
- end
128
+ }
102
129
  end
103
130
 
104
- Login.new.launch
131
+ Login.launch
@@ -35,8 +35,8 @@ class TicTacToe
35
35
  (1..3).each { |column|
36
36
  button {
37
37
  layout_data :fill, :fill, true, true
38
- text bind(@tic_tac_toe_board[row, column], :sign)
39
- enabled bind(@tic_tac_toe_board[row, column], :empty)
38
+ text <= [@tic_tac_toe_board[row, column], :sign]
39
+ enabled <= [@tic_tac_toe_board[row, column], :empty]
40
40
  font style: :bold, height: 20
41
41
  on_widget_selected {
42
42
  @tic_tac_toe_board.mark(row, column)
@@ -0,0 +1,157 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'net/http'
23
+ require 'json'
24
+ require 'facets/string/titlecase'
25
+
26
+ class Weather
27
+ include Glimmer::UI::CustomShell
28
+
29
+ DEFAULT_FONT_HEIGHT = 30
30
+ DEFAULT_FOREGROUND = :white
31
+ DEFAULT_BACKGROUND = rgb(135, 176, 235)
32
+
33
+ attr_accessor :city, :temp, :temp_min, :temp_max, :feels_like, :humidity
34
+
35
+ before_body {
36
+ @weather_mutex = Mutex.new
37
+ self.city = 'Montreal, QC, CA'
38
+ fetch_weather!
39
+ }
40
+
41
+ body {
42
+ shell(:no_resize) {
43
+ grid_layout
44
+
45
+ text 'Glimmer Weather'
46
+ minimum_size 400, 300
47
+ background DEFAULT_BACKGROUND
48
+
49
+ text {
50
+ layout_data(:center, :center, true, true)
51
+
52
+ text <=> [self, :city]
53
+
54
+ on_key_pressed {|event|
55
+ if event.keyCode == swt(:cr) # carriage return
56
+ Thread.new do
57
+ fetch_weather!
58
+ end
59
+ end
60
+ }
61
+ }
62
+
63
+ tab_folder {
64
+ layout_data(:center, :center, true, true)
65
+
66
+ ['℃', '℉'].each do |temp_unit|
67
+ tab_item {
68
+ grid_layout 2, false
69
+
70
+ text temp_unit
71
+ background DEFAULT_BACKGROUND
72
+
73
+ rectangle(0, 0, [:default, -2], [:default, -2], 15, 15) {
74
+ foreground DEFAULT_FOREGROUND
75
+ }
76
+
77
+ %w[temp temp_min temp_max feels_like].each do |field_name|
78
+ temp_field(field_name, temp_unit)
79
+ end
80
+
81
+ humidity_field
82
+ }
83
+ end
84
+ }
85
+ }
86
+ }
87
+
88
+ def temp_field(field_name, temp_unit)
89
+ name_label(field_name)
90
+ label {
91
+ layout_data(:fill, :center, true, false)
92
+ text <= [self, field_name, on_read: ->(t) { "#{kelvin_to_temp_unit(t, temp_unit).to_f.round}°" }]
93
+ font height: DEFAULT_FONT_HEIGHT
94
+ foreground DEFAULT_FOREGROUND
95
+ }
96
+ end
97
+
98
+ def humidity_field
99
+ name_label('humidity')
100
+ label {
101
+ layout_data(:fill, :center, true, false)
102
+ text <= [self, 'humidity', on_read: ->(h) { "#{h.to_f.round}%" }]
103
+ font height: DEFAULT_FONT_HEIGHT
104
+ foreground DEFAULT_FOREGROUND
105
+ }
106
+ end
107
+
108
+ def name_label(field_name)
109
+ label {
110
+ layout_data :fill, :center, false, false
111
+ text field_name.titlecase
112
+ font height: DEFAULT_FONT_HEIGHT
113
+ foreground DEFAULT_FOREGROUND
114
+ }
115
+ end
116
+
117
+ def fetch_weather!
118
+ @weather_mutex.synchronize do
119
+ self.weather_data = JSON.parse(Net::HTTP.get('api.openweathermap.org', "/data/2.5/weather?q=#{city}&appid=1d16d70a9aec3570b5cbd27e6b421330"))
120
+ end
121
+ rescue => e
122
+ Glimmer::Config.logger.error "Unable to fetch weather due to error: #{e.full_message}"
123
+ end
124
+
125
+ def weather_data=(data)
126
+ @weather_data = data
127
+ main_data = data['main']
128
+ # temps come back in Kelvin
129
+ self.temp = main_data['temp']
130
+ self.temp_min = main_data['temp_min']
131
+ self.temp_max = main_data['temp_max']
132
+ self.feels_like = main_data['feels_like']
133
+ self.humidity = main_data['humidity']
134
+ end
135
+
136
+ def kelvin_to_temp_unit(kelvin, temp_unit)
137
+ temp_unit == '℃' ? kelvin_to_celsius(kelvin) : kelvin_to_fahrenheit(kelvin)
138
+ end
139
+
140
+ def kelvin_to_celsius(kelvin)
141
+ return nil if kelvin.nil?
142
+ kelvin - 273.15
143
+ end
144
+
145
+ def celsius_to_fahrenheit(celsius)
146
+ return nil if celsius.nil?
147
+ (celsius * 9 / 5 ) + 32
148
+ end
149
+
150
+ def kelvin_to_fahrenheit(kelvin)
151
+ return nil if kelvin.nil?
152
+ celsius_to_fahrenheit(kelvin_to_celsius(kelvin))
153
+ end
154
+
155
+ end
156
+
157
+ Weather.launch
@@ -20,27 +20,27 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  class HelloButton
23
- include Glimmer
23
+ include Glimmer::UI::CustomShell
24
24
 
25
25
  attr_accessor :count
26
26
 
27
- def initialize
27
+ before_body {
28
28
  @count = 0
29
- end
29
+ }
30
30
 
31
- def launch
31
+ body {
32
32
  shell {
33
33
  text 'Hello, Button!'
34
34
 
35
35
  button {
36
- text bind(self, :count) {|value| "Click To Increment: #{value} "}
36
+ text <= [self, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
37
37
 
38
38
  on_widget_selected {
39
39
  self.count += 1
40
40
  }
41
41
  }
42
- }.open
43
- end
42
+ }
43
+ }
44
44
  end
45
45
 
46
- HelloButton.new.launch
46
+ HelloButton.launch