glimmer-dsl-swt 4.22.2.1 → 4.22.2.5

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/README.md +26 -12
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_COMMAND.md +3 -1
  6. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +145 -0
  7. data/docs/reference/GLIMMER_SAMPLES.md +17 -9
  8. data/glimmer-dsl-swt.gemspec +0 -0
  9. data/lib/glimmer/dsl/swt/exec_expression.rb +1 -2
  10. data/lib/glimmer/launcher.rb +7 -4
  11. data/lib/glimmer/rake_task/scaffold.rb +28 -15
  12. data/lib/glimmer/swt/image_proxy.rb +1 -0
  13. data/lib/glimmer/swt/layout_data_proxy.rb +4 -0
  14. data/samples/elaborate/calculator.rb +12 -12
  15. data/samples/elaborate/contact_manager.rb +26 -14
  16. data/samples/elaborate/game_of_life.rb +8 -8
  17. data/samples/elaborate/klondike_solitaire/view/action_panel.rb +2 -2
  18. data/samples/elaborate/klondike_solitaire/view/klondike_solitaire_menu_bar.rb +15 -10
  19. data/samples/elaborate/login.rb +16 -10
  20. data/samples/elaborate/mandelbrot_fractal.rb +26 -20
  21. data/samples/elaborate/meta_sample.rb +6 -6
  22. data/samples/elaborate/metronome.rb +4 -4
  23. data/samples/elaborate/snake/model/apple.rb +33 -0
  24. data/samples/elaborate/snake/model/game.rb +68 -0
  25. data/samples/elaborate/snake/model/snake.rb +95 -0
  26. data/samples/elaborate/snake/model/vertebra.rb +22 -0
  27. data/samples/elaborate/snake/presenter/cell.rb +27 -0
  28. data/samples/elaborate/snake/presenter/grid.rb +49 -0
  29. data/samples/elaborate/snake.rb +103 -0
  30. data/samples/elaborate/stock_ticker.rb +12 -12
  31. data/samples/elaborate/tetris.rb +10 -10
  32. data/samples/elaborate/timer.rb +36 -26
  33. data/samples/elaborate/user_profile.rb +53 -14
  34. data/samples/elaborate/weather.rb +2 -2
  35. data/samples/hello/hello_button.rb +3 -3
  36. data/samples/hello/hello_canvas_animation.rb +2 -2
  37. data/samples/hello/hello_color_dialog.rb +4 -4
  38. data/samples/hello/hello_custom_shell.rb +2 -2
  39. data/samples/hello/hello_dialog.rb +4 -4
  40. data/samples/hello/hello_directory_dialog.rb +2 -2
  41. data/samples/hello/hello_expand_bar.rb +4 -5
  42. data/samples/hello/hello_file_dialog.rb +2 -2
  43. data/samples/hello/hello_font_dialog.rb +2 -2
  44. data/samples/hello/hello_link.rb +5 -4
  45. data/samples/hello/hello_list_multi_selection.rb +3 -1
  46. data/samples/hello/hello_list_single_selection.rb +3 -1
  47. data/samples/hello/hello_menu_bar.rb +28 -28
  48. data/samples/hello/hello_message_box.rb +2 -2
  49. data/samples/hello/hello_pop_up_context_menu.rb +18 -8
  50. data/samples/hello/hello_shell.rb +16 -16
  51. data/samples/hello/hello_styled_text.rb +2 -2
  52. data/samples/hello/hello_table.rb +4 -4
  53. data/samples/hello/hello_tray_item.rb +2 -2
  54. metadata +9 -2
