glimmer-dsl-libui 0.3.5 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +4364 -3406
  4. data/VERSION +1 -1
  5. data/examples/basic_entry.rb +27 -24
  6. data/examples/basic_entry2.rb +31 -0
  7. data/examples/button_counter.rb +27 -0
  8. data/examples/color_the_circles.rb +2 -2
  9. data/examples/form.rb +42 -30
  10. data/examples/form2.rb +37 -0
  11. data/examples/form_table.rb +100 -85
  12. data/examples/form_table2.rb +95 -0
  13. data/examples/login.rb +45 -39
  14. data/examples/login2.rb +55 -0
  15. data/examples/login3.rb +65 -0
  16. data/examples/login4.rb +61 -0
  17. data/examples/login5.rb +43 -0
  18. data/examples/meta_example.rb +10 -7
  19. data/examples/method_based_custom_keyword.rb +8 -15
  20. data/examples/method_based_custom_keyword2.rb +97 -0
  21. data/examples/midi_player.rb +2 -6
  22. data/examples/snake/model/game.rb +2 -2
  23. data/examples/snake/presenter/grid.rb +5 -3
  24. data/examples/snake.rb +11 -21
  25. data/examples/tetris.rb +12 -12
  26. data/examples/tic_tac_toe.rb +3 -12
  27. data/examples/timer.rb +2 -6
  28. data/glimmer-dsl-libui.gemspec +0 -0
  29. data/lib/glimmer/dsl/libui/bind_expression.rb +36 -0
  30. data/lib/glimmer/dsl/libui/data_binding_expression.rb +45 -0
  31. data/lib/glimmer/dsl/libui/dsl.rb +3 -0
  32. data/lib/glimmer/dsl/libui/observe_expression.rb +35 -0
  33. data/lib/glimmer/dsl/libui/shine_data_binding_expression.rb +42 -0
  34. data/lib/glimmer/dsl/libui/string_expression.rb +4 -5
  35. data/lib/glimmer/libui/attributed_string.rb +19 -6
  36. data/lib/glimmer/libui/control_proxy/area_proxy.rb +52 -46
  37. data/lib/glimmer/libui/control_proxy/entry_proxy.rb +5 -0
  38. data/lib/glimmer/libui/control_proxy/image_proxy.rb +4 -5
  39. data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +5 -0
  40. data/lib/glimmer/libui/control_proxy/table_proxy.rb +1 -1
  41. data/lib/glimmer/libui/control_proxy.rb +16 -1
  42. data/lib/glimmer/libui/shape.rb +6 -3
  43. metadata +17 -4
