Class: Glimmer::SWT::Custom::Shape

Inherits:
Object
  • Object
show all
Includes:
Packages, Properties
Defined in:
lib/glimmer/swt/custom/shape.rb

Overview

Represents a shape (graphics) to be drawn on a control/widget/canvas/display That is because Shape is drawn on a parent as graphics and doesn’t have an SWT widget for itself

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Properties

attribute_getter, #attribute_getter, attribute_setter, #attribute_setter, normalized_attribute, #normalized_attribute, ruby_attribute_getter, #ruby_attribute_setter, ruby_attribute_setter

Methods included from Packages

included

Constructor Details

#initialize(parent, keyword, *args, &property_block) ⇒ Shape

Returns a new instance of Shape.



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/glimmer/swt/custom/shape.rb', line 96

def initialize(parent, keyword, *args, &property_block)
  @parent = parent
  @name = keyword
  @options = self.class.arg_options(args, extract: true)
  @method_name = self.class.method_name(keyword, @options)
  @args = args
  @properties = {}
  @options.reject {|key, value| %w[fill gradient round].include?(key.to_s)}.each do |property, property_args|
    @properties[property] = property_args
  end
  @parent.add_shape(self)
  post_add_content if property_block.nil?
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



94
95
96
# File 'lib/glimmer/swt/custom/shape.rb', line 94

def args
  @args
end

#nameObject (readonly)

Returns the value of attribute name.



94
95
96
# File 'lib/glimmer/swt/custom/shape.rb', line 94

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



94
95
96
# File 'lib/glimmer/swt/custom/shape.rb', line 94

def options
  @options
end

#parentObject (readonly)

Returns the value of attribute parent.



94
95
96
# File 'lib/glimmer/swt/custom/shape.rb', line 94

def parent
  @parent
end

Class Method Details

.arg_options(args, extract: false) ⇒ Object



59
60
61
62
63
# File 'lib/glimmer/swt/custom/shape.rb', line 59

def arg_options(args, extract: false)
  arg_options_method = extract ? :pop : :last
  options = args.send(arg_options_method) if args.last.is_a?(Hash)
  options.nil? ? {} : options.symbolize_keys
end

.flyweigh_patternsObject



89
90
91
# File 'lib/glimmer/swt/custom/shape.rb', line 89

def flyweigh_patterns
  @flyweigh_patterns ||= {}
end

.flyweight_method_namesObject



77
78
79
# File 'lib/glimmer/swt/custom/shape.rb', line 77

def flyweight_method_names
  @flyweight_method_names ||= {}
end

.gc_instance_methodsObject



45
46
47
# File 'lib/glimmer/swt/custom/shape.rb', line 45

def gc_instance_methods
  @gc_instance_methods ||= org.eclipse.swt.graphics.GC.instance_methods.map(&:to_s)
end

.keywordsObject



49
50
51
52
53
54
55
56
57
# File 'lib/glimmer/swt/custom/shape.rb', line 49

def keywords
  @keywords ||= gc_instance_methods.select do |method_name|
    !method_name.end_with?('=') && (method_name.start_with?('draw_') || method_name.start_with?('fill_'))
  end.reject do |method_name|
    gc_instance_methods.include?("#{method_name}=") || gc_instance_methods.include?("set_#{method_name}")
  end.map do |method_name|
    method_name.gsub(/(draw|fill|gradient|round)_/, '')
  end.uniq.compact.to_a
end

.method_name(keyword, method_arg_options) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/glimmer/swt/custom/shape.rb', line 65

def method_name(keyword, method_arg_options)
  keyword = keyword.to_s
  method_arg_options = method_arg_options.select {|key, value| %w[fill gradient round].include?(key.to_s)}
  unless flyweight_method_names.keys.include?([keyword, method_arg_options])
    gradient = 'Gradient' if method_arg_options[:gradient]
    round = 'Round' if method_arg_options[:round]
    gc_instance_method_name_prefix = !['polyline', 'point', 'image', 'focus'].include?(keyword) && (method_arg_options[:fill] || method_arg_options[:gradient]) ? 'fill' : 'draw'
    flyweight_method_names[[keyword, method_arg_options]] = "#{gc_instance_method_name_prefix}#{gradient}#{round}#{keyword.capitalize}"
  end
  flyweight_method_names[[keyword, method_arg_options]]
end

.pattern(*args) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/glimmer/swt/custom/shape.rb', line 81

def pattern(*args)
  found_pattern = flyweigh_patterns[args]
  if found_pattern.nil? || found_pattern.is_disposed
    found_pattern = flyweigh_patterns[args] = org.eclipse.swt.graphics.Pattern.new(*args)
  end
  found_pattern
