// // KeyPath.swift // Popsicle // // Created by David Román Aguirre on 04/11/15. // Copyright © 2015 David Román Aguirre. All rights reserved. // /// `KeyPathable` defines how a value is transformed to a valid `NSObject` key path. public protocol KeyPathable { func stringify() -> String } extension String : KeyPathable { public func stringify() -> String { return self } } extension NSLayoutAttribute: KeyPathable { public func stringify() -> String { var type = "UnknownAttribute" switch(self) { case .Left: type = "Left" case .Right: type = "Right" case .Top: type = "Top" case .Bottom: type = "Bottom" case .Leading: type = "Leading" case .Trailing: type = "Trailing" case .Width: type = "Width" case .Height: type = "Height" case .CenterX: type = "CenterX" case .CenterY: type = "CenterY" case .Baseline: type = "Baseline" case .FirstBaseline: type = "FirstBaseline" case .LeftMargin: type = "LeftMargin" case .RightMargin: type = "RightMargin" case .TopMargin: type = "TopMargin" case .BottomMargin: type = "BottomMargin" case .LeadingMargin: type = "LeadingMargin" case .TrailingMargin: type = "TrailingMargin" case .CenterXWithinMargins: type = "CenterXWithinMargins" case .CenterYWithinMargins: type = "CenterYWithinMargins" case .NotAnAttribute: type = "NotAnAttribute" } return "NSLayoutAttribute." + type } } /// `KeyPath` defines a `NSObject`'s key path, constrained to specific `NSObject` and `Interpolable` types for higher safety. public struct KeyPath { let keyPathable: KeyPathable public init(keyPathable: KeyPathable) { self.keyPathable = keyPathable } } public let alpha = KeyPath(keyPathable: "alpha") public let backgroundColor = KeyPath(keyPathable: "backgroundColor") public let barTintColor = KeyPath(keyPathable: "barTintColor") public let borderColor = KeyPath(keyPathable: "borderColor") public let borderWidth = KeyPath(keyPathable: "borderWidth") public let constant = KeyPath(keyPathable: "constant") public let cornerRadius = KeyPath(keyPathable: "cornerRadius") public let hidden = KeyPath(keyPathable: "hidden") public let textColor = KeyPath(keyPathable: "textColor") public let tintColor = KeyPath(keyPathable: "tintColor") public let transform = KeyPath(keyPathable: "transform") public let baselineConstraint = KeyPath(keyPathable: NSLayoutAttribute.Baseline) public let firstBaselineConstraint = KeyPath(keyPathable: NSLayoutAttribute.FirstBaseline) public let topConstraint = KeyPath(keyPathable: NSLayoutAttribute.Top) public let leftConstraint = KeyPath(keyPathable: NSLayoutAttribute.Left) public let rightConstraint = KeyPath(keyPathable: NSLayoutAttribute.Right) public let bottomConstraint = KeyPath(keyPathable: NSLayoutAttribute.Bottom) public let leadingConstraint = KeyPath(keyPathable: NSLayoutAttribute.Leading) public let trailingConstraint = KeyPath(keyPathable: NSLayoutAttribute.Trailing) public let leftMarginConstraint = KeyPath(keyPathable: NSLayoutAttribute.LeftMargin) public let rightMarginConstraint = KeyPath(keyPathable: NSLayoutAttribute.RightMargin) public let topMarginConstraint = KeyPath(keyPathable: NSLayoutAttribute.TopMargin) public let bottomMarginConstraint = KeyPath(keyPathable: NSLayoutAttribute.BottomMargin) public let leadingMarginConstraint = KeyPath(keyPathable: NSLayoutAttribute.LeadingMargin) public let trailingMarginConstraint = KeyPath(keyPathable: NSLayoutAttribute.TrailingMargin) public let centerXConstraint = KeyPath(keyPathable: NSLayoutAttribute.CenterX) public let centerYConstraint = KeyPath(keyPathable: NSLayoutAttribute.CenterY) public let centerXWithinMarginsConstraint = KeyPath(keyPathable: NSLayoutAttribute.CenterXWithinMargins) public let centerYWithinMarginsConstraint = KeyPath(keyPathable: NSLayoutAttribute.CenterYWithinMargins) public let widthConstraint = KeyPath(keyPathable: NSLayoutAttribute.Width) public let heightConstraint = KeyPath(keyPathable: NSLayoutAttribute.Height) extension NSObject { static func filteredObjectAndKeyPath(withObject object: T, andKeyPath keyPath: KeyPath) -> (NSObject, String) { if let view = object as? UIView, let superview = view.superview, let attribute = keyPath.keyPathable as? NSLayoutAttribute { let constrainedView = (attribute == .Width || attribute == .Height) ? view : superview for constraint in constrainedView.constraints where !constraint.isKindOfClass(NSClassFromString("NSContentSizeLayoutConstraint")!) && ((constraint.firstItem as? NSObject == view && constraint.firstAttribute == attribute) || (constraint.secondItem as? NSObject == view && constraint.secondAttribute == attribute)) { return (constraint, constant.keyPathable.stringify()) } } return (object, keyPath.keyPathable.stringify()) } }