@@ -0,0 +1,55 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Login
4
+ include Glimmer
5
+
6
+ attr_accessor :username, :password, :logged_in
7
+
8
+ def logged_out
9
+ !logged_in
10
+ end
11
+
12
+ def launch
13
+ window('Login') {
14
+ margined true
15
+
16
+ vertical_box {
17
+ form {
18
+ entry {
19
+ label 'Username:'
20
+ text <=> [self, :username]
21
+ enabled <= [self, :logged_out, computed_by: :logged_in] # computed_by option ensures being notified of changes to logged_in
22
+ }
23
+
24
+ password_entry {
25
+ label 'Password:'
26
+ text <=> [self, :password]
27
+ enabled <= [self, :logged_out, computed_by: :logged_in]
28
+ }
29
+ }
30
+
31
+ horizontal_box {
32
+ button('Login') {
33
+ enabled <= [self, :logged_out, computed_by: :logged_in]
34
+
35
+ on_clicked do
36
+ self.logged_in = true
37
+ end
38
+ }
39
+
40
+ button('Logout') {
41
+ enabled <= [self, :logged_in]
42
+
43
+ on_clicked do
44
+ self.logged_in = false
45
+ self.username = ''
46
+ self.password = ''
47
+ end
48
+ }
49
+ }
50
+ }
51
+ }.show
52
+ end
53
+ end
54
+
55
+ Login.new.launch
@@ -0,0 +1,65 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Login
4
+ include Glimmer
5
+
6
+ attr_accessor :username, :password
7
+ attr_reader :logged_in
8
+
9
+ def logged_in=(value)
10
+ @logged_in = value
11
+ self.logged_out = !value # calling logged_out= method notifies logged_out observers
12
+ end
13
+
14
+ def logged_out=(value)
15
+ self.logged_in = !value unless logged_in == !value
16
+ end
17
+
18
+ def logged_out
19
+ !logged_in
20
+ end
21
+
22
+ def launch
23
+ window('Login') {
24
+ margined true
25
+
26
+ vertical_box {
27
+ form {
28
+ entry {
29
+ label 'Username:'
30
+ text <=> [self, :username]
31
+ enabled <= [self, :logged_out]
32
+ }
33
+
34
+ password_entry {
35
+ label 'Password:'
36
+ text <=> [self, :password]
37
+ enabled <= [self, :logged_out]
38
+ }
39
+ }
40
+
41
+ horizontal_box {
42
+ button('Login') {
43
+ enabled <= [self, :logged_out]
44
+
45
+ on_clicked do
46
+ self.logged_in = true
47
+ end
48
+ }
49
+
50
+ button('Logout') {
51
+ enabled <= [self, :logged_in]
52
+
53
+ on_clicked do
54
+ self.logged_in = false
55
+ self.username = ''
56
+ self.password = ''
57
+ end
58
+ }
59
+ }
60
+ }
61
+ }.show
62
+ end
63
+ end
64
+
65
+ Login.new.launch
@@ -0,0 +1,61 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Login
4
+ include Glimmer
5
+
6
+ attr_accessor :username, :password
7
+ attr_reader :logged_in
8
+
9
+ def logged_in=(value)
10
+ @logged_in = value
11
+ notify_observers(:logged_out) # manually notify observers of logged_out upon logged_in changes; this method comes automatically from enhancement as Glimmer::DataBinding::ObservableModel via data-binding
12
+ end
13
+
14
+ def logged_out
15
+ !logged_in
16
+ end
17
+
18
+ def launch
19
+ window('Login') {
20
+ margined true
21
+
22
+ vertical_box {
23
+ form {
24
+ entry {
25
+ label 'Username:'
26
+ text <=> [self, :username]
27
+ enabled <= [self, :logged_out]
28
+ }
29
+
30
+ password_entry {
31
+ label 'Password:'
32
+ text <=> [self, :password]
33
+ enabled <= [self, :logged_out]
34
+ }
35
+ }
36
+
37
+ horizontal_box {
38
+ button('Login') {
39
+ enabled <= [self, :logged_out]
40
+
41
+ on_clicked do
42
+ self.logged_in = true
43
+ end
44
+ }
45
+
46
+ button('Logout') {
47
+ enabled <= [self, :logged_in]
48
+
49
+ on_clicked do
50
+ self.logged_in = false
51
+ self.username = ''
52
+ self.password = ''
53
+ end
54
+ }
55
+ }
56
+ }
57
+ }.show
58
+ end
59
+ end
60
+
61
+ Login.new.launch
@@ -0,0 +1,43 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ include Glimmer
4
+
5
+ window('Login') {
6
+ margined true
7
+
8
+ vertical_box {
9
+ form {
10
+ @username_entry = entry {
11
+ label 'Username:'
12
+ }
13
+
14
+ @password_entry = password_entry {
15
+ label 'Password:'
16
+ }
17
+ }
18
+
19
+ horizontal_box {
20
+ @login_button = button('Login') {
21
+ on_clicked do
22
+ @username_entry.enabled = false
23
+ @password_entry.enabled = false
24
+ @login_button.enabled = false
25
+ @logout_button.enabled = true
26
+ end
27
+ }
28
+
29
+ @logout_button = button('Logout') {
30
+ enabled false
31
+
32
+ on_clicked do
33
+ @username_entry.text = ''
34
+ @password_entry.text = ''
35
+ @username_entry.enabled = true
36
+ @password_entry.enabled = true
37
+ @login_button.enabled = true
38
+ @logout_button.enabled = false
39
+ end
40
+ }
41
+ }
42
+ }
43
+ }.show
@@ -7,8 +7,11 @@ class MetaExample
7
7
 
