glimmer-dsl-swt 4.18.1.1 → 4.18.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -45,7 +45,7 @@ module Glimmer
45
45
  class << self
46
46
  # Returns singleton instance
47
47
  def instance(*args)
48
- if @instance.nil? || @instance.swt_display.isDisposed
48
+ if @instance.nil? || @instance.swt_display.nil? || @instance.swt_display.isDisposed
49
49
  @instance = new(*args)
50
50
  end
51
51
  @instance
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2021 Andy Maleh
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -46,6 +46,7 @@ module Glimmer
46
46
  @swt_widget = swt_widget
47
47
  else
48
48
  if args.first.is_a?(ShellProxy)
49
+ @parent_proxy = args[0]
49
50
  args[0] = args[0].swt_widget
50
51
  end
51
52
  style_args = args.select {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
@@ -78,7 +79,7 @@ module Glimmer
78
79
  end
79
80
 
80
81
  # Centers shell within monitor it is in
81
- def center
82
+ def center_within_display
82
83
  primary_monitor = @display.getPrimaryMonitor()
83
84
  monitor_bounds = primary_monitor.getBounds()
84
85
  shell_bounds = @swt_widget.getBounds()
@@ -101,7 +102,7 @@ module Glimmer
101
102
  else
102
103
  @opened_before = true
103
104
  @swt_widget.pack
104
- center
105
+ center_within_display
105
106
  @swt_widget.open
106
107
  end
107
108
  end
@@ -74,12 +74,10 @@ module Glimmer
74
74
 
75
75
  DEFAULT_INITIALIZERS = {
76
76
  composite: lambda do |composite|
77
- if composite.get_layout.nil?
78
- layout = GridLayout.new
79
- layout.marginWidth = 15
80
- layout.marginHeight = 15
81
- composite.layout = layout
82
- end
77
+ composite.layout = GridLayout.new if composite.get_layout.nil?
78
+ end,
79
+ canvas: lambda do |canvas|
80
+ canvas.layout = nil unless canvas.get_layout.nil?
83
81
  end,
84
82
  scrolled_composite: lambda do |scrolled_composite|
85
83
  scrolled_composite.expand_horizontal = true
@@ -160,7 +158,7 @@ module Glimmer
160
158
  underscored_widget_name = self.class.underscored_widget_name(@swt_widget)
161
159
  parent_proxy_class = self.class.widget_proxy_class(self.class.underscored_widget_name(@swt_widget.parent))
162
160
  parent = swt_widget.parent
163
- @parent_proxy = parent.get_data('proxy') || parent_proxy_class.new(swt_widget: parent)
161
+ @parent_proxy = parent&.get_data('proxy') || parent_proxy_class.new(swt_widget: parent)
164
162
  end
165
163
  if @swt_widget&.get_data('proxy').nil?
166
164
  @swt_widget.set_data('proxy', self)
@@ -27,6 +27,19 @@ module Glimmer
27
27
  include SuperModule
28
28
  include Glimmer::UI::CustomWidget
29
29
 
30
+ class << self
31
+ attr_reader :custom_shell
32
+
33
+ def launch
34
+ @custom_shell = send(self.name.underscore.gsub('::', '__'))
35
+ @custom_shell.open
36
+ end
37
+
38
+ def shutdown
39
+ @custom_shell.close
40
+ end
41
+ end
42
+
30
43
  def initialize(parent, *swt_constants, options, &content)
31
44
  super
32
45
  @swt_widget.set_data('custom_shell', self)
@@ -55,8 +68,8 @@ module Glimmer
55
68
  body_root.visible?
56
69
  end
57
70
 
58
- def center
59
- body_root.center
71
+ def center_within_display
72
+ body_root.center_within_display
60
73
  end
61
74
 
62
75
  def start_event_loop
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2021 Andy Maleh
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -141,10 +141,9 @@ module Glimmer
141
141
  end
142
142
  end
143
143
 
144
- attr_reader :body_root, :swt_widget, :parent, :swt_style, :options
144
+ attr_reader :body_root, :swt_widget, :parent, :parent_proxy, :swt_style, :options
145
145
 
146
146
  def initialize(parent, *swt_constants, options, &content)
147
- @parent = parent
148
147
  @swt_style = SWT::SWTProxy[*swt_constants]
149
148
  options ||= {}
150
149
  @options = self.class.options.merge(options)
@@ -156,6 +155,9 @@ module Glimmer
156
155
  raise Glimmer::Error, 'Invalid custom widget for having an empty body! Please fill body block!' if @body_root.nil?
157
156
  @swt_widget = @body_root.swt_widget
158
157
  @swt_widget.set_data('custom_widget', self)
158
+ @parent = parent
159
+ @parent ||= @swt_widget.parent
160
+ @parent_proxy ||= @parent&.get_data('proxy')
159
161
  execute_hooks('after_body')
160
162
  end
161
163
 
@@ -211,10 +213,10 @@ module Glimmer
211
213
 
212
214
  # This method ensures it has an instance method not coming from Glimmer DSL
213
215
  def has_instance_method?(method_name)
214
- respond_to?(method_name) and
216
+ respond_to?(method_name) and
215
217
  !swt_widget&.respond_to?(method_name) and
216
218
  (method(method_name) rescue nil) and
217
- !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
219
+ !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
218
220
  !method(method_name)&.source_location&.first&.include?('glimmer/swt/widget_proxy.rb')
219
221
  end
220
222
 
@@ -265,13 +267,13 @@ module Glimmer
265
267
  end
266
268
  end
267
269
 
268
- alias local_respond_to? respond_to?
270
+ alias local_respond_to? respond_to?
269
271
  def respond_to?(method, *args, &block)
270
272
  super or
271
273
  can_handle_observation_request?(method) or
272
274
  body_root.respond_to?(method, *args, &block)
273
275
  end
274
-
276
+
275
277
  private
276
278
 
277
279
  def execute_hooks(hook_name)
@@ -1,3 +1,24 @@
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
+
1
22
  require 'fileutils'
2
23
  require 'etc'
3
24
 
@@ -0,0 +1,108 @@
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
+ # Tetris App View Custom Shell (represents `tetris` keyword)
23
+
24
+ require_relative 'tetris/model/game'
25
+
26
+ require_relative 'tetris/view/playfield'
27
+ require_relative 'tetris/view/score_lane'
28
+ require_relative 'tetris/view/game_over_dialog'
29
+
30
+ class Tetris
31
+ include Glimmer::UI::CustomShell
32
+
33
+ BLOCK_SIZE = 25
34
+ PLAYFIELD_WIDTH = 10
35
+ PLAYFIELD_HEIGHT = 20
36
+ PREVIEW_PLAYFIELD_WIDTH = 4
37
+ PREVIEW_PLAYFIELD_HEIGHT = 2
38
+
39
+ before_body {
40
+ display {
41
+ on_swt_keydown { |key_event|
42
+ case key_event.keyCode
43
+ when swt(:arrow_down)
44
+ Model::Game.current_tetromino.down
45
+ when swt(:arrow_left)
46
+ Model::Game.current_tetromino.left
47
+ when swt(:arrow_right)
48
+ Model::Game.current_tetromino.right
49
+ when swt(:shift)
50
+ if key_event.keyLocation == swt(:right) # right shift key
51
+ Model::Game.current_tetromino.rotate(:right)
52
+ elsif key_event.keyLocation == swt(:left) # left shift key
53
+ Model::Game.current_tetromino.rotate(:left)
54
+ end
55
+ when 'd'.bytes.first, swt(:arrow_up)
56
+ Model::Game.current_tetromino.rotate(:right)
57
+ when 'a'.bytes.first
58
+ Model::Game.current_tetromino.rotate(:left)
59
+ end
60
+ }
61
+ }
62
+
63
+ Model::Game.configure_beeper do
64
+ async_exec {
65
+ display.beep
66
+ }
67
+ end
68
+ }
69
+
70
+ after_body {
71
+ Model::Game.start
72
+
73
+ Thread.new {
74
+ loop {
75
+ sleep(Model::Game.delay)
76
+ sync_exec {
77
+ unless Model::Game.game_over?
78
+ Model::Game.current_tetromino.down
79
+ game_over_dialog(parent_shell: body_root).open if Model::Game.current_tetromino.row <= 0 && Model::Game.current_tetromino.stopped?
80
+ end
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ body {
87
+ shell(:no_resize) {
88
+ grid_layout {
89
+ num_columns 2
90
+ make_columns_equal_width false
91
+ margin_width 0
92
+ margin_height 0
93
+ horizontal_spacing 0
94
+ }
95
+
96
+ text 'Glimmer Tetris'
97
+ background :gray
98
+
99
+ playfield(game_playfield: Model::Game.playfield, playfield_width: PLAYFIELD_WIDTH, playfield_height: PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
100
+
101
+ score_lane(block_size: BLOCK_SIZE) {
102
+ layout_data(:fill, :fill, false, true)
103
+ }
104
+ }
105
+ }
106
+ end
107
+
108
+ Tetris.launch
@@ -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 Tetris
23
+ module Model
24
+ class Block
25
+ COLOR_CLEAR = :white
26
+
27
+ attr_accessor :color
28
+
29
+ # Initializes with color. Default color (gray) signifies an empty block
30
+ def initialize(color = COLOR_CLEAR)
31
+ @color = color
32
+ end
33
+
34
+ # Clears block color. `quietly` option indicates if it should not notify observers by setting value quietly via variable not attribute writer.
35
+ def clear
36
+ self.color = COLOR_CLEAR
37
+ end
38
+
39
+ def clear?
40
+ self.color == COLOR_CLEAR
41
+ end
42
+
43
+ def occupied?
44
+ !clear?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,185 @@
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 'block'
23
+ require_relative 'tetromino'
24
+
25
+ class Tetris
26
+ module Model
27
+ class Game
28
+ SCORE_MULTIPLIER = {1 => 40, 2 => 100, 3 => 300, 4 => 1200}
29
+
30
+ class << self
31
+ attr_accessor :game_over, :preview_tetromino, :lines, :score, :level
32
+ alias game_over? game_over
33
+
34
+ def consider_adding_tetromino
35
+ if tetrominoes.empty? || Game.current_tetromino.stopped?
36
+ preview_tetromino.launch!
37
+ preview_next_tetromino!
38
+ end
39
+ end
40
+
41
+ def current_tetromino
42
+ tetrominoes.last
43
+ end
44
+
45
+ def tetrominoes
46
+ @tetrominoes ||= reset_tetrominoes
47
+ end
48
+
49
+ # Returns blocks in the playfield
50
+ def playfield
51
+ @playfield ||= @original_playfield = PLAYFIELD_HEIGHT.times.map {
52
+ PLAYFIELD_WIDTH.times.map {
53
+ Block.new
54
+ }
55
+ }
56
+ end
57
+
58
+ def hypothetical(&block)
59
+ @playfield = hypothetical_playfield
60
+ block.call
61
+ @playfield = @original_playfield
62
+ end
63
+
64
+ def hypothetical?
65
+ @playfield != @original_playfield
66
+ end
67
+
68
+ def hypothetical_playfield
69
+ PLAYFIELD_HEIGHT.times.map { |row|
70
+ PLAYFIELD_WIDTH.times.map { |column|
71
+ playfield[row][column].clone
72
+ }
73
+ }
74
+ end
75
+
76
+ def preview_playfield
77
+ @preview_playfield ||= PREVIEW_PLAYFIELD_HEIGHT.times.map {|row|
78
+ PREVIEW_PLAYFIELD_WIDTH.times.map {|column|
79
+ Block.new
80
+ }
81
+ }
82
+ end
83
+
84
+ def preview_next_tetromino!
85
+ self.preview_tetromino = Tetromino.new
86
+ end
87
+
88
+ def calculate_score!(eliminated_lines)
89
+ new_score = SCORE_MULTIPLIER[eliminated_lines] * (level + 1)
90
+ self.score += new_score
91
+ end
92
+
93
+ def level_up!
94
+ self.level += 1 if lines >= self.level*10
95
+ end
96
+
97
+ def delay
98
+ [1.1 - (level.to_i * 0.1), 0.001].max
99
+ end
100
+
101
+ def consider_eliminating_lines
102
+ eliminated_lines = 0
103
+ playfield.each_with_index do |row, playfield_row|
104
+ if row.all? {|block| !block.clear?}
105
+ eliminated_lines += 1
106
+ shift_blocks_down_above_row(playfield_row)
107
+ end
108
+ end
109
+ if eliminated_lines > 0
110
+ beep
111
+ self.lines += eliminated_lines
112
+ level_up!
113
+ calculate_score!(eliminated_lines)
114
+ end
115
+ end
116
+
117
+ def beep
118
+ @beeper&.call
119
+ end
120
+
121
+ def configure_beeper(&beeper)
122
+ @beeper = beeper
123
+ end
124
+
125
+ def shift_blocks_down_above_row(row)
126
+ row.downto(0) do |playfield_row|
127
+ playfield[playfield_row].each_with_index do |block, playfield_column|
128
+ previous_row = playfield[playfield_row - 1]
129
+ previous_block = previous_row[playfield_column]
130
+ block.color = previous_block.color
131
+ end
132
+ end
133
+ playfield[0].each(&:clear)
134
+ end
135
+
136
+ def start
137
+ self.level = 1
138
+ self.score = 0
139
+ self.lines = @previoius_lines = 0
140
+ reset_playfield
141
+ reset_preview_playfield
142
+ reset_tetrominoes
143
+ preview_next_tetromino!
144
+ consider_adding_tetromino
145
+ self.game_over = false
146
+ end
147
+ alias restart start
148
+
149
+ def reset_tetrominoes
150
+ @tetrominoes = []
151
+ end
152
+
153
+ def reset_playfield
154
+ playfield.each do |row|
155
+ row.each do |block|
156
+ block.clear
157
+ end
158
+ end
159
+ end
160
+
161
+ def reset_preview_playfield
162
+ preview_playfield.each do |row|
163
+ row.each do |block|
164
+ block.clear
165
+ end
166
+ end
167
+ end
168
+
169
+ def playfield_remaining_heights(tetromino = nil)
170
+ PLAYFIELD_WIDTH.times.map do |playfield_column|
171
+ (playfield.each_with_index.detect do |row, playfield_row|
172
+ !row[playfield_column].clear? &&
173
+ (
174
+ tetromino.nil? ||
175
+ (bottom_most_block = tetromino.bottom_most_block_for_column(playfield_column)).nil? ||
176
+ (playfield_row > tetromino.row + bottom_most_block[:row])
177
+ )
178
+ end || [nil, PLAYFIELD_HEIGHT])[1]
179
+ end.to_a
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+