Skip to content

Instantly share code, notes, and snippets.

@jweinberg
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jweinberg/1c82963125755c2ddbe0 to your computer and use it in GitHub Desktop.
Save jweinberg/1c82963125755c2ddbe0 to your computer and use it in GitHub Desktop.
//
// 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
}
//
// 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