8
8
  ADDITIONAL_BASIC_EXAMPLES = ['Color Button', 'Font Button', 'Form', 'Date Time Picker', 'Simple Notepad']
9
9
 
10
+ attr_accessor :code_text
11
+
10
12
  def initialize
11
13
  @selected_example_index = examples_with_versions.index(basic_examples_with_versions.first)
14
+ @code_text = File.read(file_path_for(selected_example))
12
15
  end
13
16
 
14
17
  def examples
@@ -40,7 +43,7 @@ class MetaExample
40
43
  end
41
44
 
42
45
  def version_count_for(example)
43
- Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/\d\.rb$/)}.count + 1
46
+ Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/#{example.underscore}\d\.rb$/)}.count + 1
44
47
  end
45
48
 
46
49
  def glimmer_dsl_libui_file
@@ -89,7 +92,7 @@ class MetaExample
89
92
  on_selected do
90
93
  @selected_example_index = examples_with_versions.index(basic_examples_with_versions[@basic_example_radio_buttons.selected])
91
94
  example = selected_example
92
- @code_entry.text = File.read(file_path_for(example))
95
+ self.code_text = File.read(file_path_for(example))
93
96
  @version_spinbox.value = 1
94
97
  end
95
98
  }
@@ -108,7 +111,7 @@ class MetaExample
108
111
  on_selected do
109
112
  @selected_example_index = examples_with_versions.index(advanced_examples_with_versions[@advanced_example_radio_buttons.selected])
110
113
  example = selected_example
111
- @code_entry.text = File.read(file_path_for(example))
114
+ self.code_text = File.read(file_path_for(example))
112
115
  @version_spinbox.value = 1
113
116
  end
114
117
  }
@@ -134,7 +137,7 @@ class MetaExample
134
137
  else
135
138
  version_number = @version_spinbox.value == 1 ? '' : @version_spinbox.value
136
139
  example = "#{selected_example}#{version_number}"
137
- @code_entry.text = File.read(file_path_for(example))
140
+ self.code_text = File.read(file_path_for(example))
138
141
  end
139
142
  end
140
143
  }
@@ -149,7 +152,7 @@ class MetaExample
149
152
  parent_dir = File.join(Dir.home, '.glimmer-dsl-libui', 'examples')
150
153
  FileUtils.mkdir_p(parent_dir)
151
154
  example_file = File.join(parent_dir, "#{selected_example.underscore}.rb")
152
- File.write(example_file, @code_entry.text)
155
+ File.write(example_file, code_text)
153
156
  example_supporting_directory = File.expand_path(selected_example.underscore, __dir__)
154
157
  FileUtils.cp_r(example_supporting_directory, parent_dir) if Dir.exist?(example_supporting_directory)
155
158
  FileUtils.cp_r(File.expand_path('../icons', __dir__), File.dirname(parent_dir))
@@ -164,14 +167,14 @@ class MetaExample
164
167
  }
165
168
  button('Reset') {
166
169
  on_clicked do
167
- @code_entry.text = File.read(file_path_for(selected_example))
170
+ self.code_text = File.read(file_path_for(selected_example))
168
171
  end
169
172
  }
170
173
  }
171
174
  }
172
175
 
173
176
  @code_entry = non_wrapping_multiline_entry {
174
- text File.read(file_path_for(selected_example))
177
+ text <=> [self, :code_text]
175
178
  }
176
179
  }
177
180
  }.show
@@ -5,15 +5,11 @@ include Glimmer
5
5
 
6
6
  Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
7
7
 
8
- def form_field(model, property)
9
- property = property.to_s
8
+ def form_field(model, attribute)
9
+ attribute = attribute.to_s
10
10
  entry { |e|
11
- label property.underscore.split('_').map(&:capitalize).join(' ')
12
- text model.send(property).to_s
13
-
14
- on_changed do
15
- model.send("#{property}=", e.text)
16
- end
11
+ label attribute.underscore.split('_').map(&:capitalize).join(' ')
12
+ text <=> [model, attribute]
17
13
  }
