diff --git a/Source/ConstraintDescription.swift b/Source/ConstraintDescription.swift index f3a137c..90201d1 100644 --- a/Source/ConstraintDescription.swift +++ b/Source/ConstraintDescription.swift @@ -106,138 +106,231 @@ extension View : RelationTarget { } } +extension ConstraintItem : RelationTarget { + public var constraintItem : ConstraintItem { + return self + } +} + /** Used to expose the final API of a `ConstraintDescription` which allows getting a constraint from it */ -public protocol ConstraintDescriptionFinalizable: class { +public class ConstraintDescriptionFinalizable { - var constraint: Constraint { get } + private let backing : ConstraintDescription + internal init(_ backing : ConstraintDescription) { + self.backing = backing + } + + public var constraint: Constraint { + return backing.constraint + } } /** Used to expose priority APIs */ -public protocol ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable { +public class ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable { - func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable - func priorityRequired() -> ConstraintDescriptionFinalizable - func priorityHigh() -> ConstraintDescriptionFinalizable - func priorityMedium() -> ConstraintDescriptionFinalizable - func priorityLow() -> ConstraintDescriptionFinalizable + public func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priority(priority)) + } + + public func priorityRequired() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityRequired()) + } + public func priorityHigh() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityHigh()) + } + public func priorityMedium() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityMedium()) + } + public func priorityLow() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityLow()) + } } /** Used to expose multiplier & constant APIs */ -public protocol ConstraintDescriptionEditable: ConstraintDescriptionPriortizable { +public class ConstraintDescriptionEditable: ConstraintDescriptionPriortizable { - func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable + public func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.multipliedBy(amount)) + } - func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable - - func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable - func offset(amount: CGPoint) -> ConstraintDescriptionEditable - func offset(amount: CGSize) -> ConstraintDescriptionEditable - func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable + public func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + return self.multipliedBy(1 / amount.floatValue) + } - func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable - func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable + public func offset(amount : FloatConvertible) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + public func offset(amount: CGPoint) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + public func offset(amount: CGSize) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + public func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + + public func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.inset(amount)) + } + public func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.inset(amount)) + } } /** Used to expose relation APIs */ -public protocol ConstraintDescriptionRelatable: class { +public class ConstraintDescriptionRelatable { + + private let backing : ConstraintDescription - func equalTo(other: ConstraintItem) -> ConstraintDescriptionEditable - func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable - @available(iOS 7.0, *) - func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable + init(_ backing : ConstraintDescription) { + self.backing = backing + } - func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable - func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable - @available(iOS 7.0, *) - func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable + + public func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .Equal)) + } + public func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .Equal)) + } - func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable - func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable - @available(iOS 7.0, *) - func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable + public func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .LessThanOrEqualTo)) + } + public func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .LessThanOrEqualTo)) + } + + public func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .GreaterThanOrEqualTo)) + } + public func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .GreaterThanOrEqualTo)) + } } /** Used to expose chaining APIs */ -public protocol ConstraintDescriptionExtendable: ConstraintDescriptionRelatable { +public class ConstraintDescriptionExtendable: ConstraintDescriptionRelatable { - var left: ConstraintDescriptionExtendable { get } - var top: ConstraintDescriptionExtendable { get } - var bottom: ConstraintDescriptionExtendable { get } - var right: ConstraintDescriptionExtendable { get } - var leading: ConstraintDescriptionExtendable { get } - var trailing: ConstraintDescriptionExtendable { get } - var width: ConstraintDescriptionExtendable { get } - var height: ConstraintDescriptionExtendable { get } - var centerX: ConstraintDescriptionExtendable { get } - var centerY: ConstraintDescriptionExtendable { get } - var baseline: ConstraintDescriptionExtendable { get } + public var left: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.left) + } + public var top: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.top) + } + public var bottom: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.bottom) + } + public var right: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.right) + } + public var leading: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.leading) + } + public var trailing: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.trailing) + } + public var width: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.width) + } + public var height: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.height) + } + public var centerX: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerX) + } + public var centerY: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerY) + } + public var baseline: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.baseline) + } @available(iOS 8.0, *) - var firstBaseline: ConstraintDescriptionExtendable { get } + public var firstBaseline: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.firstBaseline) + } @available(iOS 8.0, *) - var leftMargin: ConstraintDescriptionExtendable { get } + public var leftMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.leftMargin) + } @available(iOS 8.0, *) - var rightMargin: ConstraintDescriptionExtendable { get } + public var rightMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.rightMargin) + } @available(iOS 8.0, *) - var topMargin: ConstraintDescriptionExtendable { get } + public var topMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.topMargin) + } @available(iOS 8.0, *) - var bottomMargin: ConstraintDescriptionExtendable { get } + public var bottomMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.bottomMargin) + } @available(iOS 8.0, *) - var leadingMargin: ConstraintDescriptionExtendable { get } + public var leadingMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.leadingMargin) + } @available(iOS 8.0, *) - var trailingMargin: ConstraintDescriptionExtendable { get } + public var trailingMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.trailingMargin) + } @available(iOS 8.0, *) - var centerXWithinMargins: ConstraintDescriptionExtendable { get } + public var centerXWithinMargins: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerXWithinMargins) + } @available(iOS 8.0, *) - var centerYWithinMargins: ConstraintDescriptionExtendable { get } + public var centerYWithinMargins: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerYWithinMargins) + } } /** Used to internally manage building constraint */ -internal class ConstraintDescription: ConstraintDescriptionExtendable, ConstraintDescriptionEditable, ConstraintDescriptionFinalizable { +internal class ConstraintDescription { - internal var left: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Left) } - internal var top: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Top) } - internal var right: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Right) } - internal var bottom: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Bottom) } - internal var leading: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Leading) } - internal var trailing: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Trailing) } - internal var width: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Width) } - internal var height: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Height) } - internal var centerX: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterX) } - internal var centerY: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterY) } - internal var baseline: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Baseline) } + private var left: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Left) } + private var top: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Top) } + private var right: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Right) } + private var bottom: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Bottom) } + private var leading: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Leading) } + private var trailing: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Trailing) } + private var width: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Width) } + private var height: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Height) } + private var centerX: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterX) } + private var centerY: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterY) } + private var baseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Baseline) } @available(iOS 8.0, *) - internal var firstBaseline: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.FirstBaseline) } + private var firstBaseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.FirstBaseline) } @available(iOS 8.0, *) - internal var leftMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.LeftMargin) } + private var leftMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeftMargin) } @available(iOS 8.0, *) - internal var rightMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.RightMargin) } + private var rightMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.RightMargin) } @available(iOS 8.0, *) - internal var topMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.TopMargin) } + private var topMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TopMargin) } @available(iOS 8.0, *) - internal var bottomMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.BottomMargin) } + private var bottomMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.BottomMargin) } @available(iOS 8.0, *) - internal var leadingMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.LeadingMargin) } + private var leadingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeadingMargin) } @available(iOS 8.0, *) - internal var trailingMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.TrailingMargin) } + private var trailingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TrailingMargin) } @available(iOS 8.0, *) - internal var centerXWithinMargins: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } + private var centerXWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } @available(iOS 8.0, *) - internal var centerYWithinMargins: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } + private var centerYWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } // MARK: initializer @@ -246,108 +339,69 @@ internal class ConstraintDescription: ConstraintDescriptionExtendable, Constrain self.toItem = ConstraintItem(object: nil, attributes: ConstraintAttributes.None) } - // MARK: equalTo - - internal func equalTo(other: ConstraintItem) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .Equal) - } - internal func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .Equal) - } - @available(iOS 7.0, *) - internal func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .Equal) - } - - // MARK: lessThanOrEqualTo - - internal func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .LessThanOrEqualTo) - } - internal func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .LessThanOrEqualTo) - } - @available(iOS 7.0, *) - internal func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .LessThanOrEqualTo) - } - - // MARK: greaterThanOrEqualTo - - internal func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .GreaterThanOrEqualTo) - } - internal func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .GreaterThanOrEqualTo) - } - @available(iOS 7.0, *) - internal func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .GreaterThanOrEqualTo) - } - // MARK: multiplier - internal func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func multipliedBy(amount: FloatConvertible) -> ConstraintDescription { self.multiplier = amount.floatValue return self } - internal func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func dividedBy(amount: FloatConvertible) -> ConstraintDescription { self.multiplier = 1.0 / amount.floatValue; return self } // MARK: offset - internal func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func offset(amount: FloatConvertible) -> ConstraintDescription { self.constant = amount.floatValue return self } - internal func offset(amount: CGPoint) -> ConstraintDescriptionEditable { + private func offset(amount: CGPoint) -> ConstraintDescription { self.constant = amount return self } - internal func offset(amount: CGSize) -> ConstraintDescriptionEditable { + private func offset(amount: CGSize) -> ConstraintDescription { self.constant = amount return self } - internal func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + private func offset(amount: EdgeInsets) -> ConstraintDescription { self.constant = amount return self } // MARK: inset - internal func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func inset(amount: FloatConvertible) -> ConstraintDescription { let value = CGFloat(amount.floatValue) self.constant = EdgeInsets(top: value, left: value, bottom: -value, right: -value) return self } - internal func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + private func inset(amount: EdgeInsets) -> ConstraintDescription { self.constant = EdgeInsets(top: amount.top, left: amount.left, bottom: -amount.bottom, right: -amount.right) return self } // MARK: priority - internal func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable { + private func priority(priority: FloatConvertible) -> ConstraintDescription { self.priority = priority.floatValue return self } - internal func priorityRequired() -> ConstraintDescriptionFinalizable { + private func priorityRequired() -> ConstraintDescription { return self.priority(1000.0) } - internal func priorityHigh() -> ConstraintDescriptionFinalizable { + private func priorityHigh() -> ConstraintDescription { return self.priority(750.0) } - internal func priorityMedium() -> ConstraintDescriptionFinalizable { + private func priorityMedium() -> ConstraintDescription { #if os(iOS) || os(tvOS) return self.priority(500.0) #else return self.priority(501.0) #endif } - internal func priorityLow() -> ConstraintDescriptionFinalizable { + private func priorityLow() -> ConstraintDescription { return self.priority(250.0) } @@ -416,35 +470,32 @@ internal class ConstraintDescription: ConstraintDescriptionExtendable, Constrain return self } - private func constrainTo(other: ConstraintItem, relation: ConstraintRelation) -> ConstraintDescription { - if other.attributes != ConstraintAttributes.None { - let toLayoutAttributes = other.attributes.layoutAttributes + private func constrainTo(other: RelationTarget, relation: ConstraintRelation) -> ConstraintDescription { + if let constant = other as? FloatConvertible { + self.constant = constant.floatValue + } + + let item = other.constraintItem + + if item.attributes != ConstraintAttributes.None { + let toLayoutAttributes = item.attributes.layoutAttributes if toLayoutAttributes.count > 1 { let fromLayoutAttributes = self.fromItem.attributes.layoutAttributes if toLayoutAttributes != fromLayoutAttributes { NSException(name: "Invalid Constraint", reason: "Cannot constrain to multiple non identical attributes", userInfo: nil).raise() return self } - other.attributes = ConstraintAttributes.None + item.attributes = ConstraintAttributes.None } } - self.toItem = other + self.toItem = item self.relation = relation return self } - private func constrainTo(other: RelationTarget, relation: ConstraintRelation) -> ConstraintDescription { - return constrainTo(other.constraintItem, relation: relation) - } - @available(iOS 7.0, *) private func constrainTo(other: LayoutSupport, relation: ConstraintRelation) -> ConstraintDescription { - return constrainTo(ConstraintItem(object: self, attributes: ConstraintAttributes.None), relation: relation) - } - - private func constrainTo(other: FloatConvertible, relation: ConstraintRelation) -> ConstraintDescription { - self.constant = other.floatValue - return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) + return constrainTo(ConstraintItem(object: other, attributes: ConstraintAttributes.None), relation: relation, location: location) } } diff --git a/Source/ConstraintMaker.swift b/Source/ConstraintMaker.swift index 154b9dd..be38201 100644 --- a/Source/ConstraintMaker.swift +++ b/Source/ConstraintMaker.swift @@ -129,11 +129,11 @@ public class ConstraintMaker { internal let view: View internal var constraintDescriptions = [ConstraintDescription]() - internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescription { + internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescriptionExtendable { let item = ConstraintItem(object: self.view, attributes: attributes) let constraintDescription = ConstraintDescription(fromItem: item) self.constraintDescriptions.append(constraintDescription) - return constraintDescription + return ConstraintDescriptionExtendable(constraintDescription) } internal class func prepareConstraints(view view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {