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.
@@ -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
@@ -30,7 +30,8 @@ module Glimmer
30
30
  args.size > 0 and
31
31
  parent.respond_to?(:set_attribute) and
32
32
  parent.respond_to?(:has_attribute?) and
33
- parent.has_attribute?(keyword, *args)
33
+ parent.has_attribute?(keyword, *args) and
34
+ !(parent.respond_to?(:swt_widget) && parent.swt_widget.class == org.eclipse.swt.widgets.Canvas && keyword == 'image')
34
35
  end
35
36
 
36
37
  def interpret(parent, keyword, *args, &block)
@@ -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
@@ -27,7 +27,7 @@ module Glimmer
27
27
  module Package
28
28
  class << self
29
29
  attr_accessor :javapackager_extra_args
30
- alias jpackage_extra_args :javapackager_extra_args
30
+ alias jpackage_extra_args javapackager_extra_args
31
31
 
32
32
  def clean
33
33
  require 'fileutils'
@@ -48,7 +48,7 @@ module Glimmer
48
48
  FileUtils.mkdir_p('vendor/jars')
49
49
  command = "lock_jars --vendor-dir vendor/jars"
50
50
  puts command
51
- system command
51
+ system command
52
52
  end
53
53
 
54
54
  def config
@@ -78,18 +78,18 @@ module Glimmer
78
78
  else
79
79
  puts 'Warbler executable "warble" is missing!'
80
80
  end
81
- end
81
+ end
82
82
  end
83
83
 
84
84
  def jar
85
85
  FileUtils.mkdir_p('dist')
86
86
  puts "Generating JAR with Warbler..."
87
87
  system "jruby -S gem install warbler -v2.0.5 --no-document" unless warbler_exists?
88
- system('warble')
88
+ system('warble')
89
89
  end
90
90
 
91
91
  def native(native_type=nil, native_extra_args)
92
- puts "Generating native executable with javapackager/jpackage..."
92
+ puts "Generating native executable with javapackager/jpackage..."
93
93
  java_version = `java -version`
94
94
  puts "WARNING! Glimmer Packaging Pre-Requisite Java Version 1.8.0_241 Is Not Found!" unless java_version.include?('1.8.0_241')
95
95
  require 'facets/string/titlecase'
@@ -125,7 +125,7 @@ module Glimmer
125
125
  command += " #{ENV['JAVAPACKAGER_EXTRA_ARGS']} " if ENV['JAVAPACKAGER_EXTRA_ARGS']
126
126
  command += " #{native_extra_args} " if native_extra_args
127
127
  puts command
128
- system command
128
+ system command
129
129
  end
130
130
 
131
131
  private
@@ -42,6 +42,7 @@ module Glimmer
42
42
  *.gem
43
43
  *.rbc
44
44
  /.config
45
+ /.mvn/
45
46
  /coverage/
46
47
  /InstalledFiles
47
48
  /pkg/
@@ -97,9 +98,9 @@ module Glimmer
97
98
  .gladiator
98
99
 
99
100
  # Glimmer
100
- dist
101
- packages
102
- vendor/jars
101
+ /dist/
102
+ /packages/
103
+ /vendor/jars/
103
104
  MULTI_LINE_STRING
104
105
 
105
106
  GEMFILE = <<~MULTI_LINE_STRING
@@ -28,42 +28,126 @@ module Glimmer
28
28
  class Animation
29
29
  include Properties # TODO rename to Properties
30
30
 
31
+ class << self
32
+ def schedule_frame_animation(animation, &frame_animation_block)
33
+ frame_animation_queue(animation).prepend(frame_animation_block)
34
+ swt_display.async_exec do
35
+ frame_animation_queue(next_animation)&.pop&.call
36
+ end
37
+ end
38
+
39
+ def next_animation
40
+ animation = nil
41
+ while frame_animation_queues.values.reduce(:+)&.any? && (animation.nil? || frame_animation_queue(animation).last.nil?)
42
+ animation = frame_animation_queues.keys[next_animation_index]
43
+ frame_animation_queues.delete(animation) if frame_animation_queues.values.reduce(:+)&.any? && !animation.nil? && frame_animation_queue(animation).empty?
44
+ end
45
+ animation
46
+ end
47
+
48
+ def next_animation_index
49
+ next_schedule_index % frame_animation_queues.keys.size
50
+ end
51
+
52
+ def next_schedule_index
53
+ unless defined? @@next_schedule_index
54
+ @@next_schedule_index = 0
55
+ else
56
+ @@next_schedule_index += 1
57
+ end
58
+ end
59
+
60
+ def frame_animation_queues
61
+ unless defined? @@frame_animation_queues
62
+ @@frame_animation_queues = {}
63
+ end
64
+ @@frame_animation_queues
65
+ end
66
+
67
+ def frame_animation_queue(animation)
68
+ frame_animation_queues[animation] ||= []
69
+ end
70
+
71
+ def swt_display
72
+ unless defined? @@swt_display
73
+ @@swt_display = DisplayProxy.instance.swt_display
74
+ end
75
+ @@swt_display
76
+ end
77
+ end
78
+
31
79
  attr_reader :parent, :options, :frame_index, :cycle