@@ -0,0 +1,27 @@
1
+ class Snake
2
+ module Presenter
3
+ class Cell
4
+ COLOR_CLEAR = :white
5
+ COLOR_SNAKE = :green
6
+ COLOR_APPLE = :red
7
+
8
+ attr_reader :row, :column, :grid
9
+ attr_accessor :color
10
+
11
+ def initialize(grid: ,row: ,column: )
12
+ @row = row
13
+ @column = column
14
+ @grid = grid
15
+ end
16
+
17
+ def clear
18
+ self.color = COLOR_CLEAR unless color == COLOR_CLEAR
19
+ end
20
+
21
+ # inspect is overridden to prevent printing very long stack traces
22
+ def inspect
23
+ "#{super[0, 150]}... >"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ require 'glimmer'
2
+ require_relative '../model/game'
3
+ require_relative 'cell'
4
+
5
+ class Snake
6
+ module Presenter
7
+ class Grid
8
+ include Glimmer
9
+
10
+ attr_reader :game, :cells
11
+
12
+ def initialize(game = Model::Game.new)
13
+ @game = game
14
+ @cells = @game.height.times.map do |row|
15
+ @game.width.times.map do |column|
16
+ Cell.new(grid: self, row: row, column: column)
17
+ end
18
+ end
19
+ observe(@game.snake, :vertebrae) do |new_vertebrae|
20
+ occupied_snake_positions = @game.snake.vertebrae.map {|v| [v.row, v.column]}
21
+ @cells.each_with_index do |row_cells, row|
22
+ row_cells.each_with_index do |cell, column|
23
+ if [@game.apple.row, @game.apple.column] == [row, column]
24
+ cell.color = Cell::COLOR_APPLE
25
+ elsif occupied_snake_positions.include?([row, column])
26
+ cell.color = Cell::COLOR_SNAKE
27
+ else
28
+ cell.clear
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def clear
36
+ @cells.each do |row_cells|
37
+ row_cells.each do |cell|
38
+ cell.clear
39
+ end
40
+ end
41
+ end
42
+
43
+ # inspect is overridden to prevent printing very long stack traces
44
+ def inspect
45
+ "#{super[0, 75]}... >"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,103 @@
1
+ require 'glimmer-dsl-swt'
2
+
3
+ require_relative 'snake/presenter/grid'
4
+
5
+ class Snake
6
+ include Glimmer::UI::CustomShell
7
+
8
+ CELL_SIZE = 15
9
+ SNAKE_MOVE_DELAY = 100 # millis
10
+
11
+ before_body do
12
+ @game = Model::Game.new
13
+ @grid = Presenter::Grid.new(@game)
14
+ @game.start
15
+ @keypress_queue = []
16
+
17
+ display {
18
+ on_swt_keydown do |key_event|
19
+ if key_event.keyCode == 32
20
+ @game.toggle_pause
21
+ else
22
+ @keypress_queue << key_event.keyCode
23
+ end
24
+ end
25
+ }
26
+ end
27
+
28
+ after_body do
29
+ register_observers
30
+ end
31
+
32
+ body {
33
+ shell(:no_resize) {
34
+ grid_layout(@game.width, true) {
35
+ margin_width 0
36
+ margin_height 0
37
+ horizontal_spacing 0
38
+ vertical_spacing 0
39
+ }
40
+
41
+ # data-bind window title to game score, converting it to a title string on read from the model
42
+ text <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
43
+ minimum_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
44
+
45
+ @game.height.times do |row|
46
+ @game.width.times do |column|
47
+ canvas {
48
+ layout_data {
49
+ width_hint CELL_SIZE
50
+ height_hint CELL_SIZE
51
+ }
52
+
53
+ rectangle(0, 0, CELL_SIZE, CELL_SIZE) {
54
+ background <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
55
+ }
56
+ }
57
+ end
58
+ end
59
+ }
60
+ }
61
+
62
+ def register_observers
63
+ observe(@game, :over) do |game_over|
64
+ async_exec do
65
+ if game_over
66
+ message_box {
67
+ text 'Game Over!'
68
+ message "Score: #{@game.score} | High Score: #{@game.high_score}"
69
+ }.open
70
+ @game.start
71
+ end
72
+ end
73
+ end
74
+
75
+ timer_exec(SNAKE_MOVE_DELAY, &method(:move_snake))
76
+ end
77
+
78
+ def move_snake
79
+ unless @game.paused? || @game.over?
80
+ process_queued_keypress
81
+ @game.snake.move
82
+ end
83
+ timer_exec(SNAKE_MOVE_DELAY, &method(:move_snake))
84
+ end
85
+
86
+ def process_queued_keypress
87
+ # key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
88
+ key = @keypress_queue.shift
89
+ if [@game.snake.head.orientation, key] == [:north, swt(:arrow_right)] ||
90
+ [@game.snake.head.orientation, key] == [:east, swt(:arrow_down)] ||
91
+ [@game.snake.head.orientation, key] == [:south, swt(:arrow_left)] ||
92
+ [@game.snake.head.orientation, key] == [:west, swt(:arrow_up)]
93
+ @game.snake.turn_right
94
+ elsif [@game.snake.head.orientation, key] == [:north, swt(:arrow_left)] ||
95
+ [@game.snake.head.orientation, key] == [:west, swt(:arrow_down)] ||
96
+ [@game.snake.head.orientation, key] == [:south, swt(:arrow_right)] ||
97
+ [@game.snake.head.orientation, key] == [:east, swt(:arrow_up)]
98
+ @game.snake.turn_left
99
+ end
100
+ end
101
+ end
102
+
103
+ Snake.launch
@@ -170,42 +170,42 @@ class StockTicker
170
170
  }
