lib/ProMotion/styling/styling.rb
module ProMotion
module Styling
def set_attributes(element, args = {})
args = get_attributes_from_symbol(args)
ignore_keys = [:transition_style, :presentation_style]
args.each do |k, v|
set_attribute(element, k, v) unless ignore_keys.include?(k)
end
element.send(:on_styled) if element.respond_to?(:on_styled)
element
end
def set_attribute(element, k, v)
return unless element
if !element.is_a?(CALayer) && v.is_a?(Hash) && element.respond_to?("#{k}=")
element.send("#{k}=", v)
elsif v.is_a?(Hash) && element.respond_to?(k)
sub_element = element.send(k)
set_attributes(sub_element, v) if sub_element
elsif element.respond_to?("#{k}=")
element.send("#{k}=", v)
elsif v.is_a?(Array) && element.respond_to?("#{k}") && element.method("#{k}").arity == v.length
element.send("#{k}", *v)
elsif k.to_s.include?("_") # Snake case?
set_attribute(element, camelize(k), v)
else # Warn
mp "set_attribute: #{element.inspect} does not respond to #{k}=.", force_color: :purple
# TODO - remove now, or when fully deprecated - there will be no verbose
# check when logger is removed
mp "BACKTRACE", caller(0).join("\n") if PM.logger.level == :verbose
end
element
end
def content_max(view, mode = :height)
view.subviews.map do |sub_view|
if sub_view.isHidden
0
elsif mode == :height
sub_view.frame.origin.y + sub_view.frame.size.height
else
sub_view.frame.origin.x + sub_view.frame.size.width
end
end.max.to_f
end
def content_height(view)
content_max(view, :height)
end
def content_width(view)
content_max(view, :width)
end
# iterate up the view hierarchy to find the parent element
# of "type" containing this view
def closest_parent(type, this_view = nil)
this_view ||= view_or_self.superview
while this_view != nil do
return this_view if this_view.is_a? type
this_view = this_view.superview
end
nil
end
def add(element, attrs = {})
add_to view_or_self, element, attrs
end
def remove(elements)
Array(elements).each(&:removeFromSuperview)
end
def add_to(parent_element, elements, attrs = {})
attrs = get_attributes_from_symbol(attrs)
Array(elements).each do |element|
parent_element.addSubview element
set_attributes(element, attrs) if attrs && attrs.length > 0
element.send(:on_load) if element.respond_to?(:on_load)
end
elements
end
def view_or_self
self.respond_to?(:view) ? self.view : self
end
# These three color methods are stolen from BubbleWrap.
def rgb_color(r,g,b)
rgba_color(r,g,b,1)
end
def rgba_color(r,g,b,a)
r,g,b = [r,g,b].map { |i| i / 255.0}
UIColor.colorWithRed(r, green: g, blue:b, alpha:a)
end
def hex_color(str)
hex_color = str.gsub("#", "")
case hex_color.size
when 3
colors = hex_color.scan(%r{[0-9A-Fa-f]}).map{ |el| (el * 2).to_i(16) }
when 6
colors = hex_color.scan(%r<[0-9A-Fa-f]{2}>).map{ |el| el.to_i(16) }
else
raise ArgumentError
end
raise ArgumentError unless colors.size == 3
rgb_color(colors[0], colors[1], colors[2])
end
# Turns a snake_case string into a camelCase string.
def camelize(str)
str.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
end
protected
def get_attributes_from_symbol(attrs)
return attrs if attrs.is_a?(Hash)
mp("#{attrs} styling method is not defined", force_color: :red) unless self.respond_to?(attrs)
new_attrs = send(attrs)
mp("#{attrs} should return a hash", force_color: :red) unless new_attrs.is_a?(Hash)
new_attrs
end
def map_resize_symbol(symbol)
@_resize_symbols ||= {
left: UIViewAutoresizingFlexibleLeftMargin,
right: UIViewAutoresizingFlexibleRightMargin,
top: UIViewAutoresizingFlexibleTopMargin,
bottom: UIViewAutoresizingFlexibleBottomMargin,
width: UIViewAutoresizingFlexibleWidth,
height: UIViewAutoresizingFlexibleHeight
}
@_resize_symbols[symbol] || symbol
end
end
end