32
80
  alias current_frame_index frame_index
33
- attr_accessor :frame_block, :every, :cycle_count, :frame_count, :started
81
+ attr_accessor :frame_block, :every, :cycle_count, :frame_count, :started, :duration_limit
82
+ alias started? started
34
83
  # TODO consider supporting an async: false option
35
84
 
36
85
  def initialize(parent)
37
86
  @parent = parent
38
87
  @started = true
39
88
  @frame_index = 0
89
+ @cycle_count_index = 0
90
+ @start_number = 0 # denotes the number of starts (increments on every start)
91
+ self.class.swt_display # ensures initializing variable to set from GUI thread
40
92
  end
41
93
 
42
94
  def post_add_content
43
95
  @parent.on_widget_disposed { stop }
44
- start if @started
96
+ start if started?
45
97
  end
46
98
 
99
+ # Starts an animation that is indefinite or has never been started before (i.e. having `started: false` option).
100
+ # Otherwise, resumes a stopped animation that has not been completed.
47
101
  def start
48
- swt_display = DisplayProxy.instance.swt_display
102
+ return if @start_number > 0 && started?
103
+ @start_number += 1
104
+ @started = true
105
+ @start_time = Time.now
106
+ @original_start_time = @start_time if @duration.nil?
107
+ # TODO track when finished in a variable for finite animations (whether by frame count, cycle count, or duration limit)
49
108
  Thread.new do
109
+ start_number = @start_number
50
110
  if cycle_count.is_a?(Integer) && cycle.is_a?(Array)
51
111
  (cycle_count * cycle.length).times do
52
- break unless draw_frame(swt_display)
112
+ break unless draw_frame(start_number)
53
113
  end
54
114
  else
55
115
  loop do
56
116
  # this code has to be duplicated to break from a loop (break keyword only works when literally in a loop block)
57
- break unless draw_frame(swt_display)
117
+ break unless draw_frame(start_number)
58
118
  end
59
119
  end
60
- @started = false
61
120
  end
62
121
  end
63
122
 
64
123
  def stop
124
+ return if stopped?
65
125
  @started = false
126
+ @duration = (Time.now - @start_time) + @duration.to_f if duration_limited? && !@start_time.nil?
127
+ end
128
+
129
+ # Restarts an animation (whether indefinite or not and whether stopped or not)
130
+ def restart
131
+ @original_start_time = @start_time = nil
132
+ @duration = nil
133
+ @frame_index = 0
134
+ @cycle_count_index = 0
135
+ stop
136
+ start
137
+ end
138
+
139
+ def stopped?
140
+ !started?
141
+ end
142
+
143
+ def finite?
144
+ frame_count_limited? || cycle_limited? || duration_limited?
145
+ end
146
+
147
+ def infinite?
148
+ !finite?
66
149
  end
150
+ alias indefinite? infinite?
67
151
 
68
152
  def has_attribute?(attribute_name, *args)
69
153
  respond_to?(ruby_attribute_setter(attribute_name)) && respond_to?(ruby_attribute_getter(attribute_name))
@@ -89,21 +173,60 @@ module Glimmer
89
173
  end
90
174
  end
91
175
 
176
+ def cycle_enabled?
177
+ @cycle.is_a?(Array)
178
+ end
179
+
180
+ def cycle_limited?
181
+ cycle_enabled? && @cycle_count.is_a?(Integer)
182
+ end
183
+
184
+ def duration_limited?
185
+ @duration_limit.is_a?(Integer)
186
+ end
187
+
188
+ def frame_count_limited?
189
+ @frame_count.is_a?(Integer)
190
+ end
191
+
192
+ def surpassed_duration_limit?
193
+ duration_limited? && ((Time.now - @start_time) > (@duration_limit - @duration.to_f))
194
+ end
195
+
196
+ def within_duration_limit?
197
+ !surpassed_duration_limit?
198
+ end
199
+
92
200
  private
93
201
 
94
202
  # Returns true on success of painting a frame and false otherwise