171
171
  end
172
172
 
173
- on_mouse_down {
173
+ on_mouse_down do
174
174
  @drag_detected = false
175
- }
175
+ end
176
176
 
177
- on_drag_detected { |drag_detect_event|
177
+ on_drag_detected do |drag_detect_event|
178
178
  @drag_detected = true
179
179
  @drag_start_x = drag_detect_event.x
180
180
  @drag_start_y = drag_detect_event.y
181
- }
181
+ end
182
182
 
183
- on_mouse_move { |mouse_event|
183
+ on_mouse_move do |mouse_event|
184
184
  if @drag_detected
185
185
  origin = tab[:scrolled_composite].origin
186
186
  new_x = origin.x - (mouse_event.x - @drag_start_x)
187
187
  new_y = origin.y - (mouse_event.y - @drag_start_y)
188
188
  tab[:scrolled_composite].set_origin(new_x, new_y)
189
189
  end
190
- }
190
+ end
191
191
 
192
- on_mouse_up { |mouse_event|
192
+ on_mouse_up do |mouse_event|
193
193
  @drag_detected = false
194
- }
194
+ end
195
195
  }
196
196
  }
197
197
  }
198
198
  end
199
199
  }
200
200
 
201
- on_swt_show {
201
+ on_swt_show do
202
202
  Stock.price_min = 25
203
203
  Stock.price_max = @tabs.first[:canvas].bounds.height - 6
204
- }
204
+ end
205
205
 
206
- on_widget_disposed {
206
+ on_widget_disposed do
207
207
  @thread.kill # safe to kill as data is in memory only
208
- }
208
+ end
209
209
  }
210
210
  }
211
211
  end
@@ -54,7 +54,7 @@ class Tetris
54
54
  Display.app_name = 'Glimmer Tetris'
55
55
 
56
56
  display {
57
- on_swt_keydown { |key_event|
57
+ on_swt_keydown do |key_event|
58
58
  case key_event.keyCode
59
59
  when swt(:arrow_down), 's'.bytes.first
60
60
  if OS.mac?
@@ -88,16 +88,16 @@ class Tetris
88
88
  game.rotate!(:left)
89
89
  end
90
90
  end
91
- }
91
+ end
92
92
 
93
93
  # if running in app mode, set the Mac app about dialog (ignored in platforms)
94
- on_about {
94
+ on_about do
95
95
  show_about_dialog
96
- }
96
+ end
97
97
 
98
- on_quit {
98
+ on_quit do
99
99
  exit(0)
100
- }
100
+ end
101
101
  }
102
102
  end
103
103
 
@@ -150,15 +150,15 @@ class Tetris
150
150
  icon_size = 8
151
151
  icon_pixel_size = icon_block_size * icon_size
