glimmer-dsl-swt 4.18.6.2 → 4.18.7.3

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +4 -4
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +64 -6
  6. data/docs/reference/GLIMMER_SAMPLES.md +71 -0
  7. data/glimmer-dsl-swt.gemspec +16 -6
  8. data/lib/glimmer/dsl/swt/animation_expression.rb +1 -1
  9. data/lib/glimmer/dsl/swt/custom_shape_expression.rb +61 -0
  10. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +1 -1
  11. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  12. data/lib/glimmer/dsl/swt/expand_item_expression.rb +4 -4
  13. data/lib/glimmer/dsl/swt/image_expression.rb +1 -1
  14. data/lib/glimmer/dsl/swt/multiply_expression.rb +1 -1
  15. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  16. data/lib/glimmer/dsl/swt/transform_expression.rb +1 -1
  17. data/lib/glimmer/dsl/swt/widget_expression.rb +2 -1
  18. data/lib/glimmer/swt/custom/shape.rb +473 -180
  19. data/lib/glimmer/swt/custom/shape/image.rb +7 -9
  20. data/lib/glimmer/swt/custom/shape/path.rb +38 -29
  21. data/lib/glimmer/swt/custom/shape/path_segment.rb +21 -19
  22. data/lib/glimmer/swt/custom/shape/polygon.rb +24 -8
  23. data/lib/glimmer/swt/custom/shape/polyline.rb +5 -0
  24. data/lib/glimmer/swt/custom/shape/rectangle.rb +10 -19
  25. data/lib/glimmer/swt/display_proxy.rb +1 -1
  26. data/lib/glimmer/swt/message_box_proxy.rb +1 -1
  27. data/lib/glimmer/swt/shell_proxy.rb +1 -1
  28. data/lib/glimmer/swt/tab_folder_proxy.rb +52 -0
  29. data/lib/glimmer/swt/transform_proxy.rb +1 -1
  30. data/lib/glimmer/swt/widget_proxy.rb +1 -1
  31. data/lib/glimmer/ui/custom_shape.rb +281 -0
  32. data/samples/elaborate/meta_sample.rb +5 -5
  33. data/samples/elaborate/metronome.rb +177 -0
  34. data/samples/elaborate/stock_ticker.rb +0 -6
  35. data/samples/elaborate/tetris.rb +1 -12
  36. data/samples/elaborate/tetris/model/game.rb +3 -0
  37. data/samples/elaborate/tetris/view/bevel.rb +78 -0
  38. data/samples/elaborate/tetris/view/block.rb +6 -29
  39. data/samples/hello/hello_canvas.rb +3 -0
  40. data/samples/hello/hello_canvas_animation_data_binding.rb +66 -0
  41. data/samples/hello/hello_canvas_data_binding.rb +24 -3
  42. data/samples/hello/hello_canvas_path.rb +1 -1
  43. data/samples/hello/hello_custom_shape.rb +78 -0
  44. data/samples/hello/hello_shape.rb +71 -0
  45. data/samples/hello/hello_spinner.rb +7 -2
  46. data/sounds/metronome-down.wav +0 -0
  47. data/sounds/metronome-up.wav +0 -0
  48. metadata +14 -4
@@ -215,7 +215,7 @@ class MetaSampleApplication
215
215
 
216
216
  expand_bar {
217
217
  layout_data(:fill, :fill, true, true)
218
- font height: 30
218
+ font height: 25
219
219
 
220
220
  SampleDirectory.sample_directories.each { |sample_directory|
221
221
  expand_item {
@@ -227,7 +227,7 @@ class MetaSampleApplication
227
227
  fill true
228
228
  }
229
229
  selection bind(sample_directory, :selected_sample_name)
230
- font height: 24
230
+ font height: 20
231
231
  }
232
232
  }
233
233
  }