95
- def draw_frame(swt_display)
96
- return false if !@started || (@frame_count.is_a?(Integer) && @frame_index == @frame_count)
203
+ def draw_frame(start_number)
204
+ return false if stopped? ||
205
+ start_number != @start_number ||
206
+ (frame_count_limited? && @frame_index == @frame_count) ||
207
+ (cycle_limited? && @cycle_count_index == @cycle_count) ||
208
+ surpassed_duration_limit?
97
209
  block_args = [@frame_index]
98
- block_args << @cycle[@frame_index % @cycle.length] if @cycle.is_a?(Array)
99
- swt_display.async_exec do
100
- @parent.clear_shapes
101
- @parent.content {
102
- frame_block.call(*block_args)
103
- }
104
- @parent.redraw
210
+ block_args << @cycle[@frame_index % @cycle.length] if cycle_enabled?
211
+ current_frame_index = @frame_index
212
+ current_cycle_count_index = @cycle_count_index
213
+ self.class.schedule_frame_animation(self) do
214
+ if started? && start_number == @start_number && within_duration_limit?
215
+ @parent.clear_shapes
216
+ @parent.content {
217
+ frame_block.call(*block_args)
218
+ }
219
+ @parent.redraw
220
+ else
221
+ if stopped? && @frame_index > current_frame_index
222
+ @started = false
223
+ @frame_index = current_frame_index
224
+ @cycle_count_index = current_cycle_count_index
225
+ end
226
+ end
105
227
  end
106
228
  @frame_index += 1
229
+ @cycle_count_index += 1 if cycle_limited? && (@frame_index % @cycle&.length&.to_i) == 0
107
230
  sleep(every) if every.is_a?(Numeric)
108
231
  true
109
232
  rescue => e
@@ -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,8 +53,11 @@ 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
 
@@ -67,18 +75,26 @@ module Glimmer
67
75
  post_add_content if property_block.nil?
68
76
  end
69
77
 
78
+ def draw?
79
+ !fill?
80
+ end
81
+
70
82
  def fill?
71
- !draw?
83
+ @options[:fill]
72
84
  end
73
85
 
74
- def draw?
75
- !@options[:fill]
86
+ def gradient?
87
+ @options[:gradient]
88
+ end
89
+
90
+ def round?
91
+ @options[:round]
76
92
  end
77
93
 
78
94
  def post_add_content
79
95
  event_handler = lambda do |event|
80
- @properties['background'] = [DisplayProxy.instance.get_system_color(SWTProxy(:color_widget_background))] if fill? && !@properties.keys.map(&:to_s).include?('background')
81
- @properties['foreground'] = [ColorProxy.new(0, 0, 0)] if draw? && !@properties.keys.map(&:to_s).include?('foreground')
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')
82
98
  @properties.each do |property, args|
83
99
  method_name = attribute_setter(property)
84
100
  apply_property_arg_conversions(method_name, args)
@@ -86,6 +102,7 @@ module Glimmer
86
102
  end
87
103
  apply_shape_arg_conversions(@method_name, @args)
88
104
  apply_shape_arg_defaults(@method_name, @args)
105
+ tolerate_shape_extra_args(@method_name, @args)
89
106
  event.gc.send(@method_name, *@args)
90
107
  end
91
108
  if parent.respond_to?(:swt_display)
@@ -102,7 +119,7 @@ module Glimmer
102
119
  args[0] = ColorProxy.new(args[0])
103
120
  end
104
121
  if the_java_method.parameter_types.first == Java::int.java_class
105
- args[0] = SWTProxy[args[0]]
122
+ args[0] = SWTProxy.constant(args[0])
106
123
  end
107
124
  end
108
125
  if args.first.is_a?(ColorProxy)
@@ -114,6 +131,18 @@ module Glimmer
114
131
  if args.first.is_a?(FontProxy)
115
132
  args[0] = args[0].swt_font
116
133
  end
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
117
146
  end
118
147
 
119
148
  def apply_shape_arg_conversions(method_name, args)
@@ -126,18 +155,35 @@ module Glimmer
126
155
  def apply_shape_arg_defaults(method_name, args)
127
156
  if method_name.include?('round_rectangle') && args.size.between?(4, 5)
128
157
  (6 - args.size).times {args << 60}
129
- elsif method_name.include?('gradient_rectangle') && args.size == 4
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
130
161
  args << true
131
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
132
180
  end
133
181
 
134
182
  def has_attribute?(attribute_name, *args)
135
- # TODO test that attribute getter responds too
136
183
  self.class.gc_instance_methods.include?(attribute_setter(attribute_name))
137
184
  end
138
185
 
139
186
  def set_attribute(attribute_name, *args)
140
- # TODO special treatment for color symbols
141
187
  @properties[attribute_name] = args
142
188
  end
143
189