152
152
  image(icon_pixel_size, icon_pixel_size) {
153
- icon_size.times { |row|
154
- icon_size.times { |column|
153
+ icon_size.times do |row|
154
+ icon_size.times do |column|
155
155
  colored = row >= 1 && column.between?(1, 6)
156
156
  color = colored ? color(([:white] + Model::Tetromino::LETTER_COLORS.values).sample) : color(:white)
157
157
  x = column * icon_block_size
158
158
  y = row * icon_block_size
159
159
  bevel(x: x, y: y, base_color: color, size: icon_block_size)
160
- }
161
- }
160
+ end
161
+ end
162
162
  }
163
163
  end
164
164
 
@@ -24,12 +24,13 @@ class Timer
24
24
  Display.setAppName('Glimmer Timer')
25
25
 
26
26
  @display = display {
27
- on_about {
27
+ on_about do
28
28
  display_about_dialog
29
- }
30
- on_preferences {
29
+ end
30
+
31
+ on_preferences do
31
32
  display_about_dialog
32
- }
33
+ end
33
34
  }
34
35
 
35
36
  @min = 0
@@ -43,7 +44,7 @@ class Timer
43
44
  loop do
44
45
  sleep(1)
45
46
  if @countdown
46
- sync_exec {
47
+ sync_exec do
47
48
  @countdown_time = Time.new(1, 1, 1, 0, min, sec)
48
49
  @countdown_time -= 1
49
50
  self.min = @countdown_time.min
@@ -52,7 +53,7 @@ class Timer
52
53
  stop_countdown
53
54
  play_countdown_done_sound
54
55
  end
55
- }
56
+ end
56
57
  end
57
58
  end
58
59
  end
@@ -85,31 +86,34 @@ class Timer
85
86
  accelerator COMMAND_KEY, 's'
86
87
  enabled <= [self, :countdown, on_read: :!]
87
88
 
88
- on_widget_selected {
89
+ on_widget_selected do
89
90
  start_countdown
90
- }
91
+ end
91
92
  }
93
+
92
94
  menu_item {
93
95
  text 'St&op'
94
96
  enabled <= [self, :countdown]
95
97
  accelerator COMMAND_KEY, 'o'
96
98
 
97
- on_widget_selected {
99
+ on_widget_selected do
98
100
  stop_countdown
99
- }
101
+ end
100
102
  }
103
+
101
104
  unless OS.mac?
102
105
  menu_item(:separator)
103
106
  menu_item {
104
107
  text 'E&xit'
105
108
  accelerator :alt, :f4
106
109
 
107
- on_widget_selected {
110
+ on_widget_selected do
108
111
  exit(0)
109
- }
112
+ end
110
113
  }
111
114
  end
112
115
  }
116
+
113
117
  menu {
114
118
  text '&Help'
115
119
 
@@ -117,9 +121,9 @@ class Timer
117
121
  text '&About'
118
122
  accelerator COMMAND_KEY, :shift, 'a'
119
123
 
120
- on_widget_selected {
124
+ on_widget_selected do
121
125
  display_about_dialog
122
- }
126
+ end
123
127
  }
124
128
  }
125
129
  }
@@ -149,9 +153,10 @@ class Timer
149
153
  maximum 59
150
154
  selection <=> [self, :min]
151
155
  enabled <= [self, :countdown, on_read: :!]
152
- on_widget_default_selected {
156
+
157
+ on_widget_default_selected do
153
158
  start_countdown
154
- }
159
+ end
155
160
  }
156
161
  label {
157
162
  text ':'
@@ -163,9 +168,10 @@ class Timer
163
168
  maximum 59
164
169
  selection <=> [self, :sec]
165
170
  enabled <= [self, :countdown, on_read: :!]
166
- on_widget_default_selected {
171
+
172
+ on_widget_default_selected do
167
173
  start_countdown
168
- }
174
+ end
169
175
  }
170
176
  }
171
177
  end