18
14
  end
19
15
 
@@ -28,15 +24,12 @@ def address_form(address)
28
24
  end
29
25
 
30
26
  def label_pair(model, attribute, value)
31
- name_label = nil
32
- value_label = nil
33
27
  horizontal_box {
34
- name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
35
- value_label = label(value.to_s)
28
+ label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
29
+ label(value.to_s) {
30
+ text <= [model, attribute]
31
+ }
36
32
  }
37
- Glimmer::DataBinding::Observer.proc do
38
- value_label.text = model.send(attribute)
39
- end.observe(model, attribute)
40
33
  end
41
34
 
42
35
  def address(address)
@@ -0,0 +1,97 @@
1
+ require 'glimmer-dsl-libui'
2
+ require 'facets'
3
+
4
+ include Glimmer
5
+
6
+ Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
7
+
8
+ def form_field(model, property)
9
+ property = property.to_s
10
+ entry { |e|
11
+ label property.underscore.split('_').map(&:capitalize).join(' ')
12
+ text model.send(property).to_s
13
+
14
+ on_changed do
15
+ model.send("#{property}=", e.text)
16
+ end
17
+ }
18
+ end
19
+
20
+ def address_form(address)
21
+ form {
22
+ form_field(address, :street)
23
+ form_field(address, :p_o_box)
24
+ form_field(address, :city)
25
+ form_field(address, :state)
26
+ form_field(address, :zip_code)
27
+ }
28
+ end
29
+
30
+ def label_pair(model, attribute, value)
31
+ name_label = nil
32
+ value_label = nil
33
+ horizontal_box {
34
+ name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
35
+ value_label = label(value.to_s)
36
+ }
37
+ observe(model, attribute) do
38
+ value_label.text = model.send(attribute)
39
+ end
40
+ end
41
+
42
+ def address(address)
43
+ vertical_box {
44
+ address.each_pair do |attribute, value|
45
+ label_pair(address, attribute, value)
46
+ end
47
+ }
48
+ end
49
+
50
+ address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
51
+ address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
52
+
53
+ window('Method-Based Custom Keyword') {
54
+ margined true
55
+
56
+ horizontal_box {
57
+ vertical_box {
58
+ label('Address 1') {
59
+ stretchy false
60
+ }
61
+
62
+ address_form(address1)
63
+
64
+ horizontal_separator {
65
+ stretchy false
66
+ }
67
+
68
+ label('Address 1 (Saved)') {
69
+ stretchy false
70
+ }
71
+
72
+ address(address1)
73
+ }
74
+
75
+ vertical_separator {
76
+ stretchy false
77
+ }
78
+
79
+ vertical_box {
80
+ label('Address 2') {
81
+ stretchy false
82
+ }
83
+
84
+ address_form(address2)
85
+
86
+ horizontal_separator {
87
+ stretchy false
88
+ }
89
+
90
+ label('Address 2 (Saved)') {
91
+ stretchy false
92
+ }
93
+
94
+ address(address2)
95
+ }
96
+ }
97
+ }.show
@@ -18,12 +18,8 @@ class TinyMidiPlayer
18
18
 
19
19
  def stop_midi
20
20
  if @pid
21
- if @th.alive?
22
- Process.kill(:SIGKILL, @pid)
23
- @pid = nil
24
- else
25
- @pid = nil
26
- end
21
+ Process.kill(:SIGKILL, @pid) if @th.alive?
22
+ @pid = nil
27
23
  end
28
24
  end
29
25
 
@@ -6,8 +6,8 @@ require_relative 'apple'
6
6
  class Snake
7
7
  module Model
8
8
  class Game
9
- WIDTH_DEFAULT = 40
10
- HEIGHT_DEFAULT = 40
9
+ WIDTH_DEFAULT = 20
10
+ HEIGHT_DEFAULT = 20
11
11
  FILE_HIGH_SCORE = File.expand_path(File.join(Dir.home, '.glimmer-snake'))
12
12
 
13
13
  attr_reader :width, :height
@@ -1,10 +1,12 @@
1
- require 'glimmer/data_binding/observer'
1
+ require 'glimmer'
2
2
  require_relative '../model/game'
