glimmer-dsl-libui 0.2.18 → 0.2.22

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.
data/examples/tetris.rb CHANGED
@@ -9,40 +9,55 @@ class Tetris
9
9
  BEVEL_CONSTANT = 20
10
10
  COLOR_GRAY = {r: 192, g: 192, b: 192}
11
11
 
12
- attr_reader :game
13
-
14
12
  def initialize
15
13
  @game = Model::Game.new
16
- create_gui
17
- register_observers
18
14
  end
19
15
 
20
16
  def launch
17
+ create_gui
18
+ register_observers
21
19
  @game.start!
22
20
  @main_window.show
23
21
  end
24
22
 
25
23
  def create_gui
26
- @main_window = window('Glimmer Tetris', Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE) {
27
- playfield(playfield_width: Model::Game::PLAYFIELD_WIDTH, playfield_height: Model::Game::PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
24
+ menu_bar
25
+
26
+ @main_window = window('Glimmer Tetris') {
27
+ content_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE + 98
28
+ resizable false
29
+
30
+ vertical_box {
31
+ label { # filler
32
+ stretchy false
33
+ }
34
+
35
+ score_board(block_size: BLOCK_SIZE) {
36
+ stretchy false
37
+ }
38
+
39
+ @playfield_blocks = playfield(playfield_width: Model::Game::PLAYFIELD_WIDTH, playfield_height: Model::Game::PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
40
+ }
28
41
  }
29
42
  end
30
43
 
31
44
  def register_observers
32
45
  Glimmer::DataBinding::Observer.proc do |game_over|
33
46
  if game_over
47
+ @pause_menu_item.enabled = false
34
48
  show_game_over_dialog
35
49
  else
50
+ @pause_menu_item.enabled = true
36
51
  start_moving_tetrominos_down
37
52
  end
38
53
  end.observe(@game, :game_over)
39
54
 
40
55
  Model::Game::PLAYFIELD_HEIGHT.times do |row|
41
- Model::Game::PLAYFIELD_HEIGHT.times do |column|
56
+ Model::Game::PLAYFIELD_WIDTH.times do |column|
42
57
  Glimmer::DataBinding::Observer.proc do |new_color|
43
58
  Glimmer::LibUI.queue_main do
44
59
  color = Glimmer::LibUI.interpret_color(new_color)
45
- block = @blocks[row][column]
60
+ block = @playfield_blocks[row][column]
46
61
  block[:background_square].fill = color
47
62
  block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
48
63
  block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
@@ -53,27 +68,135 @@ class Tetris
53
68
  end.observe(@game.playfield[row][column], :color)
54
69
  end
55
70
  end
71
+
72
+ Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
73
+ Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
74
+ Glimmer::DataBinding::Observer.proc do |new_color|
75
+ Glimmer::LibUI.queue_main do
76
+ color = Glimmer::LibUI.interpret_color(new_color)
77
+ block = @preview_playfield_blocks[row][column]
78
+ block[:background_square].fill = color
79
+ block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
80
+ block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
81
+ block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
82
+ block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
83
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
84
+ end
85
+ end.observe(@game.preview_playfield[row][column], :color)
86
+ end
87
+ end
88
+
89
+ Glimmer::DataBinding::Observer.proc do |new_score|
90
+ Glimmer::LibUI.queue_main do
91
+ @score_label.text = new_score.to_s
92
+ end
93
+ end.observe(@game, :score)
94
+
95
+ Glimmer::DataBinding::Observer.proc do |new_lines|
96
+ Glimmer::LibUI.queue_main do
97
+ @lines_label.text = new_lines.to_s
98
+ end
99
+ end.observe(@game, :lines)
100
+
101
+ Glimmer::DataBinding::Observer.proc do |new_level|
102
+ Glimmer::LibUI.queue_main do
103
+ @level_label.text = new_level.to_s
104
+ end
105
+ end.observe(@game, :level)
106
+ end
107
+
108
+ def menu_bar
109
+ menu('Game') {
110
+ @pause_menu_item = check_menu_item('Pause') {
111
+ enabled false
112
+
113
+ on_clicked do
114
+ @game.paused = @pause_menu_item.checked?
115
+ end
116
+ }
117
+ menu_item('Restart') {
118
+ on_clicked do
119
+ @game.restart!
120
+ end
121
+ }
122
+ separator_menu_item
123
+ menu_item('Exit') {
124
+ on_clicked do
125
+ exit(0)
126
+ end
127
+ }
128
+ quit_menu_item if OS.mac?
129
+ }
130
+
131
+ menu('View') {
132
+ menu_item('Show High Scores') {
133
+ on_clicked do
134
+ show_high_scores
135
+ end
136
+ }
137
+ menu_item('Clear High Scores') {
138
+ on_clicked {
139
+ @game.clear_high_scores!
140
+ }
141
+ }
142
+ }
143
+
144
+ menu('Options') {
145
+ radio_menu_item('Instant Down on Up Arrow') {
146
+ on_clicked do
147
+ @game.instant_down_on_up = true
148
+ end
149
+ }
150
+ radio_menu_item('Rotate Right on Up Arrow') {
151
+ on_clicked do
152
+ @game.rotate_right_on_up = true
153
+ end
154
+ }
155
+ radio_menu_item('Rotate Left on Up Arrow') {
156
+ on_clicked do
157
+ @game.rotate_left_on_up = true
158
+ end
159
+ }
160
+ }
161
+
162
+ menu('Help') {
163
+ if OS.mac?
164
+ about_menu_item {
165
+ on_clicked do
166
+ show_about_dialog
167
+ end
168
+ }
169
+ end
170
+ menu_item('About') {
171
+ on_clicked do
172
+ show_about_dialog
173
+ end
174
+ }
175
+ }
56
176
  end
57
177
 
58
- def playfield(playfield_width: , playfield_height: , block_size: )
59
- @blocks = []
178
+ def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
179
+ blocks = []
60
180
  vertical_box {
61
181
  padded false
62
182
 
63
183
  playfield_height.times.map do |row|
64
- @blocks << []
184
+ blocks << []
65
185
  horizontal_box {
66
186
  padded false
67
187
 
68
188
  playfield_width.times.map do |column|
69
- @blocks.last << block(row: row, column: column, block_size: block_size)
189
+ blocks.last << block(row: row, column: column, block_size: block_size)
70
190
  end
71
191
  }
72
192
  end
193
+
194
+ extra_content&.call
73
195
  }
196
+ blocks
74
197
  end
75
198
 
76
- def block(row: , column: , block_size: )
199
+ def block(row: , column: , block_size: , &extra_content)
77
200
  block = {}
78
201
  bevel_pixel_size = 0.16 * block_size.to_f
79
202
  color = Glimmer::LibUI.interpret_color(Model::Block::COLOR_CLEAR)
@@ -112,32 +235,89 @@ class Tetris
112
235
  on_key_down do |key_event|
113
236
  case key_event
114
237
  in ext_key: :down
115
- game.down!
238
+ @game.down!
239
+ in key: ' '
240
+ @game.down!(instant: true)
116
241
  in ext_key: :up
117
- case game.up_arrow_action
242
+ case @game.up_arrow_action
118
243
  when :instant_down
119
- game.down!(instant: true)
244
+ @game.down!(instant: true)
120
245
  when :rotate_right
121
- game.rotate!(:right)
246
+ @game.rotate!(:right)
122
247
  when :rotate_left
123
- game.rotate!(:left)
248
+ @game.rotate!(:left)
124
249
  end
125
250
  in ext_key: :left
126
- game.left!
251
+ @game.left!
127
252
  in ext_key: :right
128
- game.right!
253
+ @game.right!
129
254
  in modifier: :shift
130
- game.rotate!(:right)
255
+ @game.rotate!(:right)
131
256
  in modifier: :control
132
- game.rotate!(:left)
257
+ @game.rotate!(:left)
133
258
  else
134
259
  # Do Nothing
135
260
  end
136
261
  end
262
+
263
+ extra_content&.call
137
264
  }
138
265
  block
139
266
  end
140
267
 
268
+ def score_board(block_size: , &extra_content)
269
+ vertical_box {
270
+ horizontal_box {
271
+ label # filler
272
+ @preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: block_size)
273
+ label # filler
274
+ }
275
+
276
+ horizontal_box {
277
+ label # filler
278
+ grid {
279
+ stretchy false
280
+
281
+ label('Score') {
282
+ left 0
283
+ top 0
284
+ halign :fill
285
+ }
286
+ @score_label = label {
287
+ left 0
288
+ top 1
289
+ halign :center
290
+ }
291
+
292
+ label('Lines') {
293
+ left 1
294
+ top 0
295
+ halign :fill
296
+ }
297
+ @lines_label = label {
298
+ left 1
299
+ top 1
300
+ halign :center
301
+ }
302
+
303
+ label('Level') {
304
+ left 2
305
+ top 0
306
+ halign :fill
307
+ }
308
+ @level_label = label {
309
+ left 2
310
+ top 1
311
+ halign :center
312
+ }
313
+ }
314
+ label # filler
315
+ }
316
+
317
+ extra_content&.call
318
+ }
319
+ end
320
+
141
321
  def start_moving_tetrominos_down
142
322
  Glimmer::LibUI.timer(@game.delay) do
143
323
  @game.down! if !@game.game_over? && !@game.paused?
@@ -146,10 +326,29 @@ class Tetris
146
326
 
147
327
  def show_game_over_dialog
148
328
  Glimmer::LibUI.queue_main do
149
- msg_box('Game Over', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
329
+ msg_box('Game Over!', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
150
330
  @game.restart!
151
331
  end
152
332
  end
333
+
334
+ def show_high_scores
335
+ Glimmer::LibUI.queue_main do
336
+ if @game.high_scores.empty?
337
+ high_scores_string = "No games have been scored yet."
338
+ else
339
+ high_scores_string = @game.high_scores.map do |high_score|
340
+ "#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
341
+ end.join("\n")
342
+ end
343
+ msg_box('High Scores', high_scores_string)
344
+ end
345
+ end
346
+
347
+ def show_about_dialog
348
+ Glimmer::LibUI.queue_main do
349
+ msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021 Andy Maleh')
350
+ end
351
+ end
153
352
  end
154
353
 
155
354
  Tetris.new.launch
@@ -0,0 +1,145 @@
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_relative 'cell'
23
+
24
+ class TicTacToe
25
+ class Board
26
+ DRAW = :draw
27
+ IN_PROGRESS = :in_progress
28
+ WIN = :win
29
+ attr :winning_sign
30
+ attr_accessor :game_status
31
+
32
+ def initialize
33
+ @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
34
+ build_grid
35
+ @winning_sign = Cell::EMPTY
36
+ @game_status = IN_PROGRESS
37
+ end
38
+
39
+ #row and column numbers are 1-based
40
+ def mark(row, column)
41
+ self[row, column].mark(current_sign)
42
+ game_over? #updates winning sign
43
+ end
44
+
45
+ def current_sign
46
+ @current_sign = @sign_state_machine[@current_sign]
47
+ end
48
+
49
+ def [](row, column)
50
+ @grid[row-1][column-1]
51
+ end
52
+
53
+ def game_over?
54
+ win? or draw?
55
+ end
56
+
57
+ def win?
58
+ win = (row_win? or column_win? or diagonal_win?)
59
+ self.game_status=WIN if win
60
+ win
61
+ end
62
+
63
+ def reset!
64
+ (1..3).each do |row|
65
+ (1..3).each do |column|
66
+ self[row, column].reset!
67
+ end
68
+ end
69
+ @winning_sign = Cell::EMPTY
70
+ @current_sign = nil
71
+ self.game_status=IN_PROGRESS
72
+ end
73
+
74
+ private
75
+
76
+ def build_grid
77
+ @grid = []
78
+ 3.times do |row_index| #0-based
79
+ @grid << []
80
+ 3.times { @grid[row_index] << Cell.new }
81
+ end
82
+ end
83
+
84
+ def row_win?
85
+ (1..3).each do |row|
86
+ if row_has_same_sign(row)
87
+ @winning_sign = self[row, 1].sign
88
+ return true
89
+ end
90
+ end
91
+ false
92
+ end
93
+
94
+ def column_win?
95
+ (1..3).each do |column|
96
+ if column_has_same_sign(column)
97
+ @winning_sign = self[1, column].sign
98
+ return true
99
+ end
100
+ end
101
+ false
102
+ end
103
+
104
+ #needs refactoring if we ever decide to make the board size dynamic
105
+ def diagonal_win?
106
+ if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
107
+ @winning_sign = self[1, 1].sign
108
+ return true
109
+ end
110
+ if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
111
+ @winning_sign = self[3, 1].sign
112
+ return true
113
+ end
114
+ false
115
+ end
116
+
117
+ def draw?
118
+ @board_full = true
119
+ 3.times do |x|
120
+ 3.times do |y|
121
+ @board_full = false if self[x, y].empty
122
+ end
123
+ end
124
+ self.game_status = DRAW if @board_full
125
+ @board_full
126
+ end
127
+
128
+ def row_has_same_sign(number)
129
+ row_sign = self[number, 1].sign
130
+ [2, 3].each do |column|
131
+ return false unless row_sign == (self[number, column].sign)
132
+ end
133
+ true if self[number, 1].marked
134
+ end
135
+
136
+ def column_has_same_sign(number)
137
+ column_sign = self[1, number].sign
138
+ [2, 3].each do |row|
139
+ return false unless column_sign == (self[row, number].sign)
140
+ end
141
+ true if self[1, number].marked
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,48 @@
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
+ class TicTacToe
23
+ class Cell
24
+ EMPTY = ""
25
+ attr_accessor :sign, :empty
26
+
27
+ def initialize
28
+ reset!
29
+ end
30
+
31
+ def mark(sign)
32
+ self.sign = sign
33
+ end
34
+
35
+ def reset!
36
+ self.sign = EMPTY
37
+ end
38
+
39
+ def sign=(sign_symbol)
40
+ @sign = sign_symbol
41
+ self.empty = sign == EMPTY
42
+ end
43
+
44
+ def marked
45
+ !empty
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,85 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ require_relative "tic_tac_toe/board"
4
+
5
+ class TicTacToe
6
+ include Glimmer
7
+
8
+ def initialize
9
+ @tic_tac_toe_board = Board.new
10
+ end
11
+
12
+ def launch
13
+ create_gui
14
+ register_observers
15
+ @main_window.show
16
+ end
17
+
18
+ def register_observers
19
+ Glimmer::DataBinding::Observer.proc do |game_status|
20
+ display_win_message if game_status == Board::WIN
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
+ end
31
+ end
32
+
33
+ def create_gui
34
+ @main_window = window('Tic-Tac-Toe', 180, 180) {
35
+ resizable false
36
+
37
+ @cells = []
38
+ vertical_box {
39
+ padded false
40
+
41
+ 3.times.map do |row|
42
+ @cells << []
43
+ horizontal_box {
44
+ padded false
45
+
46
+ 3.times.map do |column|
47
+ area {
48
+ path {
49
+ square(0, 0, 60)
50
+
51
+ stroke :black, thickness: 2
52
+ }
53
+ text(23, 19) {
54
+ @cells[row] << string('') {
55
+ font family: 'Arial', size: 20
56
+ }
57
+ }
58
+ on_mouse_up do
59
+ @tic_tac_toe_board.mark(row + 1, column + 1) # board model is 1-based
60
+ end
61
+ }
62
+ end
63
+ }
64
+ end
65
+ }
66
+ }
67
+ end
68
+
69
+ def display_win_message
70
+ display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
71
+ end
72
+
73
+ def display_draw_message
74
+ display_game_over_message("Draw!")
75
+ end
76
+
77
+ def display_game_over_message(message_text)
78
+ Glimmer::LibUI.queue_main do
79
+ msg_box('Game Over', message_text)
80
+ @tic_tac_toe_board.reset!
81
+ end
82
+ end
83
+ end
84
+
85
+ TicTacToe.new.launch
Binary file
@@ -78,6 +78,7 @@ module Glimmer
78
78
  when 'on_destroy'
79
79
  on_destroy(&listener)
80
80
  else
81
+ default_behavior_listener = nil
81
82
  if listener_name == 'on_closing'
82
83
  default_behavior_listener = Proc.new do
83
84
  return_value = listener.call(self)
@@ -90,9 +91,45 @@ module Glimmer
90
91
  end
91
92
  end
92
93
  end
93
- super(listener_name, &default_behavior_listener)
94
+ super(listener_name, &(default_behavior_listener || listener))
94
95
  end
95
96
  end
97
+
98
+ def content_size(*args)
99
+ if args.empty?
100
+ width = Fiddle::Pointer.malloc(8)
101
+ height = Fiddle::Pointer.malloc(8)
102
+ ::LibUI.window_content_size(@libui, width, height)
103
+ width = width[0, 8].unpack1('i')
104
+ height = height[0, 8].unpack1('i')
105
+ [width, height]
106
+ else
107
+ args = args.first if args.size == 1 && args.first.is_a?(Array)
108
+ super
109
+ @width = args[0]
110
+ @height = args[1]
111
+ end
112
+ end
113
+ alias content_size= content_size
114
+ alias set_content_size content_size
115
+
116
+ def resizable(value = nil)
117
+ if value.nil?
118
+ @resizable = true if @resizable.nil?
119
+ @resizable
120
+ else
121
+ @resizable = value
122
+ if !@resizable && !@resizable_listener_registered
123
+ handle_listener('on_content_size_changed') do
124
+ set_content_size(@width, @height) unless @resizable
125
+ end
126
+ @resizable_listener_registered = true
127
+ end
128
+ end
129
+ end
130
+ alias resizable? resizable
131
+ alias resizable= resizable
132
+ alias set_resizable resizable
96
133
 
97
134
  private
98
135
 
@@ -107,6 +144,8 @@ module Glimmer
107
144
  construction_args[2] = DEFAULT_HEIGHT if construction_args.size == 2
108
145
  construction_args[3] = DEFAULT_HAS_MENUBAR if construction_args.size == 3
109
146
  construction_args[3] = Glimmer::LibUI.boolean_to_integer(construction_args[3]) if construction_args.size == 4 && (construction_args[3].is_a?(TrueClass) || construction_args[3].is_a?(FalseClass))
147
+ @width = construction_args[1]
148
+ @height = construction_args[2]
110
149
  @libui = ControlProxy.new_control(@keyword, construction_args)
111
150
  @libui.tap do
112
151
  handle_listener('on_closing') do