glimmer-dsl-swt 4.18.1.0 → 4.18.2.3

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.
@@ -61,11 +61,12 @@ module Glimmer
61
61
 
62
62
  before_body {
63
63
  @swt_style = swt_style == 0 ? [:border, :multi, :v_scroll, :h_scroll] : swt_style
64
+ @font_name = display.get_font_list(nil, true).map(&:name).include?('Consolas') ? 'Consolas' : 'Courier'
64
65
  }
65
66
 
66
67
  body {
67
68
  styled_text(swt_style) {
68
- font name: 'Consolas', height: 15
69
+ font name: @font_name, height: 15
69
70
  foreground rgb(75, 75, 75)
70
71
  left_margin 5
71
72
  top_margin 5
@@ -20,6 +20,10 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/swt/properties'
23
+ require 'glimmer/swt/swt_proxy'
24
+ require 'glimmer/swt/display_proxy'
25
+ require 'glimmer/swt/color_proxy'
26
+ require 'glimmer/swt/font_proxy'
23
27
 
24
28
  module Glimmer
25
29
  module SWT
@@ -28,8 +32,9 @@ module Glimmer
28
32
  # swt_widget returns the parent (e.g. a `canvas` WidgetProxy), equivalent to `parent.swt_widget`
29
33
  # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
30
34
  class Shape
35
+ include Packages
31
36
  include Properties
32
- # TODO support textExtent as an option
37
+ # TODO support textExtent sized shapes nested within text/string
33
38
  # TODO support a Pattern DSL for methods that take Pattern arguments
34
39
 
35
40
  class << self
@@ -48,14 +53,17 @@ module Glimmer
48
53
  end
49
54
 
50
55
  def method_name(keyword, args)
51
- gc_instance_method_name_prefix = arg_options(args)[:fill] ? 'fill_' : 'draw_'
52
- "#{gc_instance_method_name_prefix}#{keyword}"
56
+ keyword = keyword.to_s
57
+ gradient = 'gradient_' if arg_options(args)[:gradient]
58
+ round = 'round_' if arg_options(args)[:round]
59
+ gc_instance_method_name_prefix = !['polyline', 'point', 'image', 'focus'].include?(keyword) && (arg_options(args)[:fill] || arg_options(args)[:gradient]) ? 'fill_' : 'draw_'
60
+ "#{gc_instance_method_name_prefix}#{gradient}#{round}#{keyword}"
53
61
  end
54
62
  end
55
63
 
56
64
  attr_reader :parent, :name, :args, :options, :swt_widget, :paint_listener_proxy
57
65
 
58
- def initialize(parent, keyword, *args)
66
+ def initialize(parent, keyword, *args, &property_block)
59
67
  @parent = parent
60
68
  @name = keyword
61
69
  @method_name = self.class.method_name(keyword, args)
@@ -64,23 +72,37 @@ module Glimmer
64
72
  @swt_widget = parent.respond_to?(:swt_display) ? parent.swt_display : parent.swt_widget
65
73
  @properties = {}
66
74
  @parent.shapes << self
75
+ post_add_content if property_block.nil?
76
+ end
77
+
78
+ def draw?
79
+ !fill?
67
80
  end
68
81
 
69
82
  def fill?
70
- !draw?
83
+ @options[:fill]
71
84
  end
72
85
 
73
- def draw?
74
- !@options[:fill]
86
+ def gradient?
87
+ @options[:gradient]
88
+ end
89
+
90
+ def round?
91
+ @options[:round]
75
92
  end
76
93
 
77
94
  def post_add_content
78
95
  event_handler = lambda do |event|
96
+ @properties['background'] = [@parent.background] if fill? && !@properties.keys.map(&:to_s).include?('background')
97
+ @properties['foreground'] = [@parent.foreground] if draw? && !@properties.keys.map(&:to_s).include?('foreground')
79
98
  @properties.each do |property, args|
80
99
  method_name = attribute_setter(property)
81
- handle_conversions(method_name, args)
100
+ apply_property_arg_conversions(method_name, args)
82
101
  event.gc.send(method_name, *args)
83
102
  end
103
+ apply_shape_arg_conversions(@method_name, @args)
104
+ apply_shape_arg_defaults(@method_name, @args)
105
+ tolerate_shape_extra_args(@method_name, @args)
84
106
  event.gc.send(@method_name, *@args)
85
107
  end
86
108
  if parent.respond_to?(:swt_display)
@@ -90,35 +112,78 @@ module Glimmer
90
112
  end
91
113
  end
92
114
 
93
- def handle_conversions(method_name, args)
115
+ def apply_property_arg_conversions(method_name, args)
94
116
  the_java_method = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.detect {|m| m.name == method_name}
95
- if args.first.is_a?(Symbol) || args.first.is_a?(String)
117
+ if (args.first.is_a?(Symbol) || args.first.is_a?(String))
96
118
  if the_java_method.parameter_types.first == Color.java_class
97
119
  args[0] = ColorProxy.new(args[0])
98
120
  end
121
+ if the_java_method.parameter_types.first == Java::int.java_class
122
+ args[0] = SWTProxy.constant(args[0])
123
+ end
99
124
  end
100
125
  if args.first.is_a?(ColorProxy)
101
126
  args[0] = args[0].swt_color
102
127
  end
103
- if args.first.is_a?(Hash)
104
- if the_java_method.parameter_types.first == Font.java_class
105
- args[0] = FontProxy.new(args[0])
106
- end
128
+ if args.first.is_a?(Hash) && the_java_method.parameter_types.first == Font.java_class
129
+ args[0] = FontProxy.new(args[0])
107
130
  end
108
131
  if args.first.is_a?(FontProxy)
109
132
  args[0] = args[0].swt_font
110
133
  end
111
-
112
- # TODO convert SWT style symbol to integer if method takes integer
134
+ if ['setBackgroundPattern', 'setForegroundPattern'].include?(method_name.to_s)
135
+ args.each_with_index do |arg, i|
136
+ if arg.is_a?(Symbol) || arg.is_a?(String)
137
+ args[i] = ColorProxy.new(arg).swt_color
138
+ elsif arg.is_a?(ColorProxy)
139
+ args[i] = arg.swt_color
140
+ end
141
+ end
142
+ new_args = [DisplayProxy.instance.swt_display] + args
143
+ args[0] = org.eclipse.swt.graphics.Pattern.new(*new_args)
144
+ args[1..-1] = []
145
+ end
113
146
  end
114
147
 
148
+ def apply_shape_arg_conversions(method_name, args)
149
+ if args.size > 1 && (method_name.include?('polygon') || method_name.include?('polyline'))
150
+ args[0] = args.dup
151
+ args[1..-1] = []
152
+ end
153
+ end
154
+
155
+ def apply_shape_arg_defaults(method_name, args)
156
+ if method_name.include?('round_rectangle') && args.size.between?(4, 5)
157
+ (6 - args.size).times {args << 60}
158
+ elsif method_name.include?('rectangle') && gradient? && args.size == 4
159
+ args << true
160
+ elsif (method_name.include?('text') || method_name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && args.size == 3
161
+ args << true
162
+ end
163
+ if method_name.include?('image') && args.first.is_a?(String)
164
+ args[0] = ImageProxy.new(args[0])
165
+ end
166
+ if method_name.include?('image') && args.first.is_a?(ImageProxy)
167
+ args[0] = args[0].swt_image
168
+ end
169
+ end
170
+
171
+ # Tolerates shape extra args added by user by mistake
172
+ # (e.g. happens when switching from round rectangle to a standard one without removing all extra args)
173
+ def tolerate_shape_extra_args(method_name, args)
174
+ the_java_method_arg_count = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.select do |m|
175
+ m.name == method_name.camelcase(:lower)
176
+ end.map(&:parameter_types).map(&:size).max
177
+ if args.size > the_java_method_arg_count
178
+ args[the_java_method_arg_count..-1] = []
179
+ end
180
+ end
181
+
115
182
  def has_attribute?(attribute_name, *args)
116
- # TODO test that attribute getter responds too
117
183
  self.class.gc_instance_methods.include?(attribute_setter(attribute_name))
118
184
  end
119
185
 
120
186
  def set_attribute(attribute_name, *args)
121
- # TODO special treatment for color symbols
122
187
  @properties[attribute_name] = args
123
188
  end
124
189
 
@@ -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
@@ -56,6 +56,7 @@ module Glimmer
56
56
  attr_reader :swt_display
57
57
 
58
58
  def initialize(*args)
59
+ Display.app_name ||= 'Glimmer'
59
60
  @swt_display = Display.new(*args)
60
61
  @swt_display.set_data('proxy', self)
61
62
  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
@@ -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)
@@ -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
 
@@ -150,7 +171,7 @@ class MetaSampleApplication
150
171
  end
151
172
 
152
173
  def launch
153
- Display.setAppName('Glimmer Meta-Sample')
174
+ Display.app_name = 'Glimmer Meta-Sample'
154
175
  shell {
155
176
  minimum_size 1280, 768
156
177
  text 'Glimmer Meta-Sample (The Sample of Samples)'
@@ -0,0 +1,102 @@
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
+
28
+ class Tetris
29
+ include Glimmer::UI::CustomShell
30
+
31
+ BLOCK_SIZE = 25
32
+ PLAYFIELD_WIDTH = 10
33
+ PLAYFIELD_HEIGHT = 20
34
+
35
+ before_body {
36
+ Model::Game.configure_beeper do
37
+ display.beep
38
+ end
39
+
40
+ Model::Game.start
41
+
42
+ display {
43
+ on_swt_keydown { |key_event|
44
+ unless Model::Game.current_tetromino.stopped?
45
+ case key_event.keyCode
46
+ when swt(:arrow_down)
47
+ Model::Game.current_tetromino.down
48
+ when swt(:arrow_left)
49
+ Model::Game.current_tetromino.left
50
+ when swt(:arrow_right)
51
+ Model::Game.current_tetromino.right
52
+ when swt(:shift)
53
+ if key_event.keyLocation == swt(:right) # right shift key
54
+ Model::Game.current_tetromino.rotate(:right)
55
+ elsif key_event.keyLocation == swt(:left) # left shift key
56
+ Model::Game.current_tetromino.rotate(:left)
57
+ end
58
+ when 'd'.bytes.first, swt(:arrow_up)
59
+ Model::Game.current_tetromino.rotate(:right)
60
+ when 'a'.bytes.first
61
+ Model::Game.current_tetromino.rotate(:left)
62
+ end
63
+ end
64
+ }
65
+ }
66
+ }
67
+
68
+ after_body {
69
+ Thread.new {
70
+ loop {
71
+ sleep(0.9)
72
+ sync_exec {
73
+ unless @game_over
74
+ Model::Game.current_tetromino.down
75
+ if Model::Game.current_tetromino.stopped? && Model::Game.current_tetromino.row <= 0
76
+ @game_over = true
77
+ display.beep
78
+ message_box(:icon_error) {
79
+ text 'Tetris'
80
+ message 'Game Over!'
81
+ }.open
82
+ Model::Game.restart
83
+ @game_over = false
84
+ end
85
+ Model::Game.consider_adding_tetromino
86
+ end
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ body {
93
+ shell(:no_resize) {
94
+ text 'Glimmer Tetris'
95
+ background :gray
96
+
97
+ playfield(playfield_width: PLAYFIELD_WIDTH, playfield_height: PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
98
+ }
99
+ }
100
+ end
101
+
102
+ 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
+ def clear
35
+ self.color = COLOR_CLEAR
36
+ end
37
+
38
+ def clear?
39
+ self.color == COLOR_CLEAR
40
+ end
41
+
42
+ def occupied?
43
+ !clear?
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,116 @@
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
+ class << self
29
+ def consider_adding_tetromino
30
+ if tetrominoes.empty? || Game.current_tetromino.stopped?
31
+ tetrominoes << Tetromino.new
32
+ end
33
+ end
34
+
35
+ def current_tetromino
36
+ tetrominoes.last
37
+ end
38
+
39
+ def tetrominoes
40
+ @tetrominoes ||= reset_tetrominoes
41
+ end
42
+
43
+ # Returns blocks in the playfield
44
+ def playfield
45
+ @playfield ||= PLAYFIELD_HEIGHT.times.map {
46
+ PLAYFIELD_WIDTH.times.map {
47
+ Block.new
48
+ }
49
+ }
50
+ end
51
+
52
+ def consider_eliminating_lines
53
+ cleared_line = false
54
+ playfield.each_with_index do |row, playfield_row|
55
+ if row.all? {|block| !block.clear?}
56
+ cleared_line = true
57
+ shift_blocks_down_above_row(playfield_row)
58
+ end
59
+ end
60
+ beep if cleared_line
61
+ end
62
+
63
+ def beep
64
+ @beeper&.call
65
+ end
66
+
67
+ def configure_beeper(&beeper)
68
+ @beeper = beeper
69
+ end
70
+
71
+ def shift_blocks_down_above_row(row)
72
+ row.downto(0) do |playfield_row|
73
+ playfield[playfield_row].each_with_index do |block, playfield_column|
74
+ previous_row = playfield[playfield_row - 1]
75
+ previous_block = previous_row[playfield_column]
76
+ block.color = previous_block.color
77
+ end
78
+ end
79
+ playfield[0].each(&:clear)
80
+ end
81
+
82
+ def restart
83
+ reset_playfield
84
+ reset_tetrominoes
85
+ end
86
+ alias start restart
87
+
88
+ def reset_tetrominoes
89
+ @tetrominoes = [Tetromino.new]
90
+ end
91
+
92
+ def reset_playfield
93
+ playfield.each do |row|
94
+ row.each do |block|
95
+ block.clear
96
+ end
97
+ end
98
+ end
99
+
100
+ def playfield_remaining_heights(tetromino = nil)
101
+ PLAYFIELD_WIDTH.times.map do |playfield_column|
102
+ (playfield.each_with_index.detect do |row, playfield_row|
103
+ !row[playfield_column].clear? &&
104
+ (
105
+ tetromino.nil? ||
106
+ tetromino.bottom_block_for_column(playfield_column).nil? ||
107
+ (playfield_row > tetromino.row + tetromino.bottom_block_for_column(playfield_column)[:row])
108
+ )
109
+ end || [nil, PLAYFIELD_HEIGHT])[1]
110
+ end.to_a
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+