@@ -236,12 +236,12 @@ class MetaSampleApplication
236
236
  composite {
237
237
  fill_layout
238
238
  layout_data(:fill, :center, true, false) {
239
- height_hint 120
239
+ height_hint 96
240
240
  }
241
241
 
242
242
  button {
243
243
  text 'Launch'
244
- font height: 30
244
+ font height: 25
245
245
  enabled bind(SampleDirectory, 'selected_sample.launchable')
246
246
 
247
247
  on_widget_selected {
@@ -254,7 +254,7 @@ class MetaSampleApplication
254
254
  }
255
255
  button {
256
256
  text 'Reset'
257
- font height: 30
257
+ font height: 25
258
258
  enabled bind(SampleDirectory, 'selected_sample.editable')
259
259
 
260
260
  on_widget_selected {
@@ -0,0 +1,177 @@
1
+ # Copyright (c) 2007-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'
23
+
24
+ class Metronome
25
+ class Beat
26
+ attr_accessor :on
27
+
28
+ def off!
29
+ self.on = false
30
+ end
31
+
32
+ def on!
33
+ self.on = true
34
+ end
35
+ end
36
+
37
+ class Rhythm
38
+ attr_reader :beat_count
39
+ attr_accessor :beats, :bpm
40
+
41
+ def initialize(beat_count)
42
+ self.beat_count = beat_count
43
+ @bpm = 120
44
+ end
45
+
46
+ def beat_count=(value)
47
+ @beat_count = value
48
+ reset_beats!
49
+ end
50
+
51
+ def reset_beats!
52
+ @beats = beat_count.times.map {Beat.new}
53
+ @beats.first.on!
54
+ end
55
+ end
56
+
57
+ include Glimmer::UI::CustomShell
58
+
59
+ import 'javax.sound.sampled'
60
+
61
+ GEM_ROOT = File.expand_path(File.join('..', '..'), __dir__)
62
+ FILE_SOUND_METRONOME_UP = File.join(GEM_ROOT, 'sounds', 'metronome-up.wav')
63
+ FILE_SOUND_METRONOME_DOWN = File.join(GEM_ROOT, 'sounds', 'metronome-down.wav')
64
+
65
+ attr_accessor :rhythm
66
+
67
+ before_body {
68
+ @rhythm = Rhythm.new(4)
69
+ }
70
+
71
+ body {
72
+ shell {
73
+ row_layout(:vertical) {
74
+ center true
75
+ }
76
+ text 'Glimmer Metronome'
77
+
78
+ label {
79
+ text 'Beat Count'
80
+ font height: 30, style: :bold
81
+ }
82
+
83
+ spinner {
84
+ minimum 1
85
+ maximum 64
86
+ selection bind(self, 'rhythm.beat_count', after_write: ->(v) {restart_metronome})
87
+ font height: 30
88
+ }
89
+
90
+ label {
91
+ text 'BPM'
92
+ font height: 30, style: :bold
93
+ }
94
+
95
+ spinner {
96
+ minimum 30
97
+ maximum 1000
98
+ selection bind(self, 'rhythm.bpm')
99
+ font height: 30
100
+ }
101
+
102
+ @beat_container = beat_container
103
+
104
+ on_swt_show {
105
+ start_metronome
106
+ }
107
+
108
+ on_widget_disposed {
109
+ stop_metronome
110
+ }
111
+ }
112
+ }
113
+
114
+ def beat_container
115
+ composite {
116
+ grid_layout(@rhythm.beat_count, true)
117
+
118
+ @rhythm.beat_count.times { |n|
119
+ canvas {
120
+ layout_data {
121
+ width_hint 50
122
+ height_hint 50
123
+ }
124
+ rectangle(0, 0, :default, :default, 36, 36) {
125
+ background bind(self, "rhythm.beats[#{n}].on") {|on| on ? :red : :yellow}
126
+ }
127
+ }
128
+ }
129
+ }
130
+ end
131
+
132
+ def start_metronome
133
+ @thread ||= Thread.new {
134
+ @rhythm.beat_count.times.cycle { |n|
135
+ sleep(60.0/@rhythm.bpm.to_f)
136
+ @rhythm.beats.each(&:off!)
137
+ @rhythm.beats[n].on!
138
+ sound_file = n == 0 ? FILE_SOUND_METRONOME_UP : FILE_SOUND_METRONOME_DOWN
139
+ play_sound(sound_file)
140
+ }
141
+ }
142
+ if @beat_container.nil?
143
+ body_root.content {
144
+ @beat_container = beat_container
145
+ }
146
+ body_root.layout(true, true)
147
+ body_root.pack(true)
148
+ end
149
+ end
150
+
151
+ def stop_metronome
152
+ @thread&.kill # safe since no stored data is involved
153
+ @thread = nil
154
+ @beat_container&.dispose
155
+ @beat_container = nil
156
+ end
157
+
158
+ def restart_metronome
159
+ stop_metronome
160
+ start_metronome
161
+ end
162
+
163
+ # Play sound with the Java Sound library
164
+ def play_sound(sound_file)
165
+ begin
166
+ file_or_stream = java.io.File.new(sound_file)
167
+ audio_stream = AudioSystem.get_audio_input_stream(file_or_stream)
168
+ clip = AudioSystem.clip
169
+ clip.open(audio_stream)
170
+ clip.start
171
+ rescue => e
172
+ puts e.full_message
173
+ end
174
+ end
175
+ end
176
+
177
+ Metronome.launch
@@ -146,7 +146,6 @@ class StockTicker
146
146
  text 'Stock Ticker'
147
147
  minimum_size 650, 650
148
148
  background :white
149
-
150
149
  @tab_folder = tab_folder {
151
150
  @tabs.each do |tab|
152
151
  tab_item {
@@ -202,11 +201,6 @@ class StockTicker
202
201
  on_swt_show {
203
202
  Stock.price_min = 25
204
203
  Stock.price_max = @tabs.first[:canvas].bounds.height - 6
205
- # pre-initialize all tabs by selecting them so that they render content when they are later in the background
206
- @tab_folder.items.each do |item|
207
- @tab_folder.selection = item
208
- end
209
- @tab_folder.selection = @tab_folder.items.first
210
204
  }
211
205
 
212
206
  on_widget_disposed {
@@ -158,18 +158,7 @@ class Tetris
158
158
  y = row * icon_block_size
159
159
  rectangle(x, y, icon_block_size, icon_block_size) {
160
160
  background color
161
- }
162
- polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
163
- background rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
164
- }
165
- polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
166
- background rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
167
- }
168
- polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
169
- background rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
170
- }
171
- polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
172
- background rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
161
+ bevel(base_color: color, size: icon_block_size)
173
162
  }
174
163
  }
175
164
  }
@@ -33,6 +33,8 @@ class Tetris
33
33
  class Game
34
34
  PLAYFIELD_WIDTH = 10
35
35
  PLAYFIELD_HEIGHT = 20
36
+ # PLAYFIELD_WIDTH = 5
37
+ # PLAYFIELD_HEIGHT = 5
36
38
  PREVIEW_PLAYFIELD_WIDTH = 4
37
39
  PREVIEW_PLAYFIELD_HEIGHT = 2
38
40
  SCORE_MULTIPLIER = {1 => 40, 2 => 100, 3 => 300, 4 => 1200}
@@ -199,6 +201,7 @@ class Tetris
199
201
 
200
202
  def delay
201
203
  [1.1 - (level.to_i * 0.1), 0.001].max
204
+ # 99999
202
205
  end
203
206
 
204
207
  def beep
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2007-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
+ # Creates a class-based custom shape representing the `bevel` keyword by convention
23
+ class Tetris
24
+ module View
25
+ class Bevel
26
+ include Glimmer::UI::CustomShape
27
+
28
+ options :base_color, :size, :bevel_pixel_size
29
+
30
+ before_body {
31
+ self.bevel_pixel_size = 0.16*size.to_f if bevel_pixel_size.nil?
32
+ }
33
+
34
+ body {
35
+ shape(0, 0, size, size) {
36
+ polygon(0, 0, size, 0, size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
37
+ background bind(self, :base_color) { |color_value|
38
+ unless color_value.nil?
39
+ color = color(color_value)
40
+ rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
41
+ end
42
+ }
43
+ }
44
+ polygon(size, 0, size - bevel_pixel_size, bevel_pixel_size, size - bevel_pixel_size, size - bevel_pixel_size, size, size) {
45
+ background bind(self, :base_color) { |color_value|
46
+ unless color_value.nil?
47
+ color = color(color_value)
48
+ rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
49
+ end
50
+ }
51
+ }
52
+ polygon(size, size, 0, size, bevel_pixel_size, size - bevel_pixel_size, size - bevel_pixel_size, size - bevel_pixel_size) {
53
+ background bind(self, :base_color) { |color_value|
54
+ unless color_value.nil?
55
+ color = color(color_value)
56
+ rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
57
+ end
58
+ }
59
+ }
60
+ polygon(0, 0, 0, size, bevel_pixel_size, size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
61
+ background bind(self, :base_color) { |color_value|
62
+ unless color_value.nil?
63
+ color = color(color_value)
64
+ rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
65
+ end
66
+ }
67
+ }
68
+ rectangle(0, 0, size, size) {
69
+ foreground bind(self, :base_color) { |color_value|
70
+ # use gray instead of white for the border
71
+ color_value == Model::Block::COLOR_CLEAR ? :gray : color_value
72
+ }
73
+ }
74
+ }
75
+ }
76
+ end
77
+ end
78
+ end
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require_relative 'bevel'
23
+
22
24
  class Tetris
23
25
  module View
24
26
  class Block
@@ -27,36 +29,11 @@ class Tetris
27
29
  options :game_playfield, :block_size, :row, :column
28
30
 
29
31
  body {
30
- canvas {
32
+ canvas { |canvas_proxy|
31
33
  background bind(game_playfield[row][column], :color)
32
- polygon(0, 0, block_size, 0, block_size - 4, 4, 4, 4) {
33
- background bind(game_playfield[row][column], :color) { |color_value|
34
- color = color(color_value)
35
- rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
36
- }
37
- }
38
- polygon(block_size, 0, block_size - 4, 4, block_size - 4, block_size - 4, block_size, block_size) {
39
- background bind(game_playfield[row][column], :color) { |color_value|
40
- color = color(color_value)
41
- rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
42
- }
43
- }
44
- polygon(block_size, block_size, 0, block_size, 4, block_size - 4, block_size - 4, block_size - 4) {
45
- background bind(game_playfield[row][column], :color) { |color_value|
46
- color = color(color_value)
47
- rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
48
- }
49
- }
50
- polygon(0, 0, 0, block_size, 4, block_size - 4, 4, 4) {
51
- background bind(game_playfield[row][column], :color) { |color_value|
52
- color = color(color_value)
53
- rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
54
- }
55
- }
56
- rectangle(0, 0, block_size, block_size) {
57
- foreground bind(game_playfield[row][column], :color) { |color_value|
58
- color_value == Model::Block::COLOR_CLEAR ? :gray : color_value
59
- }
34
+
35
+ bevel(base_color: game_playfield[row][column].color, size: block_size) {
36
+ base_color bind(game_playfield[row][column], :color)
60
37
  }
61
38
  }
62
39
  }
@@ -53,6 +53,9 @@ class HelloCanvas
53
53
  }
54
54
  rectangle(50, 20, 300, 150, 30, 50) {
55
55
  background :magenta
56
+ rectangle(:default, :default, :max, :max, 30, 50) {
57
+ foreground :yellow
58
+ }
56
59
  rectangle([:default, -70], :default, :default, [:default, 1]) {
57
60
  foreground :cyan
58
61
  text {
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2007-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'
23
+ require 'bigdecimal'
24
+
25
+ class HelloAnimationDataBinding
26
+ include Glimmer::UI::CustomShell
27
+
28
+ attr_accessor :delay_time
29
+
30
+ before_body {
31
+ @delay_time = 0.050
32
+ }
33
+
34
+ body {
35
+ shell {
36
+ text 'Hello, Canvas Animation Data Binding!'
37
+ minimum_size 320, 320
38
+
39
+ canvas {
40
+ grid_layout
41
+
42
+ spinner {
43
+ layout_data(:center, :center, true, true) {
44
+ minimum_width 75
45
+ }
46
+ digits 3
47
+ minimum 1
48
+ maximum 100
49
+ selection bind(self, :delay_time, on_read: ->(v) {(BigDecimal(v.to_s)*1000).to_f}, on_write: ->(v) {(BigDecimal(v.to_s)/1000).to_f})
50
+ }
51
+ animation {
52
+ every bind(self, :delay_time)
53
+
54
+ frame { |index|
55
+ background rgb(index%100, index%100 + 100, index%55 + 200)
56
+ oval(index*3%300, index*3%300, 20, 20) {
57
+ background :yellow
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ end
65
+
66
+ HelloAnimationDataBinding.launch