glimmer-dsl-swt 4.18.1.1 → 4.18.2.4

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.
@@ -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
+