Last active
August 29, 2015 14:02
-
-
Save jweinberg/1c82963125755c2ddbe0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Constraints.swift | |
// ConstraintsTest | |
// | |
import UIKit | |
operator prefix |~ {} | |
operator postfix ~| {} | |
operator infix ~= {associativity none precedence 130} | |
operator infix ~> {associativity none precedence 130} | |
operator infix ~< {associativity none precedence 130} | |
operator infix ~ {associativity left precedence 160} | |
operator infix <> {associativity left precedence 160} | |
func ~=(left: UIView, right: Double) -> LayoutContext { | |
return (left ~= SizeConstraint(nil, right, 1.0, 1000)) | |
} | |
func ~=(left: UIView, right: UIView) -> LayoutContext { | |
return (left ~= SizeConstraint(right, 0, 1.0, 1000)) | |
} | |
func ~=(left: UIView, right: LayoutMargin) -> LayoutContext { | |
return (left ~= SizeConstraint(nil, right.margin, 1.0, right.priority)) | |
} | |
func ~>(left: UIView, right: Double) -> LayoutContext { | |
return (left ~> SizeConstraint(nil, right, 1.0, 1000)) | |
} | |
func ~>(left: UIView, right: LayoutMargin) -> LayoutContext { | |
return (left ~> SizeConstraint(nil, right.margin, 1.0, right.priority)) | |
} | |
func ~>(left: UIView, right: UIView) -> LayoutContext { | |
return (left ~> SizeConstraint(right, 0, 1.0, 1000)) | |
} | |
func ~<(left: UIView, right: Double) -> LayoutContext { | |
return (left ~< SizeConstraint(nil, right, 1.0, 1000)) | |
} | |
func ~<(left: UIView, right: LayoutMargin) -> LayoutContext { | |
return (left ~< SizeConstraint(nil, right.margin, 1.0, right.priority)) | |
} | |
func ~<(left: UIView, right: UIView) -> LayoutContext { | |
return (left ~< SizeConstraint(right, 0, 1.0, 1000)) | |
} | |
func -(left: UIView, right: Double) -> SizeConstraint { | |
return SizeConstraint(left, -right, 1.0, 1000) | |
} | |
func +(left: UIView, right: Double) -> SizeConstraint { | |
return SizeConstraint(left, right, 1.0, 1000) | |
} | |
func /(left: UIView, right: Double) -> SizeConstraint { | |
return SizeConstraint(left, 0, 1.0/right, 1000) | |
} | |
func *(left: UIView, right: Double) -> SizeConstraint { | |
return SizeConstraint(left, 0, right, 1000) | |
} | |
func <>(left: Double, right: Int) -> LayoutMargin { | |
return LayoutMargin(left, right) | |
} | |
func <>(left: SizeConstraint, right: Int) -> SizeConstraint { | |
return SizeConstraint(left.view, left.constant, left.multiplier, right) | |
} | |
@prefix func |~(view: UIView) -> LayoutContext { | |
return (|~LayoutContext(view)) | |
} | |
@prefix func |~(ctx: LayoutContext) -> LayoutContext { | |
return (|~8~ctx) | |
} | |
@postfix func ~|(view: UIView) -> LayoutContext { | |
return (LayoutContext(view)~|) | |
} | |
@postfix func ~|(ctx: LayoutContext) -> LayoutContext { | |
return (ctx~8~|) | |
} | |
@postfix func ~|(margin: Double) -> LayoutStub { | |
return ((margin<>1000)~|) | |
} | |
@prefix func |~(margin: Double) -> LayoutStub { | |
return (|~(margin<>1000)) | |
} | |
@postfix func ~|(margin: LayoutMargin) -> LayoutStub { | |
return LayoutStub(margin, LayoutContext(nil)) | |
} | |
@prefix func |~(margin: LayoutMargin) -> LayoutStub { | |
return LayoutStub(margin, LayoutContext(nil)) | |
} | |
func ~(left: LayoutMargin, right: UIView) -> LayoutStub { | |
return left ~ LayoutContext(right) | |
} | |
func ~(left: UIView, right: LayoutMargin) -> LayoutStub { | |
return LayoutContext(left) ~ right | |
} | |
func ~(left: LayoutMargin, right: LayoutContext) -> LayoutStub { | |
return LayoutStub(left, right) | |
} | |
func ~(left: LayoutContext, right: LayoutMargin) -> LayoutStub { | |
return LayoutStub(right, left) | |
} | |
func ~(left: UIView, right: UIView) -> LayoutContext { | |
return LayoutContext(left) ~ LayoutContext(right) | |
} | |
func ~(left: UIView, right: LayoutContext) -> LayoutContext { | |
return LayoutContext(left) ~ right | |
} | |
func ~(left: LayoutContext, right: UIView) -> LayoutContext { | |
return left ~ LayoutContext(right) | |
} | |
func ~(left: Double, right: UIView) -> LayoutStub { | |
return ((left<>1000)~LayoutContext(right)) | |
} | |
func ~(left: UIView, right: Double) -> LayoutStub { | |
return (LayoutContext(left)~(right<>1000)) | |
} | |
func ~(left: Double, right: LayoutContext) -> LayoutStub { | |
return ((left<>1000) ~ right) | |
} | |
func ~(left: LayoutContext, right: Double) -> LayoutStub { | |
return (left ~ (right<>1000)) | |
} | |
func ~(left: LayoutStub, right: UIView) -> LayoutContext { | |
return (left ~ LayoutContext(right)) | |
} | |
func ~(left: UIView, right: LayoutStub) -> LayoutContext { | |
return (LayoutContext(left) ~ right) | |
} | |
func ~(left: LayoutContext, right: LayoutContext) -> LayoutContext { | |
return left~8~right | |
} | |
func ~=(left: UIView, right: SizeConstraint) -> LayoutContext { | |
var context = LayoutContext(left) | |
var constraint = ConstraintDescriptor(item: left, attribute: .Size, relatedBy: .Equal, toItem: right.view, attribute:.Size, multiplier: right.multiplier, constant: right.constant) | |
constraint.priority = right.priority | |
context.constraints.append(constraint) | |
return context | |
} | |
func ~<(left: UIView, right: SizeConstraint) -> LayoutContext { | |
var context = LayoutContext(left) | |
var constraint = ConstraintDescriptor(item: left, attribute: .Size, relatedBy: .LessThanOrEqual, toItem: right.view, attribute:.Size, multiplier: right.multiplier, constant: right.constant) | |
constraint.priority = right.priority | |
context.constraints.append(constraint) | |
return context | |
} | |
func ~>(left: UIView, right: SizeConstraint) -> LayoutContext { | |
var context = LayoutContext(left) | |
var constraint = ConstraintDescriptor(item: left, attribute: .Size, relatedBy: .GreaterThanOrEqual, toItem: right.view, attribute:.Size, multiplier: right.multiplier, constant: right.constant) | |
constraint.priority = right.priority | |
context.constraints.append(constraint) | |
return context | |
} | |
func ~(left: LayoutStub, right: LayoutContext) -> LayoutContext { | |
var c = LayoutContext(left.context, right) | |
var constraint: ConstraintDescriptor | |
if let bindingView = left.context.rightView { | |
constraint = ConstraintDescriptor(item: bindingView, attribute: .Right, relatedBy: .Equal, toItem:right.leftView, attribute: .Left, multiplier: 1.0, constant: -left.margin.margin) | |
} else { | |
constraint = ConstraintDescriptor(item: right.leftView, attribute: .Left, relatedBy: .Equal, toItem:right.leftView?.superview, attribute: .Left, multiplier: 1.0, constant: left.margin.margin) | |
} | |
constraint.priority = left.margin.priority | |
c.constraints.append(constraint) | |
return c | |
} | |
func ~(left: LayoutContext, right: LayoutStub) -> LayoutContext { | |
var c = LayoutContext(left, right.context) | |
var constraint: ConstraintDescriptor | |
if let bindingView = right.context.leftView { | |
constraint = ConstraintDescriptor(item: left.rightView, attribute: .Right, relatedBy: .Equal, toItem:bindingView, attribute: .Left, multiplier: 1.0, constant: -right.margin.margin) | |
} else { | |
constraint = ConstraintDescriptor(item: left.rightView, attribute: .Right, relatedBy: .Equal, toItem:left.rightView?.superview, attribute: .Right, multiplier: 1.0, constant: -right.margin.margin) | |
} | |
constraint.priority = right.margin.priority | |
c.constraints.append(constraint) | |
return c | |
} | |
func H(context: LayoutContext) -> NSLayoutConstraint[] { | |
return H(context, .Natural) | |
} | |
func H(context: LayoutContext, direction: ConstraintDirection) -> NSLayoutConstraint[] { | |
var constraints = NSLayoutConstraint[]() | |
for constraint in context.constraints { | |
constraints.append(constraint.toConstraint(.Horizontal, direction)) | |
} | |
return constraints | |
} | |
func V(context: LayoutContext) -> NSLayoutConstraint[] { | |
var constraints = NSLayoutConstraint[]() | |
for constraint in context.constraints { | |
constraints.append(constraint.toConstraint(.Vertical, .Natural)) | |
} | |
return constraints | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ConstraintTypes.swift | |
// ConstraintsTest | |
// | |
import UIKit | |
enum ConstraintDirection { | |
case Natural | |
case LTR | |
case RTL | |
} | |
struct ConstraintDescriptor { | |
enum ConstraintType { | |
case Left | |
case Right | |
case Size | |
case None | |
func toAttribute(axis: UILayoutConstraintAxis, _ direction: ConstraintDirection) -> NSLayoutAttribute { | |
switch (axis) { | |
case .Horizontal: | |
switch (self) { | |
case .Left where direction == .Natural: | |
return .Leading | |
case .Right where direction == .Natural: | |
return .Trailing | |
case .Left where direction == .LTR: | |
return .Left | |
case .Right where direction == .LTR: | |
return .Right | |
case .Left where direction == .RTL: | |
return .Right | |
case .Right where direction == .RTL: | |
return .Left | |
case .Size: | |
return .Width | |
default: | |
return .NotAnAttribute | |
} | |
case .Vertical: | |
switch (self) { | |
case .Left: | |
return .Top | |
case .Right: | |
return .Bottom | |
case .Size: | |
return .Height | |
case .None: | |
return .NotAnAttribute | |
} | |
} | |
} | |
} | |
let multiplier: Double | |
let constant: Double | |
let toView: UIView? | |
let fromView: UIView? | |
let relation: NSLayoutRelation | |
let fromAttribute: ConstraintType | |
let toAttribute: ConstraintType | |
var priority: Int | |
init(item: UIView?, attribute fromAttribute: ConstraintType, relatedBy: NSLayoutRelation, toItem: UIView?, attribute toAttribute: ConstraintType, multiplier: Double, constant: Double) { | |
self.fromView = item | |
self.toView = toItem | |
self.toAttribute = toAttribute | |
self.fromAttribute = fromAttribute | |
self.relation = relatedBy | |
self.multiplier = multiplier | |
self.constant = constant | |
self.priority = UILayoutPriorityRequired | |
} | |
func toConstraint(axis: UILayoutConstraintAxis, _ direction: ConstraintDirection) -> NSLayoutConstraint { | |
var adjustedFromAttribute = fromAttribute.toAttribute(axis, direction) | |
var adjustedToAttribute = toAttribute.toAttribute(axis, direction) | |
var adjustedConstant = constant | |
if (axis == .Horizontal) && direction == .RTL { | |
if toAttribute == .Left || toAttribute == .Right { | |
adjustedConstant *= -1 | |
} | |
} | |
var constraint = NSLayoutConstraint(item: fromView, attribute: adjustedFromAttribute, relatedBy:relation, toItem: toView, attribute: adjustedToAttribute, multiplier: CGFloat(multiplier), constant: CGFloat(adjustedConstant)) | |
constraint.priority = UILayoutPriority(priority) | |
return constraint | |
} | |
} | |
struct LayoutContext { | |
var leftView: UIView? | |
var rightView: UIView? | |
var constraints: ConstraintDescriptor[] | |
init(_ left: LayoutContext, _ right: LayoutContext) { | |
leftView = left.leftView | |
rightView = right.rightView | |
constraints = left.constraints + right.constraints | |
} | |
init(_ view: LayoutContext) { | |
leftView = view.leftView | |
rightView = view.rightView | |
constraints = view.constraints | |
} | |
init(_ view: UIView?) { | |
leftView = view | |
rightView = view | |
constraints = ConstraintDescriptor[]() | |
} | |
} | |
struct LayoutStub { | |
let margin: LayoutMargin | |
let context: LayoutContext | |
init(_ margin: LayoutMargin, _ context: LayoutContext) { | |
self.margin = margin | |
self.context = context | |
} | |
} | |
struct LayoutMargin { | |
let margin: Double | |
let priority: Int | |
init(_ margin: Double, _ priority: Int) { | |
self.margin = margin | |
self.priority = priority | |
} | |
} | |
struct SizeConstraint { | |
let view: UIView? | |
let constant: Double | |
let multiplier: Double | |
let priority: Int | |
init(_ view: UIView?, _ constant: Double, _ multiplier: Double, _ priority: Int) { | |
self.view = view | |
self.constant = constant | |
self.multiplier = multiplier | |
self.priority = priority | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment