glimmer-dsl-swt 4.22.2.1 → 4.22.2.5

Sign up to get free protection for your applications and to get access to all the features.
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
  }