@@ -179,22 +185,26 @@ class Timer
179
185
  @start_button = button {
180
186
  text '&Start'
181
187
  enabled <= [self, :countdown, on_read: :!]
182
- on_widget_selected {
188
+
189
+ on_widget_selected do
183
190
  start_countdown
184
- }
185
- on_key_pressed { |event|
191
+ end
192
+
193
+ on_key_pressed do |event|
186
194
  start_countdown if event.keyCode == swt(:cr)
187
- }
195
+ end
188
196
  }
189
197
  @stop_button = button {
190
198
  text 'St&op'
191
199
  enabled <= [self, :countdown]
192
- on_widget_selected {
200
+
201
+ on_widget_selected do
193
202
  stop_countdown
194
- }
195
- on_key_pressed { |event|
203
+ end
204
+
205
+ on_key_pressed do |event|
196
206
  stop_countdown if event.keyCode == swt(:cr)
197
- }
207
+ end
198
208
  }
199
209
  }
200
210
  end
@@ -32,49 +32,88 @@ shell { |shell_proxy|
32
32
  grid_layout 2, false
33
33
 
34
34
  group {
35
- text "Name"
36
35
  grid_layout 2, false
36
+
37
37
  layout_data :fill, :fill, true, true
38
- label {text "First"}; text {text "Bullet"}
39
- label {text "Last"}; text {text "Tooth"}
38
+ text "Name"
39
+
40
+ label {
41
+ text "First"
42
+ }
43
+ text {
44
+ text "Bullet"
45
+ }
46
+
47
+ label {
48
+ text "Last"
49
+ }
50
+ text {
51
+ text "Tooth"
52
+ }
40
53
  }
41
54
 
42
55
  group {
43
56
  layout_data :fill, :fill, true, true
44
57
  text "Gender"
45
- radio {text "Male"; selection true}
46
- radio {text "Female"}
58
+
59
+ radio {
60
+ text "Male"
61
+ selection true
62
+ }
63
+
64
+ radio {
65
+ text "Female"
66
+ }
47
67
  }
48
68
 
49
69
  group {
50
70
  layout_data :fill, :fill, true, true
51
71
  text "Role"
52
- check {text "Student"; selection true}
53
- check {text "Employee"; selection true}
72
+
73
+ check {
74
+ text "Student"
75
+ selection true
76
+ }
77
+
78
+ check {
79
+ text "Employee"
80
+ selection true
81
+ }
54
82
  }
55
83
 
56
84
  group {
57
- text "Experience"
58
85
  row_layout
86
+
59
87
  layout_data :fill, :fill, true, true
60
- spinner {selection 5}; label {text "years"}
88
+ text "Experience"
89
+
90
+ spinner {
91
+ selection 5
92
+ }
93
+ label {
94
+ text "years"
95
+ }
61
96
  }
62
97
 
63
98
  button {
64
- text "save"
65
99
  layout_data :right, :center, true, true
66
- on_widget_selected {
100
+ text "save"
101
+
102
+ on_widget_selected do
67
103
  message_box {
68
104
  text 'Profile Saved!'
69
105
  message 'User profile has been saved!'
70
106
  }.open
71
- }
107
+ end
72
108
  }
73
109
 
74
110
  button {
75
- text "close"
76
111
  layout_data :left, :center, true, true
77
- on_widget_selected { shell_proxy.close }
112
+ text "close"
113
+
114
+ on_widget_selected do
115
+ shell_proxy.close
116
+ end
78
117
  }
79
118
  }
80
119
  }.open
@@ -62,13 +62,13 @@ class Weather
62
62
 
63
63
  text <=> [self, :city]
64
64
 
65
- on_key_pressed {|event|
65
+ on_key_pressed do |event|
66
66
  if event.keyCode == swt(:cr) # carriage return
67
67
  Thread.new do
68
68
  fetch_weather!
69
69
  end
70
70
  end
71
- }
71
+ end
72
72
  }
73
73
 
