lib/glimmer/swt/custom/shape.rb in glimmer-dsl-swt-4.18.4.11 vs lib/glimmer/swt/custom/shape.rb in glimmer-dsl-swt-4.18.5.0
- old
+ new
@@ -36,10 +36,19 @@
include Properties
# TODO support textExtent sized shapes nested within text/string
# TODO support a Pattern DSL for methods that take Pattern arguments
class << self
+ def create(parent, keyword, *args, &property_block)
+ potential_shape_class_name = keyword.to_s.camelcase(:upper).to_sym
+ if constants.include?(potential_shape_class_name)
+ const_get(potential_shape_class_name).new(parent, keyword, *args, &property_block)
+ else
+ new(parent, keyword, *args, &property_block)
+ end
+ end
+
def valid?(parent, keyword, *args, &block)
gc_instance_methods.include?(method_name(keyword, arg_options(args)))
end
def gc_instance_methods
@@ -77,19 +86,19 @@
def flyweight_method_names
@flyweight_method_names ||= {}
end
def pattern(*args)
- found_pattern = flyweigh_patterns[args]
+ found_pattern = flyweight_patterns[args]
if found_pattern.nil? || found_pattern.is_disposed
- found_pattern = flyweigh_patterns[args] = org.eclipse.swt.graphics.Pattern.new(*args)
+ found_pattern = flyweight_patterns[args] = org.eclipse.swt.graphics.Pattern.new(*args)
end
found_pattern
end
- def flyweigh_patterns
- @flyweigh_patterns ||= {}
+ def flyweight_patterns
+ @flyweight_patterns ||= {}
end
end
attr_reader :parent, :name, :args, :options
@@ -121,10 +130,33 @@
def round?
@options[:round]
end
+ # subclasses (like polygon) may override to indicate if a point x,y coordinates fall inside the shape
+ # has a default implementation for rectangle and oval
+ def include?(x, y)
+ case @name
+ when 'rectangle', 'oval', 'arc'
+ self_x = self.x
+ self_y = self.y
+ width = self.width
+ height = self.height
+ x.between?(self_x, self_x + width) && y.between?(self_y, self_y + height)
+ else
+ false
+ end
+ end
+
+ def move_by(x_delta, y_delta)
+ case @name
+ when 'rectangle', 'oval', 'arc'
+ self.x += x_delta
+ self.y += y_delta
+ end
+ end
+
def has_some_background?
@properties.keys.map(&:to_s).include?('background') || @properties.keys.map(&:to_s).include?('background_pattern')
end
def has_some_foreground?
@@ -172,22 +204,51 @@
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])
+ @pattern_args ||= {}
+ pattern_type = method_name.to_s.match(/set(.+)Pattern/)[1]
+ if args.first.is_a?(Pattern)
+ new_args = @pattern_args[pattern_type]
+ else
+ new_args = [DisplayProxy.instance.swt_display] + args
+ @pattern_args[pattern_type] = new_args
+ end
+ args[0] = pattern(*new_args, type: pattern_type)
args[1..-1] = []
end
args
end
def apply_shape_arg_conversions!
if @args.size > 1 && (['polygon', 'polyline'].include?(@name))
@args[0] = @args.dup
@args[1..-1] = []
end
+ if @name == 'image'
+ 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
+ if @args.first.nil?
+ @image = nil
+ end
+ end
+ if @name == 'text'
+ if @args[3].is_a?(Symbol) || @args[3].is_a?(String)
+ @args[3] = [@args[3]]
+ end
+ if @args[3].is_a?(Array)
+ if @args[3].size == 1 && @args[3].first.is_a?(Array)
+ @args[3] = @args[3].first
+ end
+ @args[3] = SWTProxy[*@args[3]]
+ end
+ end
end
def apply_shape_arg_defaults!
if @name.include?('rectangle') && round? && @args.size.between?(4, 5)
(6 - @args.size).times {@args << 60}
@@ -200,33 +261,27 @@
@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
# 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)
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
+ if the_java_method_arg_count && @args.to_a.size > the_java_method_arg_count
@args[the_java_method_arg_count..-1] = []
end
end
def amend_method_name_options_based_on_properties!
return if @name == 'point'
- if has_some_background? && !has_some_foreground?
+ if @name != 'text' && 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
@@ -235,31 +290,79 @@
if @name == 'rectangle' && @args.size > 4 && @args.last.is_a?(Numeric)
@options[:round] = true
end
@method_name = self.class.method_name(@name, @options)
end
-
+
+ # parameter names for arguments to pass to SWT GC.xyz method for rendering shape (e.g. draw_image(image, x, y) yields :image, :x, :y parameter names)
+ def parameter_names
+ []
+ end
+
+ def possible_parameter_names
+ parameter_names
+ end
+
+ def parameter_name?(attribute_name)
+ possible_parameter_names.map(&:to_s).include?(ruby_attribute_getter(attribute_name))
+ end
+
+ def parameter_index(attribute_name)
+ parameter_names.map(&:to_s).index(attribute_name.to_s)
+ end
+
+ def set_parameter_attribute(attribute_name, *args)
+ @args[parameter_index(ruby_attribute_getter(attribute_name))] = args.size == 1 ? args.first : args
+ end
+
def has_attribute?(attribute_name, *args)
- self.class.gc_instance_methods.include?(attribute_setter(attribute_name))
+ self.class.gc_instance_methods.include?(attribute_setter(attribute_name)) or
+ parameter_name?(attribute_name)
end
def set_attribute(attribute_name, *args)
- @properties[attribute_name] = args
+ if parameter_name?(attribute_name)
+ set_parameter_attribute(attribute_name, *args)
+ else
+ @properties[attribute_name] = args
+ end
if @content_added && !@parent.is_disposed
@calculated_paint_args = false
@parent.redraw
end
end
def get_attribute(attribute_name)
- @properties.symbolize_keys[attribute_name.to_s.to_sym]
+ if parameter_name?(attribute_name)
+ @args[parameter_index(attribute_name)]
+ else
+ @properties.symbolize_keys[attribute_name.to_s.to_sym]
+ end
end
+ def method_missing(method_name, *args, &block)
+ if method_name.to_s.end_with?('=')
+ set_attribute(method_name, *args)
+ elsif has_attribute?(method_name)
+ get_attribute(method_name)
+ else
+ super
+ end
+ end
+
+ def respond_to?(method_name, *args, &block)
+ if has_attribute?(method_name)
+ true
+ else
+ super
+ end
+ end
+
def pattern(*args, type: nil)
instance_variable_name = "@#{type}_pattern"
the_pattern = instance_variable_get(instance_variable_name)
- if the_pattern.nil?
+ if the_pattern.nil? || the_pattern.is_disposed
the_pattern = self.class.pattern(*args)
end
the_pattern
end
@@ -286,15 +389,19 @@
if property == 'transform' && args.first.is_a?(TransformProxy)
args.first.swt_transform.dispose
end
end
paint_event.gc.send(@method_name, *@args)
+ rescue => e
+ Glimmer::Config.logger.error {"Error encountered in painting shape: #{self.inspect}"}
+ Glimmer::Config.logger.error {e.full_message}
end
def calculate_paint_args!
unless @calculated_paint_args
- if @name == 'point'
+ if @name == 'pixel'
+ @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
@@ -332,5 +439,7 @@
end
end
end
+
+Dir[File.expand_path(File.join(__dir__, 'shape', '**', '*.rb'))].each {|shape_file| require(shape_file)}