end

.valid?(parent, keyword, *args, &block) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/glimmer/swt/custom/shape.rb', line 41

def valid?(parent, keyword, *args, &block)
  gc_instance_methods.include?(method_name(keyword, arg_options(args)))
end

Instance Method Details

#amend_method_name_options_based_on_properties!Object



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/glimmer/swt/custom/shape.rb', line 225

def amend_method_name_options_based_on_properties!
  return if @name == 'point'
  if has_some_background? && !has_some_foreground?
    @options[:fill] = true
  elsif !has_some_background? && has_some_foreground?
    @options[:fill] = false
  elsif @name == 'rectangle' && has_some_background? && has_some_foreground?
    @options[:fill] = true
    @options[:gradient] = true
  end
  if @name == 'rectangle' && @args.size > 4 && @args.last.is_a?(Numeric)
    @options[:round] = true
  end
  @method_name = self.class.method_name(@name, @options)
end

#apply_property_arg_conversions(method_name, property, args) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/glimmer/swt/custom/shape.rb', line 142

def apply_property_arg_conversions(method_name, property, args)
  args = args.dup
  the_java_method = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.detect {|m| m.name == method_name}
  if ['setBackground', 'setForeground'].include?(method_name.to_s) && args.first.is_a?(Array)
    args[0] = ColorProxy.new(args[0])
  end
  if args.first.is_a?(Symbol) || args.first.is_a?(String)
    if the_java_method.parameter_types.first == Color.java_class
      args[0] = ColorProxy.new(args[0])
    end
    if the_java_method.parameter_types.first == Java::int.java_class
      args[0] = SWTProxy.constant(args[0])
    end
  end
  if args.first.is_a?(ColorProxy)
    args[0] = args[0].swt_color
  end
  if args.first.is_a?(Hash) && the_java_method.parameter_types.first == Font.java_class
    args[0] = FontProxy.new(args[0])
  end
  if args.first.is_a?(FontProxy)
    args[0] = args[0].swt_font
  end
  if args.first.is_a?(TransformProxy)
    args[0] = args[0].swt_transform
  end
  if ['setBackgroundPattern', 'setForegroundPattern'].include?(method_name.to_s)
    @parent.requires_shape_disposal = true
    args.each_with_index do |arg, i|
      if arg.is_a?(Symbol) || arg.is_a?(String)
        args[i] = ColorProxy.new(arg).swt_color
      elsif arg.is_a?(ColorProxy)
        args[i] = arg.swt_color
      end
    end
    new_args = [DisplayProxy.instance.swt_display] + args
    args[0] = pattern(*new_args, type: method_name.to_s.match(/set(.+)Pattern/)[1])
    args[1..-1] = []
  end
  args
end

#apply_shape_arg_conversions!Object



184
185
186
187
188
189
# File 'lib/glimmer/swt/custom/shape.rb', line 184

def apply_shape_arg_conversions!
  if @args.size > 1 && (['polygon', 'polyline'].include?(@name))
    @args[0] = @args.dup
    @args[1..-1] = []
  end
end

#apply_shape_arg_defaults!Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/glimmer/swt/custom/shape.rb', line 191

def apply_shape_arg_defaults!
  if @name.include?('rectangle') && round? && @args.size.between?(4, 5)
    (6 - @args.size).times {@args << 60}
  elsif @name.include?('rectangle') && gradient? && @args.size == 4
    @args << true
  elsif (@name.include?('text') || @name.include?('String')) && !@properties.keys.map(&:to_s).include?('background') && @args.size == 3
    @args << true
  end
  if @name.include?('image')
    @parent.requires_shape_disposal = true
    if @args.size == 1
      @args[1] = 0
      @args[2] = 0
    end
    if @args.first.is_a?(String)
      @args[0] = ImageProxy.new(@args[0])
    end
    if @args.first.is_a?(ImageProxy)
      @image = @args[0] = @args[0].swt_image
    end
  end
end

#calculate_paint_args!Object



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/glimmer/swt/custom/shape.rb', line 289

def calculate_paint_args!
  unless @calculated_paint_args
    if @name == 'point'
      # optimized performance calculation for pixel points
      if !@properties[:foreground].is_a?(Color)
        if @properties[:foreground].is_a?(Array)
          @properties[:foreground] = ColorProxy.new(@properties[:foreground], ensure_bounds: false)
        end
        if @properties[:foreground].is_a?(Symbol) || @properties[:foreground].is_a?(String)
         @properties[:foreground] = ColorProxy.new(@properties[:foreground], ensure_bounds: false)
        end
        if @properties[:foreground].is_a?(ColorProxy)
          @properties[:foreground] = @properties[:foreground].swt_color
        end
      end
    else
      @properties['background'] = [@parent.background] if fill? && !has_some_background?
      @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !has_some_foreground?
      @properties['font'] = [@parent.font] if @parent.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
      @properties['transform'] = [nil] if @parent.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
      @properties.each do |property, args|
        method_name = attribute_setter(property)
        converted_args = apply_property_arg_conversions(method_name, property, args)
        @properties[property] = converted_args
      end
      apply_shape_arg_conversions!
      apply_shape_arg_defaults!
      tolerate_shape_extra_args!
      @calculated_paint_args = true
    end
  end