74
74
  tab_folder {
@@ -27,7 +27,7 @@ class HelloButton
27
27
  attr_accessor :count
28
28
 
29
29
  before_body do
30
- @count = 0
30
+ self.count = 0
31
31
  end
32
32
 
33
33
  body {
@@ -37,9 +37,9 @@ class HelloButton
37
37
  button {
38
38
  text <= [self, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
39
39
 
40
- on_widget_selected {
40
+ on_widget_selected do
41
41
  self.count += 1
42
- }
42
+ end
43
43
  }
44
44
  }
45
45
  }
@@ -123,12 +123,12 @@ class HelloCanvasAnimation
123
123
  started <=> [self, :animation_started]
124
124
  finished <=> [self, :animation_finished]
125
125
 
126
- frame { |index|
126
+ frame do |index|
127
127
  background rgb(index%100, index%100 + 100, index%55 + 200)
128
128
  oval(index*3%300, index*3%300, 20, 20) {
129
129
  background :yellow
130
130
  }
131
- }
131
+ end
132
132
  }
133
133
  }
134
134
  }
@@ -47,18 +47,18 @@ class HelloColorDialog
47
47
  layout_data :center, :center, true, false
48
48
  background <=> [self, :selected_color]
49
49
 
50
- on_mouse_up {
50
+ on_mouse_up do
51
51
  self.selected_color = color_dialog.open
52
- }
52
+ end
53
53
  }
54
54
 
55
55
  button {
56
56
  layout_data :center, :center, true, false
57
57
  text "Choose Color..."
58
58
 
59
- on_widget_selected {
59
+ on_widget_selected do
60
60
  self.selected_color = color_dialog.open
61
- }
61
+ end
62
62
  }
63
63
 
64
64
  }
@@ -140,7 +140,7 @@ class HelloCustomShell
140
140
 
141
141
  items <=> [@email_system, :emails, column_properties: [:date, :subject, :from]]
142
142
 
143
- on_mouse_up { |event|
143
+ on_mouse_up do |event|
144
144
  email = event.table_item.get_data
145
145
 
146
146
  # open a custom email shell
@@ -151,7 +151,7 @@ class HelloCustomShell
151
151
  from: email.from,
152
152
  message: email.message
153
153
  ).open
154
- }
154
+ end
155
155
  }
156
156
  }.open
157
157
  end
@@ -38,7 +38,7 @@ shell { |shell_proxy|
38
38
  }
39
39
  text "Dialog #{dialog_number}"
40
40
 
41
- on_widget_selected {
41
+ on_widget_selected do
42
42
  # pass the shell proxy as a parent to make the dialog support hitting the escape button for closing alone without closing app
43
43
  dialog(shell_proxy) { |dialog_proxy|
44
44
  row_layout(:vertical) {
@@ -70,12 +70,12 @@ shell { |shell_proxy|
70
70
  button {
71
71
  text 'Close'
72
72
 
73
- on_widget_selected {
73
+ on_widget_selected do
74
74
  dialog_proxy.close
75
- }
75
+ end
76
76
  }
77
77
  }.open
78
- }
78
+ end
79
79
  }
80
80
  }
81
81
  }.open
@@ -51,9 +51,9 @@ class HelloDirectoryDialog
51
51
  button {
52
52
  text "Browse..."
53
53
 
54
- on_widget_selected {
54
+ on_widget_selected do
55
55
  self.selected_directory = directory_dialog.open
56
- }
56
+ end
57
57
  }
58
58
  }
59
59
  }
@@ -96,14 +96,13 @@ class HelloExpandBar
96
96
  composite # just filler
97
97
  }
98
98
 
99
- on_item_expanded { |expand_event|
99
+ on_item_expanded do |expand_event|
100
100
  @status_label.text = "#{expand_event.item.text} Expanded!"
101
- }
101
+ end
102
102
 
103
- on_item_collapsed { |expand_event|
103
+ on_item_collapsed do |expand_event|
104
104
  @status_label.text = "#{expand_event.item.text} Collapsed!"
105
- }
106
-
105
+ end
107
106
  }
108
107
  }
109
108
  }