3
3
  require_relative 'cell'
4
4
 
5
5
  class Snake
6
6
  module Presenter
7
7
  class Grid
8
+ include Glimmer
9
+
8
10
  attr_reader :game, :cells
9
11
 
10
12
  def initialize(game = Model::Game.new)
@@ -14,7 +16,7 @@ class Snake
14
16
  Cell.new(grid: self, row: row, column: column)
15
17
  end
16
18
  end
17
- Glimmer::DataBinding::Observer.proc do |new_vertebrae|
19
+ observe(@game.snake, :vertebrae) do |new_vertebrae|
18
20
  occupied_snake_positions = @game.snake.vertebrae.map {|v| [v.row, v.column]}
19
21
  @cells.each_with_index do |row_cells, row|
20
22
  row_cells.each_with_index do |cell, column|
@@ -27,7 +29,7 @@ class Snake
27
29
  end
28
30
  end
29
31
  end
30
- end.observe(@game.snake, :vertebrae)
32
+ end
31
33
  end
32
34
 
33
35
  def clear
data/examples/snake.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'glimmer-dsl-libui'
2
- require 'glimmer/data_binding/observer'
3
2
 
4
3
  require_relative 'snake/presenter/grid'
5
4
 
6
5
  class Snake
6
+ include Glimmer
7
+
7
8
  CELL_SIZE = 15
8
9
  SNAKE_MOVE_DELAY = 0.1
9
- include Glimmer
10
10
 
11
11
  def initialize
12
12
  @game = Model::Game.new
@@ -21,48 +21,38 @@ class Snake
21
21
  end
22
22
 
23
23
  def register_observers
24
- @game.height.times do |row|
25
- @game.width.times do |column|
26
- Glimmer::DataBinding::Observer.proc do |new_color|
27
- @cell_grid[row][column].fill = new_color
28
- end.observe(@grid.cells[row][column], :color)
29
- end
30
- end
31
-
32
- Glimmer::DataBinding::Observer.proc do |game_over|
24
+ observe(@game, :over) do |game_over|
33
25
  Glimmer::LibUI.queue_main do
34
26
  if game_over
35
27
  msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
36
28
  @game.start
37
29
  end
38
30
  end
39
- end.observe(@game, :over)
31
+ end
40
32
 
41
33
  Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
42
- unless @game.over?
43
- @game.snake.move
44
- @main_window.title = "Glimmer Snake (Score: #{@game.score} | High Score: #{@game.high_score})"
45
- end
34
+ @game.snake.move unless @game.over?
46
35
  end
47
36
  end
48
37
 
49
38
  def create_gui