end

#disposeObject



266
267
268
269
270
271
272
273
274
# File 'lib/glimmer/swt/custom/shape.rb', line 266

def dispose
  @background_pattern&.dispose
  @background_pattern = nil
  @foreground_pattern&.dispose
  @foreground_pattern = nil
  @image&.dispose
  @image = nil
  @parent.shapes.delete(self)
end

#draw?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/glimmer/swt/custom/shape.rb', line 110

def draw?
  !fill?
end

#fill?Boolean

Returns:

  • (Boolean)


114
115
116
# File 'lib/glimmer/swt/custom/shape.rb', line 114

def fill?
  @options[:fill]
end

#get_attribute(attribute_name) ⇒ Object



253
254
255
# File 'lib/glimmer/swt/custom/shape.rb', line 253

def get_attribute(attribute_name)
  @properties.symbolize_keys[attribute_name.to_s.to_sym]
end

#gradient?Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/glimmer/swt/custom/shape.rb', line 118

def gradient?
  @options[:gradient]
end

#has_attribute?(attribute_name, *args) ⇒ Boolean

Returns:

  • (Boolean)


241
242
243
# File 'lib/glimmer/swt/custom/shape.rb', line 241

def has_attribute?(attribute_name, *args)
  self.class.gc_instance_methods.include?(attribute_setter(attribute_name))
end

#has_some_background?Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/glimmer/swt/custom/shape.rb', line 126

def has_some_background?
  @properties.keys.map(&:to_s).include?('background') || @properties.keys.map(&:to_s).include?('background_pattern')
end

#has_some_foreground?Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/glimmer/swt/custom/shape.rb', line 130

def has_some_foreground?
  @properties.keys.map(&:to_s).include?('foreground') || @properties.keys.map(&:to_s).include?('foreground_pattern')
end

#paint(paint_event) ⇒ Object



276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/glimmer/swt/custom/shape.rb', line 276

def paint(paint_event)
  calculate_paint_args!
  @properties.each do |property, args|
    method_name = attribute_setter(property)
    # TODO consider optimization of not setting a background/foreground/font if it didn't change from last shape
    paint_event.gc.send(method_name, *args)
    if property == 'transform' && args.first.is_a?(TransformProxy)
      args.first.swt_transform.dispose
    end
  end
  paint_event.gc.send(@method_name, *@args)
end

#pattern(*args, type: nil) ⇒ Object



257
258
259
260
261
262
263
264
# File 'lib/glimmer/swt/custom/shape.rb', line 257

def pattern(*args, type: nil)
  instance_variable_name = "@#{type}_pattern"
  the_pattern = instance_variable_get(instance_variable_name)
  if the_pattern.nil?
    the_pattern = self.class.pattern(*args)
  end
  the_pattern
end

#post_add_contentObject



134
135
136
137
138
139
140
# File 'lib/glimmer/swt/custom/shape.rb', line 134

def post_add_content
  unless @content_added
    amend_method_name_options_based_on_properties!
    @parent.setup_shape_painting unless @parent.is_a?(ImageProxy)
    @content_added = true
  end
end

#round?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/glimmer/swt/custom/shape.rb', line 122

def round?
  @options[:round]
end

#set_attribute(attribute_name, *args) ⇒ Object



245
246
247
248
249
250
251
# File 'lib/glimmer/swt/custom/shape.rb', line 245

def set_attribute(attribute_name, *args)
  @properties[attribute_name] = args
  if @content_added && !@parent.is_disposed
    @calculated_paint_args = false
    @parent.redraw
  end
end

#tolerate_shape_extra_args!Object

Tolerates shape extra args added by user by mistake (e.g. happens when switching from round rectangle to a standard one without removing all extra args)



216
217
218
219
220
221
222
223
# File 'lib/glimmer/swt/custom/shape.rb', line 216

def tolerate_shape_extra_args!
  the_java_method_arg_count = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.select do |m|
    m.name == @method_name.camelcase(:lower)
  end.map(&:parameter_types).map(&:size).max
  if @args.size > the_java_method_arg_count
    @args[the_java_method_arg_count..-1] = []
  end
end