├── SwiftVisualFormat.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── SwiftVisualFormat
├── AppDelegate.swift
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── ViewController.swift
├── Info.plist
└── Base.lproj
│ └── Main.storyboard
├── .gitignore
├── SwiftVisualFormatTests
├── Info.plist
└── SwiftVisualFormatTests.swift
├── LICENSE
├── Readme.markdown
└── VisualFormat.swift
/SwiftVisualFormat.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftVisualFormat/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftVisualFormat
4 | //
5 | // Created by Bridger Maxwell on 8/1/14.
6 | // Copyright (c) 2014 Bridger Maxwell. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 | var window: UIWindow?
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 | *.DS_Store
20 |
21 | # CocoaPods
22 | #
23 | # We recommend against adding the Pods directory to your .gitignore. However
24 | # you should judge for yourself, the pros and cons are mentioned at:
25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
26 | #
27 | # Pods/
--------------------------------------------------------------------------------
/SwiftVisualFormatTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.bridgermaxwell.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SwiftVisualFormat/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "ipad",
20 | "size" : "29x29",
21 | "scale" : "1x"
22 | },
23 | {
24 | "idiom" : "ipad",
25 | "size" : "29x29",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "ipad",
30 | "size" : "40x40",
31 | "scale" : "1x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "40x40",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "76x76",
41 | "scale" : "1x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "76x76",
46 | "scale" : "2x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Bridger Maxwell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/SwiftVisualFormat/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | },
18 | {
19 | "orientation" : "portrait",
20 | "idiom" : "ipad",
21 | "extent" : "full-screen",
22 | "minimum-system-version" : "7.0",
23 | "scale" : "1x"
24 | },
25 | {
26 | "orientation" : "landscape",
27 | "idiom" : "ipad",
28 | "extent" : "full-screen",
29 | "minimum-system-version" : "7.0",
30 | "scale" : "1x"
31 | },
32 | {
33 | "orientation" : "portrait",
34 | "idiom" : "ipad",
35 | "extent" : "full-screen",
36 | "minimum-system-version" : "7.0",
37 | "scale" : "2x"
38 | },
39 | {
40 | "orientation" : "landscape",
41 | "idiom" : "ipad",
42 | "extent" : "full-screen",
43 | "minimum-system-version" : "7.0",
44 | "scale" : "2x"
45 | }
46 | ],
47 | "info" : {
48 | "version" : 1,
49 | "author" : "xcode"
50 | }
51 | }
--------------------------------------------------------------------------------
/SwiftVisualFormat/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SwiftVisualFormat
4 | //
5 | // Created by Bridger Maxwell on 8/1/14.
6 | // Copyright (c) 2014 Bridger Maxwell. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let redView = UIView()
17 | redView.backgroundColor = UIColor.redColor()
18 | redView.translatesAutoresizingMaskIntoConstraints = false
19 | self.view.addSubview(redView)
20 |
21 | let greenView = UIView()
22 | greenView.backgroundColor = UIColor.greenColor()
23 | greenView.translatesAutoresizingMaskIntoConstraints = false
24 | self.view.addSubview(greenView)
25 |
26 | let blueView = UIView()
27 | blueView.backgroundColor = UIColor.blueColor()
28 | blueView.translatesAutoresizingMaskIntoConstraints = false
29 | self.view.addSubview(blueView)
30 |
31 | self.view.addConstraints(horizontalConstraints( |-5-[redView]-0-[greenView]-0-[blueView]-5-| ))
32 |
33 | self.view.addConstraints(horizontalConstraints( [redView == greenView] ))
34 | self.view.addConstraints(horizontalConstraints( [blueView == greenView] ))
35 |
36 | self.view.addConstraints(verticalConstraints( |-5-[redView]-5-| ))
37 | self.view.addConstraints(verticalConstraints( |-5-[greenView]-5-| ))
38 | self.view.addConstraints(verticalConstraints( |-5-[blueView]-5-| ))
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/SwiftVisualFormat/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.bridgermaxwell.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/SwiftVisualFormat/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Readme.markdown:
--------------------------------------------------------------------------------
1 | Swift Visual Format Language
2 | ===
3 |
4 | This project is an attempt to bring the [Auto Layout Visual Format Language](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage/VisualFormatLanguage.html) to Swift, without requiring strings or dictionaries. It uses some crazy operator overloading instead. Using it looks like this:
5 |
6 | view.addConstraints(horizontalConstraints( |-5-[redView]-0-[greenView]-0-[blueView]-5-| ))
7 |
8 | // Make backgroundView fill its container
9 | view.addConstraints(horizontalConstraints( |[backgroundView]| ))
10 | view.addConstraints(verticalConstraints( |[backgroundView]| ))
11 |
12 | **This project is not finished. Nor is it necessarily a good idea. See the todo section and the drawbacks discussion. Feel free to play around with this code, but I wouldn't use it in a project yet.**
13 |
14 | The purpose of the Visual Format Language is to make code that does layout _look_ like layout. Views are in brackets to look like rectangles `[view]`. Spaces between views are hyphens, like `[view]-5-[view2]`. The containing view is represented by a vertical bar, `|-0-[fullWidthView]-0-|`.
15 |
16 | More Examples
17 | ---
18 |
19 | These examples contrast the visual format with the resulting constraints represented by the equation-based [SwiftAutoLayout package from indragiek](https://github.com/indragiek/SwiftAutoLayout). There are constraints that the visual format can't represent (such as aspect ratios), but the equations are much harder to skim.
20 |
21 | horizontalConstraints( [redView]-10-[greenView] )
22 | greenView.al_leading == redView.al_trailing + 10
23 |
24 | verticalConstraints( |-5-[redView]-5-| )
25 | redView.al_top == redView.superview.al_top + 5
26 | redView.superview.al_bottom == redView.al_bottom + 5
27 |
28 | horizontalConstraints( [greenView == redView]-0-[blueView == greenView] )
29 | greenView.al_width == redView.al_width
30 | blueView.al_leading == greenView.al_trailing
31 | blueView.al_width == greenView.al_width
32 |
33 | // Impossible to represent in the visual format language
34 | greenView.al_width = 0.5 * greenView.al_height
35 |
36 | Okay, so maybe the width constraints are easier to read in the equation format.
37 |
38 | Drawbacks from the Objective-C / String API
39 | ---
40 |
41 | The Objective-C API was string-based, meaning that the visual format language was in a string with the tokens in the string mapped to views or constants via a dictionary. Accessed from Swift, this looked like this:
42 |
43 | let views = ["redView" : redView, "greenView" : greenView, "blueView": blueView]
44 | self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-5-[redView]-0-[greenView]-0-[blueView]-5-|", options: nil, metrics: nil, views: views))
45 |
46 | The string-based API has *much* better error messages. For example, when you type in the faulty format `|-0-[redView-0-|` you get the error
47 |
48 | Unable to parse constraint format:
49 | Expected a ']' here. That is how you give the end of a view.
50 | |-0-[redView-0-|
51 | ^
52 |
53 | That same faulty format in Swift gives you the unintelligble error
54 |
55 | Expected ',' separator
56 |
57 |
58 | Because it was string-based, the language didn't have many constraints and could be designed better. For example, for width constraints `"[redView(>=greenView)][greenView]"` looks much better than `[redView >= greenView]-0-[greenView]`, but is not possible (as far as I can tell) with operator overloading.
59 |
60 | The Objectice-C API is also able to do the "standard space" between controls. For example `"[button]-[textField]"` creates a constraint for whatever the correct space between a button and a textField should be. There is no other API for doing this.
61 |
62 | Benefits over Objective-C / String API
63 | ---
64 |
65 | There are some benefits to the Swift approach, mostly due to the fact that the compiler is involved in parsing the constraints intead of parsing a string at runtime.
66 |
67 | If you have an invalid constraint format, it probably won't compile. You don't have to build and run to find that out. There are still some cases where I wasn't able to enforce every rule of the grammar through the type system and operator overloading and you will get a runtime crash instead, but I hope these are encountered rarely. The compiler errors aren't generally useful (see above), but at least they are early.
68 |
69 | The biggest benefit is that you can use the view names directly without putting them into a string and a dictionary mapping them from names. The `NSDictionaryOfVariableBindings` macro isn't available in Swift, so it is a pain to declare a views dictionary. It basically meant that to make one constraint you need to type the view's name three times, with two of those times being in a string not checked by the compiler.
70 |
71 | Another, smaller, benefit is that it is easier to use the same format for either Horizontal or Vertical layout. In the string-based API, I would append either `"H:"` or `"V:"` to the string. Now just use the `toConstraints(.Vertical, [redView]-0-[greenView] )` and change the axis parameter.
72 |
73 |
74 | To Do
75 | ---
76 | - Inequalities like >= or <= aren't supported for spaces between views. It should support `|->=5-[redView]-<=10-[greenView]-==0-|`
77 | - Priorities aren't supported. I am planning to use the ! operator, if it can be infix. For example, to make a high priority constraint it should look like `[redView.al]-10.al!750.al-[greenView.al]`
78 | - Figure out the best way to distribute this. Cocoapods? As a framework?
79 |
--------------------------------------------------------------------------------
/SwiftVisualFormatTests/SwiftVisualFormatTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftVisualFormatTests.swift
3 | // SwiftVisualFormatTests
4 | //
5 | // Created by Bridger Maxwell on 8/1/14.
6 | // Copyright (c) 2014 Bridger Maxwell. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import XCTest
11 |
12 | class SwiftVisualFormatTests: XCTestCase {
13 |
14 | var containerView: UIView!
15 | var redView: UIView!
16 | var greenView: UIView!
17 | var blueView: UIView!
18 |
19 | override func setUp() {
20 | super.setUp()
21 |
22 | let containerView = UIView()
23 | containerView.translatesAutoresizingMaskIntoConstraints = false
24 | self.containerView = containerView
25 |
26 | let redView = UIView()
27 | redView.backgroundColor = UIColor.redColor()
28 | redView.translatesAutoresizingMaskIntoConstraints = false
29 | self.containerView.addSubview(redView)
30 | self.redView = redView
31 |
32 | let greenView = UIView()
33 | greenView.backgroundColor = UIColor.greenColor()
34 | greenView.translatesAutoresizingMaskIntoConstraints = false
35 | self.containerView.addSubview(greenView)
36 | self.greenView = greenView
37 |
38 | let blueView = UIView()
39 | blueView.backgroundColor = UIColor.blueColor()
40 | blueView.translatesAutoresizingMaskIntoConstraints = false
41 | self.containerView.addSubview(blueView)
42 | self.blueView = blueView
43 | }
44 |
45 | override func tearDown() {
46 | // Put teardown code here. This method is called after the invocation of each test method in the class.
47 | super.tearDown()
48 | }
49 |
50 | func compareConstraints(visualFormatString: String, checkedConstraints: [NSLayoutConstraint]) {
51 | let views = ["redView" : redView, "blueView" : blueView, "greenView" : greenView]
52 | let referenceConstraints = NSLayoutConstraint.constraintsWithVisualFormat(visualFormatString, options: [], metrics: nil, views: views) as [NSLayoutConstraint]
53 |
54 | XCTAssertEqual(checkedConstraints.count, referenceConstraints.count, "The correct amount of constraints wasn't created")
55 |
56 | for constraint in referenceConstraints {
57 |
58 | var foundMatch = false
59 | for checkConstraint in checkedConstraints {
60 | if (constraint.firstItem === checkConstraint.firstItem &&
61 | constraint.firstAttribute == checkConstraint.firstAttribute &&
62 | constraint.relation == checkConstraint.relation &&
63 | constraint.secondItem === checkConstraint.secondItem &&
64 | constraint.secondAttribute == checkConstraint.secondAttribute &&
65 | constraint.multiplier == checkConstraint.multiplier &&
66 | constraint.constant == checkConstraint.constant &&
67 | constraint.priority == checkConstraint.priority) {
68 |
69 | foundMatch = true
70 | break;
71 | }
72 | }
73 |
74 | XCTAssert(foundMatch, "The reference constraint \( constraint ) was not found in the created constraints: \(checkedConstraints)")
75 | }
76 | }
77 |
78 | func compareHorizontalAndVerticalConstraints(formatString: String, constraintAble: [ConstraintAble]) {
79 | compareConstraints("H:" + formatString, checkedConstraints: constraints(.Horizontal, constraintAble: constraintAble))
80 | compareConstraints("V:" + formatString, checkedConstraints: constraints(.Vertical, constraintAble: constraintAble))
81 | }
82 |
83 | func testSuperviewSpace() {
84 | compareHorizontalAndVerticalConstraints("|-5-[redView]", constraintAble: |-5-[redView] )
85 | compareHorizontalAndVerticalConstraints("|[redView]", constraintAble: |[redView] )
86 | compareHorizontalAndVerticalConstraints("[redView]-5-|", constraintAble: [redView]-5-| )
87 | compareHorizontalAndVerticalConstraints("[redView]|", constraintAble: [redView]| )
88 |
89 | compareHorizontalAndVerticalConstraints("|[redView]|", constraintAble: |[redView]| )
90 | compareHorizontalAndVerticalConstraints("|-5-[redView]|", constraintAble: |-5-[redView]| )
91 | compareHorizontalAndVerticalConstraints("|[redView]-5-|", constraintAble: |[redView]-5-| )
92 | }
93 |
94 | func testWidthConstraints() {
95 | compareHorizontalAndVerticalConstraints("[redView(==greenView)]", constraintAble: [redView==greenView] )
96 | compareHorizontalAndVerticalConstraints("[redView(>=greenView)]", constraintAble: [redView>=greenView] )
97 | compareHorizontalAndVerticalConstraints("[redView(<=greenView)]", constraintAble: [redView<=greenView] )
98 | }
99 |
100 | func testSpaceConstraints() {
101 | compareHorizontalAndVerticalConstraints("[redView]-5-[greenView]", constraintAble: [redView]-5-[greenView] )
102 | compareHorizontalAndVerticalConstraints("[redView]-0-[greenView]", constraintAble: [redView]-0-[greenView] )
103 | }
104 |
105 | func testCombinedConstraints() {
106 | compareHorizontalAndVerticalConstraints("|-5-[redView(>=blueView)]-10-[greenView]-15-[blueView]-20-|", constraintAble: |-5-[redView >= blueView]-10-[greenView]-15-[blueView]-20-| )
107 | compareHorizontalAndVerticalConstraints("|[redView(>=blueView)]-10-[greenView]-15-[blueView]-20-|", constraintAble: |[redView >= blueView]-10-[greenView]-15-[blueView]-20-| )
108 | compareHorizontalAndVerticalConstraints("|-5-[redView(>=blueView)]-10-[greenView]-15-[blueView]|", constraintAble: |-5-[redView >= blueView]-10-[greenView]-15-[blueView]| )
109 |
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/VisualFormat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VisualFormat.swift
3 | // SwiftVisualFormat
4 | //
5 | // Created by Bridger Maxwell on 8/1/14.
6 | // Copyright (c) 2014 Bridger Maxwell. All rights reserved.
7 | //
8 |
9 | #if os(OSX)
10 | import AppKit
11 | public typealias ALVFView = NSView
12 | #elseif os(iOS)
13 | import UIKit
14 | public typealias ALVFView = UIView
15 | #endif
16 |
17 | extension ALVFView {
18 | public func addVerticalConstraints(constraintAble: [ConstraintAble]) {
19 | self.addConstraints(verticalConstraints(constraintAble))
20 | }
21 |
22 | public func addHorizontalConstraints(constraintAble: [ConstraintAble]) {
23 | self.addConstraints(horizontalConstraints(constraintAble))
24 | }
25 | }
26 |
27 | @objc public protocol ConstraintAble {
28 | func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint];
29 | }
30 |
31 | public func constraints(axis: UILayoutConstraintAxis, constraintAble: [ConstraintAble]) -> [NSLayoutConstraint] {
32 | return constraintAble[0].toConstraints(axis)
33 | }
34 |
35 | public func horizontalConstraints(constraintAble: [ConstraintAble]) -> [NSLayoutConstraint] {
36 | return constraints(.Horizontal, constraintAble: constraintAble)
37 | }
38 |
39 | public func verticalConstraints(constraintAble: [ConstraintAble]) -> [NSLayoutConstraint] {
40 | return constraints(.Vertical, constraintAble: constraintAble)
41 | }
42 |
43 |
44 | @objc public protocol ViewContainingToken : ConstraintAble {
45 | var firstView: ALVFView? { get }
46 | var lastView: ALVFView? { get }
47 | }
48 |
49 | protocol ConstantToken {
50 | var ALConstant: CGFloat { get }
51 | }
52 |
53 | // This is half of a space constraint, [view]-space
54 | class ViewAndSpaceToken : NSObject {
55 | let view: ViewContainingToken
56 | let space: ConstantToken
57 | let relation: NSLayoutRelation
58 | init(view: ViewContainingToken, space: ConstantToken, relation: NSLayoutRelation) {
59 | self.view = view
60 | self.space = space
61 | self.relation = relation
62 | }
63 | }
64 |
65 | // This is half of a space constraint, |-5
66 | class LeadingSuperviewAndSpaceToken : NSObject {
67 | let space: ConstantToken
68 | let relation: NSLayoutRelation
69 | init(space: ConstantToken, relation: NSLayoutRelation) {
70 | self.space = space
71 | self.relation = relation
72 | }
73 | }
74 | // This is half of a space constraint, 5-|
75 | class TrailingSuperviewAndSpaceToken : NSObject {
76 | let space: ConstantToken
77 | init(space: ConstantToken) {
78 | self.space = space
79 | }
80 | }
81 |
82 | // [view]-5-[view2]
83 | class SpacedViewsConstraintToken: NSObject, ConstraintAble, ViewContainingToken {
84 | let leadingView: ViewContainingToken
85 | let trailingView: ViewContainingToken
86 | let space: ConstantToken
87 |
88 | init(leadingView: ViewContainingToken, trailingView: ViewContainingToken, space: ConstantToken) {
89 | self.leadingView = leadingView
90 | self.trailingView = trailingView
91 | self.space = space
92 | }
93 |
94 | var firstView: UIView? {
95 | get {
96 | return self.leadingView.firstView
97 | }
98 | }
99 | var lastView: UIView? {
100 | get {
101 | return self.trailingView.lastView
102 | }
103 | }
104 |
105 |
106 | func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint] {
107 | if let leadingView = self.leadingView.lastView {
108 | if let trailingView = self.trailingView.firstView {
109 | let space = self.space.ALConstant
110 |
111 | var leadingAttribute: NSLayoutAttribute!
112 | var trailingAttribute: NSLayoutAttribute!
113 | if (axis == .Horizontal) {
114 | leadingAttribute = .Leading
115 | trailingAttribute = .Trailing
116 | } else {
117 | leadingAttribute = .Top
118 | trailingAttribute = .Bottom
119 | }
120 |
121 | var constraints = [NSLayoutConstraint(
122 | item: trailingView, attribute: leadingAttribute,
123 | relatedBy: .Equal,
124 | toItem: leadingView, attribute: trailingAttribute,
125 | multiplier: 1.0, constant: space)]
126 |
127 | constraints += self.leadingView.toConstraints(axis)
128 | constraints += self.trailingView.toConstraints(axis)
129 |
130 | return constraints
131 | }
132 | }
133 |
134 | NSException(name: NSInvalidArgumentException, reason: "This space constraint was between two view items that couldn't fit together. Weird?", userInfo: nil).raise()
135 | return [] // To appease the compiler, which doesn't realize this branch dies
136 | }
137 | }
138 |
139 | // [view == 50]
140 | class SizeConstantConstraintToken: NSObject, ConstraintAble, ViewContainingToken {
141 | let view: ALVFView
142 | let size: ConstantToken
143 | let relation: NSLayoutRelation
144 | init(view: ALVFView, size: ConstantToken, relation: NSLayoutRelation) {
145 | self.view = view
146 | self.size = size
147 | self.relation = relation
148 | }
149 |
150 | var firstView: ALVFView? {
151 | get {
152 | return self.view.firstView
153 | }
154 | }
155 | var lastView: ALVFView? {
156 | get {
157 | return self.view.lastView
158 | }
159 | }
160 |
161 | func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint] {
162 | let constant = self.size.ALConstant
163 |
164 | var attribute: NSLayoutAttribute!
165 | if (axis == .Horizontal) {
166 | attribute = .Width
167 | } else {
168 | attribute = .Height
169 | }
170 | let constraint = NSLayoutConstraint(
171 | item: self.view, attribute: attribute,
172 | relatedBy: self.relation,
173 | toItem: nil, attribute: .NotAnAttribute,
174 | multiplier: 1.0, constant: constant)
175 |
176 | return [constraint]
177 | }
178 |
179 | }
180 |
181 | // [view == view2]
182 | class SizeRelationConstraintToken: NSObject, ConstraintAble, ViewContainingToken {
183 | let view: ALVFView
184 | let relatedView: ALVFView
185 | let relation: NSLayoutRelation
186 | init(view: ALVFView, relatedView: ALVFView, relation: NSLayoutRelation) {
187 | self.view = view
188 | self.relatedView = relatedView
189 | self.relation = relation
190 | }
191 |
192 | var firstView: ALVFView? {
193 | get {
194 | return self.view.firstView
195 | }
196 | }
197 | var lastView: ALVFView? {
198 | get {
199 | return self.view.lastView
200 | }
201 | }
202 |
203 | func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint] {
204 | var attribute: NSLayoutAttribute!
205 | if (axis == .Horizontal) {
206 | attribute = .Width
207 | } else {
208 | attribute = .Height
209 | }
210 | return [ NSLayoutConstraint(
211 | item: self.view, attribute: attribute,
212 | relatedBy: self.relation,
213 | toItem: self.relatedView, attribute: attribute,
214 | multiplier: 1.0, constant: 0) ]
215 | }
216 | }
217 |
218 | // |-5-[view]
219 | public class LeadingSuperviewConstraintToken: NSObject, ConstraintAble, ViewContainingToken {
220 | let viewContainer: ViewContainingToken
221 | let space: ConstantToken
222 | init(viewContainer: ViewContainingToken, space: ConstantToken) {
223 | self.viewContainer = viewContainer
224 | self.space = space
225 | }
226 | public var firstView: UIView? {
227 | get {
228 | return nil // No one can bind to our first view, is the superview
229 | }
230 | }
231 | public var lastView: UIView? {
232 | get {
233 | return self.viewContainer.lastView
234 | }
235 | }
236 |
237 | public func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint] {
238 | if let view = self.viewContainer.firstView {
239 | let constant = self.space.ALConstant
240 |
241 | if let superview = view.superview {
242 | var constraint: NSLayoutConstraint!
243 |
244 | if (axis == .Horizontal) {
245 | constraint = NSLayoutConstraint(
246 | item: view, attribute: .Leading,
247 | relatedBy: .Equal,
248 | toItem: superview, attribute: .Leading,
249 | multiplier: 1.0, constant: constant)
250 | } else {
251 | constraint = NSLayoutConstraint(
252 | item: view, attribute: .Top,
253 | relatedBy: .Equal,
254 | toItem: superview, attribute: .Top,
255 | multiplier: 1.0, constant: constant)
256 | }
257 |
258 | return viewContainer.toConstraints(axis) + [constraint]
259 | }
260 | NSException(name: NSInvalidArgumentException, reason: "You tried to create a constraint to \(view)'s superview, but it has no superview yet!", userInfo: nil).raise()
261 | }
262 | NSException(name: NSInvalidArgumentException, reason: "This superview bar | was before something that doesn't have a view. Weird?", userInfo: nil).raise()
263 | return [] // To appease the compiler, which doesn't realize this branch dies
264 | }
265 | }
266 |
267 | // [view]-5-|
268 | public class TrailingSuperviewConstraintToken: NSObject, ConstraintAble, ViewContainingToken {
269 | let viewContainer: ViewContainingToken
270 | let space: ConstantToken
271 | init(viewContainer: ViewContainingToken, space: ConstantToken) {
272 | self.viewContainer = viewContainer
273 | self.space = space
274 | }
275 | public var firstView: UIView? {
276 | get {
277 | return self.viewContainer.firstView
278 | }
279 | }
280 | public var lastView: UIView? {
281 | get {
282 | return nil // No one can bind to our last view, is the superview
283 | }
284 | }
285 |
286 | public func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint] {
287 | if let view = self.viewContainer.lastView {
288 | let constant = self.space.ALConstant
289 |
290 | if let superview = view.superview {
291 | var constraint: NSLayoutConstraint!
292 |
293 | if (axis == .Horizontal) {
294 | constraint = NSLayoutConstraint(
295 | item: superview, attribute: .Trailing,
296 | relatedBy: .Equal,
297 | toItem: view, attribute: .Trailing,
298 | multiplier: 1.0, constant: constant)
299 | } else {
300 | constraint = NSLayoutConstraint(
301 | item: superview, attribute: .Bottom,
302 | relatedBy: .Equal,
303 | toItem: view, attribute: .Bottom,
304 | multiplier: 1.0, constant: constant)
305 | }
306 |
307 | return viewContainer.toConstraints(axis) + [constraint]
308 | }
309 | NSException(name: NSInvalidArgumentException, reason: "You tried to create a constraint to \(view)'s superview, but it has no superview yet!", userInfo: nil).raise()
310 | }
311 | NSException(name: NSInvalidArgumentException, reason: "This superview bar | was after something that doesn't have a view. Weird?", userInfo: nil).raise()
312 |
313 | return [] // To appease the compiler, which doesn't realize this branch dies
314 | }
315 | }
316 |
317 | let RequiredPriority: Float = 1000 // For some reason, the linker can't find UILayoutPriorityRequired. Not sure what I am doing wrong
318 |
319 | prefix operator | {}
320 | prefix public func | (tokenArray: [ViewContainingToken]) -> [LeadingSuperviewConstraintToken] {
321 | // |[view]
322 | return [LeadingSuperviewConstraintToken(viewContainer: tokenArray[0], space: 0)]
323 | }
324 |
325 | postfix operator | {}
326 | postfix public func | (tokenArray: [ViewContainingToken]) -> [TrailingSuperviewConstraintToken] {
327 | // [view]|
328 | return [TrailingSuperviewConstraintToken(viewContainer: tokenArray[0], space: 0)]
329 | }
330 |
331 | func >= (left: ALVFView, right: ConstantToken) -> SizeConstantConstraintToken {
332 | // [view >= 50]
333 | return SizeConstantConstraintToken(view: left, size: right, relation: .GreaterThanOrEqual)
334 | }
335 | func >= (left: ALVFView, right: ALVFView) -> SizeRelationConstraintToken {
336 | // [view >= view2]
337 | return SizeRelationConstraintToken(view: left, relatedView: right, relation: .GreaterThanOrEqual)
338 | }
339 |
340 | func <= (left: ALVFView, right: ConstantToken) -> SizeConstantConstraintToken {
341 | // [view <= 50]
342 | return SizeConstantConstraintToken(view: left, size: right, relation: .LessThanOrEqual)
343 | }
344 | func <= (left: ALVFView, right: ALVFView) -> SizeRelationConstraintToken {
345 | // [view <= view2]
346 | return SizeRelationConstraintToken(view: left, relatedView: right, relation: .LessThanOrEqual)
347 | }
348 |
349 | func == (left: ALVFView, right: ConstantToken) -> SizeConstantConstraintToken {
350 | // [view == 50]
351 | return SizeConstantConstraintToken(view: left, size: right, relation: .Equal)
352 | }
353 | func == (left: ALVFView, right: ALVFView) -> SizeRelationConstraintToken {
354 | // [view == view2]
355 | return SizeRelationConstraintToken(view: left, relatedView: right, relation: .Equal)
356 | }
357 |
358 | func - (left: [ViewContainingToken], right: ConstantToken) -> ViewAndSpaceToken {
359 | // [view]-5
360 | return ViewAndSpaceToken(view: left[0], space: right, relation: .Equal)
361 | }
362 |
363 | func - (left: ViewAndSpaceToken, right: [ViewContainingToken]) -> [SpacedViewsConstraintToken] {
364 | // [view]-5-[view2]
365 | return [SpacedViewsConstraintToken(leadingView: left.view, trailingView: right[0], space: left.space)]
366 | }
367 |
368 | func - (left: [ViewContainingToken], right: TrailingSuperviewAndSpaceToken) -> [TrailingSuperviewConstraintToken] {
369 | // [view]-5-|
370 | return [TrailingSuperviewConstraintToken(viewContainer: left[0], space: right.space)]
371 | }
372 |
373 | func - (left: LeadingSuperviewAndSpaceToken, right: [ViewContainingToken]) -> [LeadingSuperviewConstraintToken] {
374 | // |-5-[view]
375 | return [LeadingSuperviewConstraintToken(viewContainer: right[0], space: left.space)]
376 | }
377 |
378 | postfix operator -| {}
379 | postfix func -| (constant: ConstantToken) -> TrailingSuperviewAndSpaceToken {
380 | // 5-|
381 | return TrailingSuperviewAndSpaceToken(space: constant)
382 | }
383 |
384 | prefix operator |- {}
385 | prefix func |- (constant: ConstantToken) -> LeadingSuperviewAndSpaceToken {
386 | // |-5
387 | return LeadingSuperviewAndSpaceToken(space: constant, relation: .Equal)
388 | }
389 |
390 |
391 | extension ALVFView: ViewContainingToken {
392 | public var firstView: ALVFView? {
393 | get {
394 | return self
395 | }
396 | }
397 | public var lastView: ALVFView? {
398 | get {
399 | return self
400 | }
401 | }
402 |
403 | public func toConstraints(axis: UILayoutConstraintAxis) -> [NSLayoutConstraint] {
404 | return []
405 | }
406 | }
407 |
408 | extension CGFloat: ConstantToken {
409 | var ALConstant: CGFloat {
410 | get {
411 | return self
412 | }
413 | }
414 | }
415 |
416 | extension NSInteger: ConstantToken {
417 | var ALConstant: CGFloat {
418 | get {
419 | return CGFloat(self)
420 | }
421 | }
422 | }
423 |
424 |
--------------------------------------------------------------------------------
/SwiftVisualFormat.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | AE18C9BC198BCA5600591FA5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE18C9BB198BCA5600591FA5 /* AppDelegate.swift */; };
11 | AE18C9BE198BCA5600591FA5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE18C9BD198BCA5600591FA5 /* ViewController.swift */; };
12 | AE18C9C1198BCA5600591FA5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AE18C9BF198BCA5600591FA5 /* Main.storyboard */; };
13 | AE18C9C3198BCA5600591FA5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE18C9C2198BCA5600591FA5 /* Images.xcassets */; };
14 | AE18C9CF198BCA5600591FA5 /* SwiftVisualFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE18C9CE198BCA5600591FA5 /* SwiftVisualFormatTests.swift */; };
15 | AE18C9D9198BCA6300591FA5 /* VisualFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE18C9D8198BCA6300591FA5 /* VisualFormat.swift */; };
16 | AE18C9DD198BF20B00591FA5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE18C9DC198BF20B00591FA5 /* UIKit.framework */; };
17 | AE18C9DF198BF22600591FA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE18C9DE198BF22600591FA5 /* Foundation.framework */; };
18 | AE9486CC199DE327004DEAB2 /* VisualFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE18C9D8198BCA6300591FA5 /* VisualFormat.swift */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXContainerItemProxy section */
22 | AE18C9C9198BCA5600591FA5 /* PBXContainerItemProxy */ = {
23 | isa = PBXContainerItemProxy;
24 | containerPortal = AE18C9AE198BCA5600591FA5 /* Project object */;
25 | proxyType = 1;
26 | remoteGlobalIDString = AE18C9B5198BCA5600591FA5;
27 | remoteInfo = SwiftVisualFormat;
28 | };
29 | /* End PBXContainerItemProxy section */
30 |
31 | /* Begin PBXFileReference section */
32 | AE18C9B6198BCA5600591FA5 /* SwiftVisualFormat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftVisualFormat.app; sourceTree = BUILT_PRODUCTS_DIR; };
33 | AE18C9BA198BCA5600591FA5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | AE18C9BB198BCA5600591FA5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
35 | AE18C9BD198BCA5600591FA5 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
36 | AE18C9C0198BCA5600591FA5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
37 | AE18C9C2198BCA5600591FA5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
38 | AE18C9C8198BCA5600591FA5 /* SwiftVisualFormatTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftVisualFormatTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
39 | AE18C9CD198BCA5600591FA5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
40 | AE18C9CE198BCA5600591FA5 /* SwiftVisualFormatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftVisualFormatTests.swift; sourceTree = ""; };
41 | AE18C9D8198BCA6300591FA5 /* VisualFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VisualFormat.swift; path = ../VisualFormat.swift; sourceTree = ""; };
42 | AE18C9DC198BF20B00591FA5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
43 | AE18C9DE198BF22600591FA5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
44 | /* End PBXFileReference section */
45 |
46 | /* Begin PBXFrameworksBuildPhase section */
47 | AE18C9B3198BCA5600591FA5 /* Frameworks */ = {
48 | isa = PBXFrameworksBuildPhase;
49 | buildActionMask = 2147483647;
50 | files = (
51 | AE18C9DF198BF22600591FA5 /* Foundation.framework in Frameworks */,
52 | AE18C9DD198BF20B00591FA5 /* UIKit.framework in Frameworks */,
53 | );
54 | runOnlyForDeploymentPostprocessing = 0;
55 | };
56 | AE18C9C5198BCA5600591FA5 /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | /* End PBXFrameworksBuildPhase section */
64 |
65 | /* Begin PBXGroup section */
66 | AE18C9AD198BCA5600591FA5 = {
67 | isa = PBXGroup;
68 | children = (
69 | AE18C9DE198BF22600591FA5 /* Foundation.framework */,
70 | AE18C9DC198BF20B00591FA5 /* UIKit.framework */,
71 | AE18C9B8198BCA5600591FA5 /* SwiftVisualFormat */,
72 | AE18C9CB198BCA5600591FA5 /* SwiftVisualFormatTests */,
73 | AE18C9B7198BCA5600591FA5 /* Products */,
74 | );
75 | sourceTree = "";
76 | };
77 | AE18C9B7198BCA5600591FA5 /* Products */ = {
78 | isa = PBXGroup;
79 | children = (
80 | AE18C9B6198BCA5600591FA5 /* SwiftVisualFormat.app */,
81 | AE18C9C8198BCA5600591FA5 /* SwiftVisualFormatTests.xctest */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | AE18C9B8198BCA5600591FA5 /* SwiftVisualFormat */ = {
87 | isa = PBXGroup;
88 | children = (
89 | AE18C9BB198BCA5600591FA5 /* AppDelegate.swift */,
90 | AE18C9BD198BCA5600591FA5 /* ViewController.swift */,
91 | AE18C9D8198BCA6300591FA5 /* VisualFormat.swift */,
92 | AE18C9BF198BCA5600591FA5 /* Main.storyboard */,
93 | AE18C9C2198BCA5600591FA5 /* Images.xcassets */,
94 | AE18C9B9198BCA5600591FA5 /* Supporting Files */,
95 | );
96 | path = SwiftVisualFormat;
97 | sourceTree = "";
98 | };
99 | AE18C9B9198BCA5600591FA5 /* Supporting Files */ = {
100 | isa = PBXGroup;
101 | children = (
102 | AE18C9BA198BCA5600591FA5 /* Info.plist */,
103 | );
104 | name = "Supporting Files";
105 | sourceTree = "";
106 | };
107 | AE18C9CB198BCA5600591FA5 /* SwiftVisualFormatTests */ = {
108 | isa = PBXGroup;
109 | children = (
110 | AE18C9CE198BCA5600591FA5 /* SwiftVisualFormatTests.swift */,
111 | AE18C9CC198BCA5600591FA5 /* Supporting Files */,
112 | );
113 | path = SwiftVisualFormatTests;
114 | sourceTree = "";
115 | };
116 | AE18C9CC198BCA5600591FA5 /* Supporting Files */ = {
117 | isa = PBXGroup;
118 | children = (
119 | AE18C9CD198BCA5600591FA5 /* Info.plist */,
120 | );
121 | name = "Supporting Files";
122 | sourceTree = "";
123 | };
124 | /* End PBXGroup section */
125 |
126 | /* Begin PBXNativeTarget section */
127 | AE18C9B5198BCA5600591FA5 /* SwiftVisualFormat */ = {
128 | isa = PBXNativeTarget;
129 | buildConfigurationList = AE18C9D2198BCA5600591FA5 /* Build configuration list for PBXNativeTarget "SwiftVisualFormat" */;
130 | buildPhases = (
131 | AE18C9B2198BCA5600591FA5 /* Sources */,
132 | AE18C9B3198BCA5600591FA5 /* Frameworks */,
133 | AE18C9B4198BCA5600591FA5 /* Resources */,
134 | );
135 | buildRules = (
136 | );
137 | dependencies = (
138 | );
139 | name = SwiftVisualFormat;
140 | productName = SwiftVisualFormat;
141 | productReference = AE18C9B6198BCA5600591FA5 /* SwiftVisualFormat.app */;
142 | productType = "com.apple.product-type.application";
143 | };
144 | AE18C9C7198BCA5600591FA5 /* SwiftVisualFormatTests */ = {
145 | isa = PBXNativeTarget;
146 | buildConfigurationList = AE18C9D5198BCA5600591FA5 /* Build configuration list for PBXNativeTarget "SwiftVisualFormatTests" */;
147 | buildPhases = (
148 | AE18C9C4198BCA5600591FA5 /* Sources */,
149 | AE18C9C5198BCA5600591FA5 /* Frameworks */,
150 | AE18C9C6198BCA5600591FA5 /* Resources */,
151 | );
152 | buildRules = (
153 | );
154 | dependencies = (
155 | AE18C9CA198BCA5600591FA5 /* PBXTargetDependency */,
156 | );
157 | name = SwiftVisualFormatTests;
158 | productName = SwiftVisualFormatTests;
159 | productReference = AE18C9C8198BCA5600591FA5 /* SwiftVisualFormatTests.xctest */;
160 | productType = "com.apple.product-type.bundle.unit-test";
161 | };
162 | /* End PBXNativeTarget section */
163 |
164 | /* Begin PBXProject section */
165 | AE18C9AE198BCA5600591FA5 /* Project object */ = {
166 | isa = PBXProject;
167 | attributes = {
168 | LastSwiftUpdateCheck = 0700;
169 | LastUpgradeCheck = 0600;
170 | ORGANIZATIONNAME = "Bridger Maxwell";
171 | TargetAttributes = {
172 | AE18C9B5198BCA5600591FA5 = {
173 | CreatedOnToolsVersion = 6.0;
174 | };
175 | AE18C9C7198BCA5600591FA5 = {
176 | CreatedOnToolsVersion = 6.0;
177 | TestTargetID = AE18C9B5198BCA5600591FA5;
178 | };
179 | };
180 | };
181 | buildConfigurationList = AE18C9B1198BCA5600591FA5 /* Build configuration list for PBXProject "SwiftVisualFormat" */;
182 | compatibilityVersion = "Xcode 3.2";
183 | developmentRegion = English;
184 | hasScannedForEncodings = 0;
185 | knownRegions = (
186 | en,
187 | Base,
188 | );
189 | mainGroup = AE18C9AD198BCA5600591FA5;
190 | productRefGroup = AE18C9B7198BCA5600591FA5 /* Products */;
191 | projectDirPath = "";
192 | projectRoot = "";
193 | targets = (
194 | AE18C9B5198BCA5600591FA5 /* SwiftVisualFormat */,
195 | AE18C9C7198BCA5600591FA5 /* SwiftVisualFormatTests */,
196 | );
197 | };
198 | /* End PBXProject section */
199 |
200 | /* Begin PBXResourcesBuildPhase section */
201 | AE18C9B4198BCA5600591FA5 /* Resources */ = {
202 | isa = PBXResourcesBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | AE18C9C1198BCA5600591FA5 /* Main.storyboard in Resources */,
206 | AE18C9C3198BCA5600591FA5 /* Images.xcassets in Resources */,
207 | );
208 | runOnlyForDeploymentPostprocessing = 0;
209 | };
210 | AE18C9C6198BCA5600591FA5 /* Resources */ = {
211 | isa = PBXResourcesBuildPhase;
212 | buildActionMask = 2147483647;
213 | files = (
214 | );
215 | runOnlyForDeploymentPostprocessing = 0;
216 | };
217 | /* End PBXResourcesBuildPhase section */
218 |
219 | /* Begin PBXSourcesBuildPhase section */
220 | AE18C9B2198BCA5600591FA5 /* Sources */ = {
221 | isa = PBXSourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | AE18C9BE198BCA5600591FA5 /* ViewController.swift in Sources */,
225 | AE18C9D9198BCA6300591FA5 /* VisualFormat.swift in Sources */,
226 | AE18C9BC198BCA5600591FA5 /* AppDelegate.swift in Sources */,
227 | );
228 | runOnlyForDeploymentPostprocessing = 0;
229 | };
230 | AE18C9C4198BCA5600591FA5 /* Sources */ = {
231 | isa = PBXSourcesBuildPhase;
232 | buildActionMask = 2147483647;
233 | files = (
234 | AE9486CC199DE327004DEAB2 /* VisualFormat.swift in Sources */,
235 | AE18C9CF198BCA5600591FA5 /* SwiftVisualFormatTests.swift in Sources */,
236 | );
237 | runOnlyForDeploymentPostprocessing = 0;
238 | };
239 | /* End PBXSourcesBuildPhase section */
240 |
241 | /* Begin PBXTargetDependency section */
242 | AE18C9CA198BCA5600591FA5 /* PBXTargetDependency */ = {
243 | isa = PBXTargetDependency;
244 | target = AE18C9B5198BCA5600591FA5 /* SwiftVisualFormat */;
245 | targetProxy = AE18C9C9198BCA5600591FA5 /* PBXContainerItemProxy */;
246 | };
247 | /* End PBXTargetDependency section */
248 |
249 | /* Begin PBXVariantGroup section */
250 | AE18C9BF198BCA5600591FA5 /* Main.storyboard */ = {
251 | isa = PBXVariantGroup;
252 | children = (
253 | AE18C9C0198BCA5600591FA5 /* Base */,
254 | );
255 | name = Main.storyboard;
256 | sourceTree = "";
257 | };
258 | /* End PBXVariantGroup section */
259 |
260 | /* Begin XCBuildConfiguration section */
261 | AE18C9D0198BCA5600591FA5 /* Debug */ = {
262 | isa = XCBuildConfiguration;
263 | buildSettings = {
264 | ALWAYS_SEARCH_USER_PATHS = NO;
265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
266 | CLANG_CXX_LIBRARY = "libc++";
267 | CLANG_ENABLE_MODULES = YES;
268 | CLANG_ENABLE_OBJC_ARC = YES;
269 | CLANG_WARN_BOOL_CONVERSION = YES;
270 | CLANG_WARN_CONSTANT_CONVERSION = YES;
271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
272 | CLANG_WARN_EMPTY_BODY = YES;
273 | CLANG_WARN_ENUM_CONVERSION = YES;
274 | CLANG_WARN_INT_CONVERSION = YES;
275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
276 | CLANG_WARN_UNREACHABLE_CODE = YES;
277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
278 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
279 | COPY_PHASE_STRIP = NO;
280 | ENABLE_STRICT_OBJC_MSGSEND = YES;
281 | GCC_C_LANGUAGE_STANDARD = gnu99;
282 | GCC_DYNAMIC_NO_PIC = NO;
283 | GCC_OPTIMIZATION_LEVEL = 0;
284 | GCC_PREPROCESSOR_DEFINITIONS = (
285 | "DEBUG=1",
286 | "$(inherited)",
287 | );
288 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
291 | GCC_WARN_UNDECLARED_SELECTOR = YES;
292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
293 | GCC_WARN_UNUSED_FUNCTION = YES;
294 | GCC_WARN_UNUSED_VARIABLE = YES;
295 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
296 | MTL_ENABLE_DEBUG_INFO = YES;
297 | ONLY_ACTIVE_ARCH = YES;
298 | SDKROOT = iphoneos;
299 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
300 | TARGETED_DEVICE_FAMILY = "1,2";
301 | };
302 | name = Debug;
303 | };
304 | AE18C9D1198BCA5600591FA5 /* Release */ = {
305 | isa = XCBuildConfiguration;
306 | buildSettings = {
307 | ALWAYS_SEARCH_USER_PATHS = NO;
308 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
309 | CLANG_CXX_LIBRARY = "libc++";
310 | CLANG_ENABLE_MODULES = YES;
311 | CLANG_ENABLE_OBJC_ARC = YES;
312 | CLANG_WARN_BOOL_CONVERSION = YES;
313 | CLANG_WARN_CONSTANT_CONVERSION = YES;
314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
315 | CLANG_WARN_EMPTY_BODY = YES;
316 | CLANG_WARN_ENUM_CONVERSION = YES;
317 | CLANG_WARN_INT_CONVERSION = YES;
318 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
319 | CLANG_WARN_UNREACHABLE_CODE = YES;
320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
321 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
322 | COPY_PHASE_STRIP = YES;
323 | ENABLE_NS_ASSERTIONS = NO;
324 | ENABLE_STRICT_OBJC_MSGSEND = YES;
325 | GCC_C_LANGUAGE_STANDARD = gnu99;
326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
328 | GCC_WARN_UNDECLARED_SELECTOR = YES;
329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
330 | GCC_WARN_UNUSED_FUNCTION = YES;
331 | GCC_WARN_UNUSED_VARIABLE = YES;
332 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
333 | MTL_ENABLE_DEBUG_INFO = NO;
334 | SDKROOT = iphoneos;
335 | TARGETED_DEVICE_FAMILY = "1,2";
336 | VALIDATE_PRODUCT = YES;
337 | };
338 | name = Release;
339 | };
340 | AE18C9D3198BCA5600591FA5 /* Debug */ = {
341 | isa = XCBuildConfiguration;
342 | buildSettings = {
343 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
344 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
345 | INFOPLIST_FILE = SwiftVisualFormat/Info.plist;
346 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
347 | PRODUCT_NAME = "$(TARGET_NAME)";
348 | };
349 | name = Debug;
350 | };
351 | AE18C9D4198BCA5600591FA5 /* Release */ = {
352 | isa = XCBuildConfiguration;
353 | buildSettings = {
354 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
355 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
356 | INFOPLIST_FILE = SwiftVisualFormat/Info.plist;
357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
358 | PRODUCT_NAME = "$(TARGET_NAME)";
359 | };
360 | name = Release;
361 | };
362 | AE18C9D6198BCA5600591FA5 /* Debug */ = {
363 | isa = XCBuildConfiguration;
364 | buildSettings = {
365 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SwiftVisualFormat.app/SwiftVisualFormat";
366 | FRAMEWORK_SEARCH_PATHS = (
367 | "$(SDKROOT)/Developer/Library/Frameworks",
368 | "$(inherited)",
369 | );
370 | GCC_PREPROCESSOR_DEFINITIONS = (
371 | "DEBUG=1",
372 | "$(inherited)",
373 | );
374 | INFOPLIST_FILE = SwiftVisualFormatTests/Info.plist;
375 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
376 | PRODUCT_NAME = "$(TARGET_NAME)";
377 | TEST_HOST = "$(BUNDLE_LOADER)";
378 | };
379 | name = Debug;
380 | };
381 | AE18C9D7198BCA5600591FA5 /* Release */ = {
382 | isa = XCBuildConfiguration;
383 | buildSettings = {
384 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SwiftVisualFormat.app/SwiftVisualFormat";
385 | FRAMEWORK_SEARCH_PATHS = (
386 | "$(SDKROOT)/Developer/Library/Frameworks",
387 | "$(inherited)",
388 | );
389 | INFOPLIST_FILE = SwiftVisualFormatTests/Info.plist;
390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
391 | PRODUCT_NAME = "$(TARGET_NAME)";
392 | TEST_HOST = "$(BUNDLE_LOADER)";
393 | };
394 | name = Release;
395 | };
396 | /* End XCBuildConfiguration section */
397 |
398 | /* Begin XCConfigurationList section */
399 | AE18C9B1198BCA5600591FA5 /* Build configuration list for PBXProject "SwiftVisualFormat" */ = {
400 | isa = XCConfigurationList;
401 | buildConfigurations = (
402 | AE18C9D0198BCA5600591FA5 /* Debug */,
403 | AE18C9D1198BCA5600591FA5 /* Release */,
404 | );
405 | defaultConfigurationIsVisible = 0;
406 | defaultConfigurationName = Release;
407 | };
408 | AE18C9D2198BCA5600591FA5 /* Build configuration list for PBXNativeTarget "SwiftVisualFormat" */ = {
409 | isa = XCConfigurationList;
410 | buildConfigurations = (
411 | AE18C9D3198BCA5600591FA5 /* Debug */,
412 | AE18C9D4198BCA5600591FA5 /* Release */,
413 | );
414 | defaultConfigurationIsVisible = 0;
415 | defaultConfigurationName = Release;
416 | };
417 | AE18C9D5198BCA5600591FA5 /* Build configuration list for PBXNativeTarget "SwiftVisualFormatTests" */ = {
418 | isa = XCConfigurationList;
419 | buildConfigurations = (
420 | AE18C9D6198BCA5600591FA5 /* Debug */,
421 | AE18C9D7198BCA5600591FA5 /* Release */,
422 | );
423 | defaultConfigurationIsVisible = 0;
424 | defaultConfigurationName = Release;
425 | };
426 | /* End XCConfigurationList section */
427 | };
428 | rootObject = AE18C9AE198BCA5600591FA5 /* Project object */;
429 | }
430 |
--------------------------------------------------------------------------------