50
- @cell_grid = []
51
- @main_window = window('Glimmer Snake', @game.width * CELL_SIZE, @game.height * CELL_SIZE) {
39
+ @main_window = window {
40
+ # data-bind window title to game score, converting it to a title string on read from the model
41
+ title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
42
+ content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
52
43
  resizable false
53
44
 
54
45
  vertical_box {
55
46
  padded false
56
47
 
57
48
  @game.height.times do |row|
58
- @cell_grid << []
59
49
  horizontal_box {
60
50
  padded false
61
51
 
62
52
  @game.width.times do |column|
63
53
  area {
64
- @cell_grid.last << square(0, 0, CELL_SIZE) {
65
- fill Presenter::Cell::COLOR_CLEAR
54
+ square(0, 0, CELL_SIZE) {
55
+ fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
66
56
  }
67
57
 
68
58
  on_key_up do |area_key_event|
data/examples/tetris.rb CHANGED
@@ -42,7 +42,7 @@ class Tetris
42
42
  end
43
43
 
44
44
  def register_observers
45
- Glimmer::DataBinding::Observer.proc do |game_over|
45
+ observe(@game, :game_over) do |game_over|
46
46
  if game_over
47
47
  @pause_menu_item.enabled = false
48
48
  show_game_over_dialog
@@ -50,11 +50,11 @@ class Tetris
50
50
  @pause_menu_item.enabled = true
51
51
  start_moving_tetrominos_down
52
52
  end
53
- end.observe(@game, :game_over)
53
+ end
54
54
 
55
55
  Model::Game::PLAYFIELD_HEIGHT.times do |row|
56
56
  Model::Game::PLAYFIELD_WIDTH.times do |column|
57
- Glimmer::DataBinding::Observer.proc do |new_color|
57
+ observe(@game.playfield[row][column], :color) do |new_color|
58
58
  Glimmer::LibUI.queue_main do
59
59
  color = Glimmer::LibUI.interpret_color(new_color)
60
60
  block = @playfield_blocks[row][column]
@@ -65,13 +65,13 @@ class Tetris
65
65
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
66
66
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
67
67
  end
68
- end.observe(@game.playfield[row][column], :color)
68
+ end
69
69
  end
70
70
  end
71
71
 
72
72
  Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
73
73
  Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
74
- Glimmer::DataBinding::Observer.proc do |new_color|
74
+ observe(@game.preview_playfield[row][column], :color) do |new_color|
75
75
  Glimmer::LibUI.queue_main do
76
76
  color = Glimmer::LibUI.interpret_color(new_color)
77
77
  block = @preview_playfield_blocks[row][column]
@@ -82,27 +82,27 @@ class Tetris
82
82
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
83
83
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
84
84
  end
85
- end.observe(@game.preview_playfield[row][column], :color)
85
+ end
86
86
  end
87
87
  end
88
88
 
89
- Glimmer::DataBinding::Observer.proc do |new_score|
89
+ observe(@game, :score) do |new_score|
90
90
  Glimmer::LibUI.queue_main do
91
91
  @score_label.text = new_score.to_s
92
92
  end
93
- end.observe(@game, :score)
93
+ end
94
94
 
95
- Glimmer::DataBinding::Observer.proc do |new_lines|
95
+ observe(@game, :lines) do |new_lines|
96
96
  Glimmer::LibUI.queue_main do
97
97
  @lines_label.text = new_lines.to_s
98
98
  end
99
- end.observe(@game, :lines)
99
+ end
100
100
 
101
- Glimmer::DataBinding::Observer.proc do |new_level|
101
+ observe(@game, :level) do |new_level|
102
102
  Glimmer::LibUI.queue_main do
103
103
  @level_label.text = new_level.to_s
104
104
  end
105
- end.observe(@game, :level)
105
+ end
106
106
  end
107
107
 
108
108
  def menu_bar
@@ -16,17 +16,9 @@ class TicTacToe
16
16
  end
17
17
 
18
18
  def register_observers
19
- Glimmer::DataBinding::Observer.proc do |game_status|
19
+ observe(@tic_tac_toe_board, :game_status) do |game_status|
20
20
  display_win_message if game_status == Board::WIN
21
21
  display_draw_message if game_status == Board::DRAW
22
- end.observe(@tic_tac_toe_board, :game_status)
23
-
24
- 3.times.map do |row|
25
- 3.times.map do |column|
26
- Glimmer::DataBinding::Observer.proc do |sign|
27
- @cells[row][column].string = sign
28
- end.observe(@tic_tac_toe_board[row + 1, column + 1], :sign) # board model is 1-based
29
- end
30
22
  end
31
23
  end
32
24
 
@@ -34,12 +26,10 @@ class TicTacToe
34
26
  @main_window = window('Tic-Tac-Toe', 180, 180) {
35
27
  resizable false
36
28
 
37
- @cells = []
38
29
  vertical_box {
39
30
  padded false
40
31
 
41
32
  3.times.map do |row|
42
- @cells << []
43
33
  horizontal_box {
44
34
  padded false
45
35
 
@@ -49,8 +39,9 @@ class TicTacToe
49
39
  stroke :black, thickness: 2
50
40
  }
51
41
  text(23, 19) {
52
- @cells[row] << string('') {
42
+ string {
53
43
  font family: 'Arial', size: OS.mac? ? 20 : 16
44
+ string <= [@tic_tac_toe_board[row + 1, column + 1], :sign] # board model is 1-based
54
45
  }
55
46
  }
56
47
  on_mouse_up do