From 7b74047efb2952aa1af457278be551e134f882d3 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Fri, 25 May 2018 20:35:09 -0400 Subject: [PATCH 001/389] Add Objective-C support for macOS Plus: * Removed not needed @discardableResult --- PinLayout.xcodeproj/project.pbxproj | 8 + Podfile.lock | 4 +- Sources/Impl/PinLayoutImpl+Layouting.swift | 1 - Sources/Impl/PinLayoutImpl+Relative.swift | 65 +-- Sources/Impl/PinLayoutImpl+Warning.swift | 1 - Sources/Impl/PinLayoutImpl.swift | 268 +++------- Sources/Impl/PinSafeArea.swift | 1 - Sources/Impl/TypesImpl.swift | 1 - Sources/NSView+PinLayout.swift | 6 + Sources/ObjectiveC/PinLayoutObjC.swift | 130 +++-- Sources/ObjectiveC/PinLayoutObjCImpl.swift | 540 ++++++++++----------- Sources/UIView+PinLayout.swift | 5 + 12 files changed, 467 insertions(+), 563 deletions(-) diff --git a/PinLayout.xcodeproj/project.pbxproj b/PinLayout.xcodeproj/project.pbxproj index d82f6417..4dcefc0d 100644 --- a/PinLayout.xcodeproj/project.pbxproj +++ b/PinLayout.xcodeproj/project.pbxproj @@ -102,6 +102,10 @@ DFED1552208533DA009EF9A7 /* AspectRatioTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */; }; DFED15532085349A009EF9A7 /* RectNimbleMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C5031E75DB7600073BEE /* RectNimbleMatcher.swift */; }; DFED15542085349B009EF9A7 /* RectNimbleMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C5031E75DB7600073BEE /* RectNimbleMatcher.swift */; }; + DFF222B120B877F400AC2A84 /* PinLayoutObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277B1F8E958F00B1AD39 /* PinLayoutObjC.swift */; }; + DFF222B220B877F600AC2A84 /* PinLayoutObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277B1F8E958F00B1AD39 /* PinLayoutObjC.swift */; }; + DFF222B320B877F800AC2A84 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; + DFF222B420B877F900AC2A84 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; DFF6F9C72084DCD3004F5AED /* PinLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244DF2F81EF46C500090508B /* PinLayout.framework */; }; DFF6F9CD2084E15A004F5AED /* BasicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C5011E75D88500073BEE /* BasicView.swift */; }; DFF6F9CE2084E15A004F5AED /* AdjustSizeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C4FF1E75D74000073BEE /* AdjustSizeSpec.swift */; }; @@ -787,6 +791,8 @@ buildActionMask = 2147483647; files = ( 243C62081FC37F6C0082C327 /* PinLayoutImpl+Warning.swift in Sources */, + DFF222B420B877F900AC2A84 /* PinLayoutObjCImpl.swift in Sources */, + DFF222B220B877F600AC2A84 /* PinLayoutObjC.swift in Sources */, 24D18D261F3E5EA5008129EF /* Pin.swift in Sources */, DF1A5D362084CFC100725EF5 /* NSView+PinLayout.swift in Sources */, 243C62041FC37F680082C327 /* PinLayoutImpl.swift in Sources */, @@ -885,6 +891,8 @@ buildActionMask = 2147483647; files = ( DF1A5D3F2084CFD600725EF5 /* PinLayoutImpl+Warning.swift in Sources */, + DFF222B320B877F800AC2A84 /* PinLayoutObjCImpl.swift in Sources */, + DFF222B120B877F400AC2A84 /* PinLayoutObjC.swift in Sources */, DF1A5D3B2084CFD600725EF5 /* PinLayoutImpl.swift in Sources */, DF1A5D412084CFD600725EF5 /* Coordinates.swift in Sources */, DF1A5D422084CFD600725EF5 /* Percent.swift in Sources */, diff --git a/Podfile.lock b/Podfile.lock index 108e8cc1..d8eb96e6 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,6 @@ PODS: - Nimble (7.0.3) - - PinLayout (1.7.0) + - PinLayout (1.7.3) - Quick (1.2.0) - Reveal-SDK (10) - SwiftLint (0.25.1) @@ -25,7 +25,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Nimble: 7f5a9c447a33002645a071bddafbfb24ea70e0ac - PinLayout: 816805698a6c478d5f0cf97dd298243c098d6e50 + PinLayout: 04488e8fc8d19b59760bdf99a16deff7bfac422d Quick: 58d203b1c5e27fff7229c4c1ae445ad7069a7a08 Reveal-SDK: 7869ddf1f902cabbb07a1f0dd06bd25861a126f7 SwiftLint: ce933681be10c3266e82576dad676fa815a602e9 diff --git a/Sources/Impl/PinLayoutImpl+Layouting.swift b/Sources/Impl/PinLayoutImpl+Layouting.swift index 1204a848..405bae96 100644 --- a/Sources/Impl/PinLayoutImpl+Layouting.swift +++ b/Sources/Impl/PinLayoutImpl+Layouting.swift @@ -443,4 +443,3 @@ extension PinLayoutImpl { return view.isLTR() } } - diff --git a/Sources/Impl/PinLayoutImpl+Relative.swift b/Sources/Impl/PinLayoutImpl+Relative.swift index 4005b304..f30d9852 100644 --- a/Sources/Impl/PinLayoutImpl+Relative.swift +++ b/Sources/Impl/PinLayoutImpl+Relative.swift @@ -28,25 +28,21 @@ extension PinLayoutImpl { // // above(of ...) // - @discardableResult func above(of relativeView: PView) -> PinLayout { func context() -> String { return "above(of: \(relativeView))" } return above(relativeViews: [relativeView], aligned: nil, context: context) } - - @discardableResult + func above(of relativeViews: [PView]) -> PinLayout { func context() -> String { return "above(of: \(relativeViews))" } return above(relativeViews: relativeViews, aligned: nil, context: context) } - - @discardableResult + func above(of relativeView: PView, aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "above(of: \(relativeView), aligned: \(aligned))" } return above(relativeViews: [relativeView], aligned: aligned, context: context) } - - @discardableResult + func above(of relativeViews: [PView], aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "above(of: \(relativeViews), aligned: \(aligned))" } return above(relativeViews: relativeViews, aligned: aligned, context: context) @@ -55,25 +51,21 @@ extension PinLayoutImpl { // // below(of ...) // - @discardableResult func below(of relativeView: PView) -> PinLayout { func context() -> String { return "below(of: \(relativeView))" } return below(relativeViews: [relativeView], aligned: nil, context: context) } - - @discardableResult + func below(of relativeViews: [PView]) -> PinLayout { func context() -> String { return "below(of: \(relativeViews))" } return below(relativeViews: relativeViews, aligned: nil, context: context) } - - @discardableResult + func below(of relativeView: PView, aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "below(of: \(relativeView), aligned: \(aligned))" } return below(relativeViews: [relativeView], aligned: aligned, context: context) } - - @discardableResult + func below(of relativeViews: [PView], aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "below(of: \(relativeViews), aligned: \(aligned))" } return below(relativeViews: relativeViews, aligned: aligned, context: context) @@ -82,25 +74,21 @@ extension PinLayoutImpl { // // left(of ...) // - @discardableResult func left(of relativeView: PView) -> PinLayout { func context() -> String { return "left(of: \(relativeView))" } return left(relativeViews: [relativeView], aligned: nil, context: context) } - - @discardableResult + func left(of relativeViews: [PView]) -> PinLayout { func context() -> String { return "left(of: \(relativeViews))" } return left(relativeViews: relativeViews, aligned: nil, context: context) } - - @discardableResult + func left(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "left(of: \(relativeView), aligned: \(aligned))" } return left(relativeViews: [relativeView], aligned: aligned, context: context) } - - @discardableResult + func left(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "left(of: \(relativeViews), aligned: \(aligned))" } return left(relativeViews: relativeViews, aligned: aligned, context: context) @@ -109,31 +97,26 @@ extension PinLayoutImpl { // // right(of ...) // - @discardableResult func right(of relativeView: PView) -> PinLayout { func context() -> String { return "right(of: \(relativeView))" } return right(relativeViews: [relativeView], aligned: nil, context: context) } - - @discardableResult + func right(of relativeViews: [PView]) -> PinLayout { func context() -> String { return "right(of: \(relativeViews))" } return right(relativeViews: relativeViews, aligned: nil, context: context) } - @discardableResult func right(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "right(of: \(relativeView), aligned: \(aligned))" } return right(relativeViews: [relativeView], aligned: aligned, context: context) } - - @discardableResult + func right(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "right(of: \(relativeViews), aligned: \(aligned))" } return right(relativeViews: relativeViews, aligned: aligned, context: context) } - - @discardableResult + func before(of relativeView: PView) -> PinLayout { func context() -> String { return "before(of: \(relativeView))" } if isLTR() { @@ -142,8 +125,7 @@ extension PinLayoutImpl { return right(relativeViews: [relativeView], aligned: nil, context: context) } } - - @discardableResult + func before(of relativeViews: [PView]) -> PinLayout { func context() -> String { return "before(of: \(relativeViews))" } if isLTR() { @@ -152,8 +134,7 @@ extension PinLayoutImpl { return right(relativeViews: relativeViews, aligned: nil, context: context) } } - - @discardableResult + func before(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "before(of: \(relativeView), aligned: \(aligned))" } if isLTR() { @@ -162,8 +143,7 @@ extension PinLayoutImpl { return right(relativeViews: [relativeView], aligned: aligned, context: context) } } - - @discardableResult + func before(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "before(of: \(relativeViews), aligned: \(aligned))" } if isLTR() { @@ -172,8 +152,7 @@ extension PinLayoutImpl { return right(relativeViews: relativeViews, aligned: aligned, context: context) } } - - @discardableResult + func after(of relativeView: PView) -> PinLayout { func context() -> String { return "after(of: \(relativeView))" } if isLTR() { @@ -182,8 +161,7 @@ extension PinLayoutImpl { return left(relativeViews: [relativeView], aligned: nil, context: context) } } - - @discardableResult + func after(of relativeViews: [PView]) -> PinLayout { func context() -> String { return "after(of: \(relativeViews))" } if isLTR() { @@ -192,8 +170,7 @@ extension PinLayoutImpl { return left(relativeViews: relativeViews, aligned: nil, context: context) } } - - @discardableResult + func after(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "after(of: \(relativeView))" } if isLTR() { @@ -202,8 +179,7 @@ extension PinLayoutImpl { return left(relativeViews: [relativeView], aligned: aligned, context: context) } } - - @discardableResult + func after(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "after(of: \(relativeViews), aligned: \(aligned))" } if isLTR() { @@ -216,7 +192,6 @@ extension PinLayoutImpl { // MARK: fileprivate extension PinLayoutImpl { - @discardableResult fileprivate func above(relativeViews: [PView], aligned: HorizontalAlign?, context: Context) -> PinLayout { guard let relativeViews = validateRelativeViews(relativeViews, context: context) else { return self } @@ -240,7 +215,6 @@ extension PinLayoutImpl { return self } - @discardableResult fileprivate func below(relativeViews: [PView], aligned: HorizontalAlign?, context: Context) -> PinLayout { guard let relativeViews = validateRelativeViews(relativeViews, context: context) else { return self } @@ -391,4 +365,3 @@ extension PinLayoutImpl { return relativeViews } } - diff --git a/Sources/Impl/PinLayoutImpl+Warning.swift b/Sources/Impl/PinLayoutImpl+Warning.swift index e7958bd1..5d30c396 100644 --- a/Sources/Impl/PinLayoutImpl+Warning.swift +++ b/Sources/Impl/PinLayoutImpl+Warning.swift @@ -157,4 +157,3 @@ extension PinLayoutImpl { return "UIEdgeInsets(top: \(insets.top), left: \(insets.left), bottom: \(insets.bottom), right: \(insets.right))" } } - diff --git a/Sources/Impl/PinLayoutImpl.swift b/Sources/Impl/PinLayoutImpl.swift index 5b16dca1..ae01e5e9 100644 --- a/Sources/Impl/PinLayoutImpl.swift +++ b/Sources/Impl/PinLayoutImpl.swift @@ -101,17 +101,15 @@ class PinLayoutImpl: PinLayout { // // top, left, bottom, right // - @discardableResult func top() -> PinLayout { + func top() -> PinLayout { top({ return "top()" }) return self } - @discardableResult func top(_ value: CGFloat) -> PinLayout { return top(value, { return "top(\(value))" }) } - - @discardableResult + func top(_ percent: Percent) -> PinLayout { func context() -> String { return "top(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } @@ -119,133 +117,112 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func top(_ insets: PEdgeInsets) -> PinLayout { return top(insets.top, { return "top(\(insetsDescription(insets))" }) } - - @discardableResult + func left() -> PinLayout { return left({ return "left()" }) } - @discardableResult func left(_ value: CGFloat) -> PinLayout { return left(value, { return "left(\(value))" }) } - - @discardableResult + func left(_ percent: Percent) -> PinLayout { return left(percent, { return "left(\(percent.description))" }) } - @discardableResult func left(_ insets: PEdgeInsets) -> PinLayout { return left(insets.left, { return "left(\(insetsDescription(insets))" }) } - - @discardableResult + func start() -> PinLayout { func context() -> String { return "start()" } return isLTR() ? left(context) : right(context) } - - @discardableResult + func start(_ value: CGFloat) -> PinLayout { func context() -> String { return "start(\(value))" } return isLTR() ? left(value, context) : right(value, context) } - - @discardableResult + func start(_ percent: Percent) -> PinLayout { func context() -> String { return "start(\(percent.description))" } return isLTR() ? left(percent, context) : right(percent, context) } - @discardableResult func start(_ insets: PEdgeInsets) -> PinLayout { func context() -> String { return "start(\(insetsDescription(insets))" } return isLTR() ? left(insets.left, context) : right(insets.right, context) } - @discardableResult func bottom() -> PinLayout { + func bottom() -> PinLayout { return bottom({ return "bottom()" }) } - @discardableResult func bottom(_ value: CGFloat) -> PinLayout { return bottom(value, { return "bottom(\(value))" }) } - - @discardableResult + func bottom(_ percent: Percent) -> PinLayout { return bottom(percent, { return "bottom(\(percent.description))" }) } - @discardableResult func bottom(_ insets: PEdgeInsets) -> PinLayout { return bottom(insets.bottom, { return "bottom(\(insetsDescription(insets))" }) } - @discardableResult func right() -> PinLayout { + func right() -> PinLayout { return right({ return "right()" }) } - @discardableResult func right(_ value: CGFloat) -> PinLayout { return right(value, { return "right(\(value))" }) } - - @discardableResult + func right(_ percent: Percent) -> PinLayout { return right(percent, { return "right(\(percent.description))" }) } - @discardableResult func right(_ insets: PEdgeInsets) -> PinLayout { return right(insets.right, { return "right(\(insetsDescription(insets))" }) } - @discardableResult func end() -> PinLayout { + func end() -> PinLayout { func context() -> String { return "end()" } return isLTR() ? right(context) : left(context) } - - @discardableResult + func end(_ value: CGFloat) -> PinLayout { func context() -> String { return "end(\(value))" } return isLTR() ? right(value, context) : left(value, context) } - - @discardableResult + func end(_ percent: Percent) -> PinLayout { func context() -> String { return "end(\(percent.description))" } return isLTR() ? right(percent, context) : left(percent, context) } - @discardableResult func end(_ insets: PEdgeInsets) -> PinLayout { func context() -> String { return "end(\(insetsDescription(insets))" } return isLTR() ? right(insets.right, context) : left(insets.left, context) } - @discardableResult func hCenter() -> PinLayout { func context() -> String { return "hCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setHorizontalCenter(layoutSuperviewRect.width / 2, context) return self } - - @discardableResult + func hCenter(_ value: CGFloat) -> PinLayout { func context() -> String { return "hCenter(\(value))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setHorizontalCenter((layoutSuperviewRect.width / 2) + value, context) return self } - - @discardableResult + func hCenter(_ percent: Percent) -> PinLayout { func context() -> String { return "hCenter(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } @@ -253,31 +230,27 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func vCenter() -> PinLayout { func context() -> String { return "vCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setVerticalCenter(layoutSuperviewRect.height / 2, context) return self } - - @discardableResult + func vCenter(_ value: CGFloat) -> PinLayout { func context() -> String { return "vCenter(\(value))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setVerticalCenter((layoutSuperviewRect.height / 2) + value, context) return self } - - @discardableResult + func vCenter(_ percent: Percent) -> PinLayout { func context() -> String { return "vCenter(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setVerticalCenter((layoutSuperviewRect.height / 2) + percent.of(layoutSuperviewRect.height), context) return self } - - @discardableResult + func all() -> PinLayout { top({ "all() top coordinate" }) bottom({ "all() bottom coordinate" }) @@ -286,7 +259,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func all(_ value: CGFloat) -> PinLayout { top(value, { "all(\(value)) top coordinate" }) bottom(value, { "all(\(value)) bottom coordinate" }) @@ -302,57 +274,49 @@ class PinLayoutImpl: PinLayout { right(insets.right, { "all(\(insets)) right coordinate" }) return self } - - @discardableResult + func horizontally() -> PinLayout { right({ "horizontally() right coordinate" }) left({ "horizontally() left coordinate" }) return self } - @discardableResult func horizontally(_ value: CGFloat) -> PinLayout { left(value, { return "horizontally(\(value)) left coordinate" }) right(value, { return "horizontally(\(value)) right coordinate" }) return self } - @discardableResult func horizontally(_ percent: Percent) -> PinLayout { left(percent, { return "horizontally(\(percent.description)) left coordinate" }) right(percent, { return "horizontally(\(percent.description)) right coordinate" }) return self } - @discardableResult func horizontally(_ insets: PEdgeInsets) -> PinLayout { left(insets.left, { return "horizontally(\(insets)) left coordinate" }) right(insets.right, { return "horizontally(\(insets)) right coordinate" }) return self } - @discardableResult func vertically() -> PinLayout { top({ "vertically() top coordinate" }) bottom({ "vertically() bottom coordinate" }) return self } - @discardableResult func vertically(_ value: CGFloat) -> PinLayout { top(value, { return "vertically(\(value)) top coordinate" }) bottom(value, { return "vertically(\(value)) bottom coordinate" }) return self } - @discardableResult func vertically(_ percent: Percent) -> PinLayout { top(percent, { return "vertically(\(percent.description)) top coordinate" }) bottom(percent, { return "vertically(\(percent.description)) bottom coordinate" }) return self } - @discardableResult func vertically(_ insets: PEdgeInsets) -> PinLayout { top(insets.top, { return "vertically(\(insets)) top coordinate" }) bottom(insets.bottom, { return "vertically(\(insets)) bottom coordinate" }) @@ -362,7 +326,6 @@ class PinLayoutImpl: PinLayout { // // top, left, bottom, right // - @discardableResult func top(to edge: VerticalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "top", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -370,8 +333,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func vCenter(to edge: VerticalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "vCenter", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -380,7 +342,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func bottom(to edge: VerticalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "bottom", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -388,8 +349,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func left(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "left", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -397,8 +357,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func hCenter(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "hCenter", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -406,8 +365,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func right(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "right", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -415,8 +373,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func start(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "start", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -424,8 +381,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func end(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "end", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { @@ -439,7 +395,6 @@ class PinLayoutImpl: PinLayout { // centerLeft, center, centerRight, // bottomLeft, bottomCenter, bottomRight, // - @discardableResult func topLeft(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topLeft", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -448,7 +403,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func topLeft() -> PinLayout { return topLeft({ return "topLeft()" }) } @@ -457,8 +411,7 @@ class PinLayoutImpl: PinLayout { setTopLeft(CGPoint(x: 0, y: 0), { return "topLeft()" }) return self } - - @discardableResult + func topStart(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topStart", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -468,13 +421,11 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func topStart() -> PinLayout { func context() -> String { return "topStart()" } return isLTR() ? topLeft(context) : topRight(context) } - - @discardableResult + func topCenter(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topCenter", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -483,7 +434,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func topCenter() -> PinLayout { func context() -> String { return "topCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } @@ -491,7 +441,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func topRight(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topRight", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -500,7 +449,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func topRight() -> PinLayout { return topRight({ return "topRight()" }) } @@ -510,8 +458,7 @@ class PinLayoutImpl: PinLayout { setTopRight(CGPoint(x: layoutSuperviewRect.width, y: 0), context) return self } - - @discardableResult + func topEnd(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topEnd", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -520,14 +467,12 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func topEnd() -> PinLayout { func context() -> String { return "topEnd()" } return isLTR() ? topRight(context) : topLeft(context) } - - @discardableResult + func centerLeft(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerLeft", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -535,8 +480,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func centerLeft() -> PinLayout { return centerLeft({ return "centerLeft()" }) } @@ -547,7 +491,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func centerStart(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerStart", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -556,14 +499,12 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func centerStart() -> PinLayout { func context() -> String { return "centerStart()" } return isLTR() ? centerLeft(context) : centerRight(context) } - - @discardableResult + func center(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "center", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -571,16 +512,14 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func center() -> PinLayout { func context() -> String { return "center()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: layoutSuperviewRect.height / 2), context) return self } - - @discardableResult + func centerRight(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerRight", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -588,20 +527,17 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func centerRight() -> PinLayout { return centerRight({ return "centerRight()" }) } - - @discardableResult + fileprivate func centerRight(_ context: Context) -> PinLayout { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setCenterRight(CGPoint(x: layoutSuperviewRect.width, y: layoutSuperviewRect.height / 2), context) return self } - - @discardableResult + func centerEnd(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerEnd", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -610,14 +546,12 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func centerEnd() -> PinLayout { func context() -> String { return "centerEnd()" } return isLTR() ? centerRight(context) : centerLeft(context) } - - @discardableResult + func bottomLeft(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomLeft", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -626,19 +560,16 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func bottomLeft() -> PinLayout { return bottomLeft({ return "bottomLeft()" }) } - - @discardableResult + fileprivate func bottomLeft(_ context: Context) -> PinLayout { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setBottomLeft(CGPoint(x: 0, y: layoutSuperviewRect.height), context) return self } - - @discardableResult + func bottomStart(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomStart", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -647,14 +578,12 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func bottomStart() -> PinLayout { func context() -> String { return "bottomStart()" } return isLTR() ? bottomLeft(context) : bottomRight(context) } - @discardableResult func bottomCenter(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomCenter", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -663,7 +592,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func bottomCenter() -> PinLayout { func context() -> String { return "bottomCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } @@ -671,7 +599,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func bottomRight(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomRight", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -680,19 +607,16 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func bottomRight() -> PinLayout { return bottomRight({ return "bottomRight()" }) } - - @discardableResult + fileprivate func bottomRight(_ context: Context) -> PinLayout { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setBottomRight(CGPoint(x: layoutSuperviewRect.width, y: layoutSuperviewRect.height), context) return self } - @discardableResult func bottomEnd(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomEnd", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { @@ -701,8 +625,7 @@ class PinLayoutImpl: PinLayout { } return self } - - @discardableResult + func bottomEnd() -> PinLayout { func context() -> String { return "bottomEnd()" } return isLTR() ? bottomRight(context) : bottomLeft(context) @@ -711,86 +634,72 @@ class PinLayoutImpl: PinLayout { // // width, height // - @discardableResult func width(_ width: CGFloat) -> PinLayout { return setWidth(width, { return "width(\(width))" }) } - - @discardableResult + func width(_ percent: Percent) -> PinLayout { func context() -> String { return "width(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setWidth(percent.of(layoutSuperviewRect.width), context) } - @discardableResult func width(of view: PView) -> PinLayout { return setWidth(view.bounds.width, { return "width(of: \(viewDescription(view)))" }) } - - @discardableResult + func minWidth(_ width: CGFloat) -> PinLayout { setMinWidth(width, { return "minWidth(\(width))" }) return self } - - @discardableResult + func minWidth(_ percent: Percent) -> PinLayout { func context() -> String { return "minWidth(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMinWidth(percent.of(layoutSuperviewRect.width), context) } - - @discardableResult + func maxWidth(_ width: CGFloat) -> PinLayout { setMaxWidth(width, { return "maxWidth(\(width))" }) return self } - - @discardableResult + func maxWidth(_ percent: Percent) -> PinLayout { func context() -> String { return "maxWidth(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMaxWidth(percent.of(layoutSuperviewRect.width), context) } - @discardableResult func height(_ height: CGFloat) -> PinLayout { return setHeight(height, { return "height(\(height))" }) } - - @discardableResult + func height(_ percent: Percent) -> PinLayout { func context() -> String { return "height(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setHeight(percent.of(layoutSuperviewRect.height), context) } - @discardableResult func height(of view: PView) -> PinLayout { return setHeight(view.bounds.height, { return "height(of: \(viewDescription(view)))" }) } - - @discardableResult + func minHeight(_ height: CGFloat) -> PinLayout { setMinHeight(height, { return "minHeight(\(height))" }) return self } - - @discardableResult + func minHeight(_ percent: Percent) -> PinLayout { func context() -> String { return "minHeight(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMinHeight(percent.of(layoutSuperviewRect.height), context) } - - @discardableResult + func maxHeight(_ height: CGFloat) -> PinLayout { setMaxHeight(height, { return "maxHeight(\(height))" }) return self } - - @discardableResult + func maxHeight(_ percent: Percent) -> PinLayout { func context() -> String { return "maxHeight(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } @@ -800,50 +709,42 @@ class PinLayoutImpl: PinLayout { // // size, sizeToFit // - @discardableResult func size(_ size: CGSize) -> PinLayout { return setSize(size, { return "size(CGSize(width: \(size.width), height: \(size.height)))" }) } - - @discardableResult + func size(_ sideLength: CGFloat) -> PinLayout { return setSize(CGSize(width: sideLength, height: sideLength), { return "size(sideLength: \(sideLength))" }) } - - @discardableResult + func size(_ percent: Percent) -> PinLayout { func context() -> String { return "size(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } let size = CGSize(width: percent.of(layoutSuperviewRect.width), height: percent.of(layoutSuperviewRect.height)) return setSize(size, context) } - - @discardableResult + func size(of view: PView) -> PinLayout { func context() -> String { return "size(of \(viewDescription(view)))" } return setSize(view.bounds.size, context) } - -// @discardableResult + // func wrapSubViews() -> PinLayout { // let neededWidth = view.subviews.max(by: { subview1, subview2 in subview1.frame.maxX < subview2.frame.maxX })?.frame.maxX ?? 0 // let neededHeight = view.subviews.max(by: { subview1, subview2 in subview1.frame.maxY < subview2.frame.maxY })?.frame.maxY ?? 0 // // return setSize(CGSize(width: neededWidth, height: neededHeight), { return "wrapSubViews()" }) // } - - @discardableResult + func aspectRatio(_ ratio: CGFloat) -> PinLayout { return setAspectRatio(ratio, context: { "aspectRatio(\(ratio))" }) } - - @discardableResult + func aspectRatio(of view: PView) -> PinLayout { return setAspectRatio(view.bounds.width / view.bounds.height, context: { "aspectRatio(of: \(viewDescription(view)))" }) } #if os(iOS) || os(tvOS) - @discardableResult func aspectRatio() -> PinLayout { func context() -> String { return "aspectRatio()" } if let imageView = view as? UIImageView { @@ -858,26 +759,22 @@ class PinLayoutImpl: PinLayout { return self } #endif - - @discardableResult + func sizeToFit(_ fitType: FitType) -> PinLayout { return setFitSize(fitType: fitType, { return "sizeToFit(\(fitType.name))" }) } #if os(iOS) || os(tvOS) - @discardableResult func fitSize() -> PinLayout { return setFitSize(fitType: nil, { return "fitSize()" }) } #endif - @discardableResult func justify(_ value: HorizontalAlign) -> PinLayout { justify = value return self } - - @discardableResult + func align(_ value: VerticalAlign) -> PinLayout { align = value return self @@ -886,88 +783,75 @@ class PinLayoutImpl: PinLayout { // // Margins // - @discardableResult func marginTop(_ value: CGFloat) -> PinLayout { marginTop = value return self } - @discardableResult func marginTop(_ percent: Percent) -> PinLayout { func context() -> String { return "marginTop(\(percent.description))" } return marginTop(percent, context) } - @discardableResult private func marginTop(_ percent: Percent, _ context: Context) -> Self { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } marginTop = percent.of(layoutSuperviewRect.height) return self } - @discardableResult func marginLeft(_ value: CGFloat) -> PinLayout { marginLeft = value return self } - @discardableResult func marginLeft(_ percent: Percent) -> PinLayout { func context() -> String { return "marginLeft(\(percent.description))" } return marginLeft(percent, context) } - @discardableResult private func marginLeft(_ percent: Percent, _ context: Context) -> Self { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } marginLeft = percent.of(layoutSuperviewRect.width) return self } - @discardableResult func marginBottom(_ value: CGFloat) -> PinLayout { marginBottom = value return self } - @discardableResult func marginBottom(_ percent: Percent) -> PinLayout { func context() -> String { return "marginBottom(\(percent.description))" } return marginBottom(percent, context) } - @discardableResult private func marginBottom(_ percent: Percent, _ context: Context) -> Self { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } marginBottom = percent.of(layoutSuperviewRect.height) return self } - @discardableResult func marginRight(_ value: CGFloat) -> PinLayout { marginRight = value return self } - @discardableResult func marginRight(_ percent: Percent) -> PinLayout { func context() -> String { return "marginRight(\(percent.description))" } return marginRight(percent, context) } - @discardableResult private func marginRight(_ percent: Percent, _ context: Context) -> Self { guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } marginRight = percent.of(layoutSuperviewRect.width) return self } - + @discardableResult func marginStart(_ value: CGFloat) -> PinLayout { return isLTR() ? marginLeft(value) : marginRight(value) } - @discardableResult func marginStart(_ percent: Percent) -> PinLayout { func context() -> String { return "marginStart(\(percent.description))" } return isLTR() ? marginLeft(percent, context) : marginRight(percent, context) @@ -978,49 +862,41 @@ class PinLayoutImpl: PinLayout { return isLTR() ? marginRight(value) : marginLeft(value) } - @discardableResult func marginEnd(_ percent: Percent) -> PinLayout { func context() -> String { return "marginEnd(\(percent.description))" } return isLTR() ? marginRight(percent, context) : marginLeft(percent, context) } - @discardableResult func marginHorizontal(_ value: CGFloat) -> PinLayout { marginLeft = value marginRight = value return self } - @discardableResult func marginHorizontal(_ percent: Percent) -> PinLayout { func context() -> String { return "marginHorizontal(\(percent.description))" } return marginHorizontal(percent, context) } - @discardableResult private func marginHorizontal(_ percent: Percent, _ context: Context) -> Self { return marginLeft(percent, context).marginRight(percent, context) } - @discardableResult func marginVertical(_ value: CGFloat) -> PinLayout { marginTop = value marginBottom = value return self } - @discardableResult func marginVertical(_ percent: Percent) -> PinLayout { func context() -> String { return "marginVertical(\(percent.description))" } return marginVertical(percent, context) } - @discardableResult private func marginVertical(_ percent: Percent, _ context: Context) -> Self { return marginTop(percent, context).marginBottom(percent, context) } - @discardableResult func margin(_ insets: PEdgeInsets) -> PinLayout { marginTop = insets.top marginBottom = insets.bottom @@ -1031,7 +907,6 @@ class PinLayoutImpl: PinLayout { #if os(iOS) || os(tvOS) @available(tvOS 11.0, iOS 11.0, *) - @discardableResult func margin(_ directionalInsets: NSDirectionalEdgeInsets) -> PinLayout { marginTop = directionalInsets.top marginBottom = directionalInsets.bottom @@ -1041,7 +916,6 @@ class PinLayoutImpl: PinLayout { } #endif - @discardableResult func margin(_ value: CGFloat) -> PinLayout { marginTop = value marginLeft = value @@ -1050,7 +924,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func margin(_ percent: Percent) -> PinLayout { func context() -> String { return "margin(\(percent.description))" } return marginTop(percent, context) @@ -1059,7 +932,6 @@ class PinLayoutImpl: PinLayout { .marginRight(percent, context) } - @discardableResult func margin(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> PinLayout { marginTop = top marginLeft = left @@ -1068,7 +940,6 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func margin(_ top: Percent, _ left: Percent, _ bottom: Percent, _ right: Percent) -> PinLayout { func context() -> String { return "margin(top: \(top.description), left: \(left.description), bottom: \(bottom.description), right: \(right.description)" @@ -1079,7 +950,7 @@ class PinLayoutImpl: PinLayout { .marginRight(right, context) } - @discardableResult func margin(_ vertical: CGFloat, _ horizontal: CGFloat) -> PinLayout { + func margin(_ vertical: CGFloat, _ horizontal: CGFloat) -> PinLayout { marginTop = vertical marginLeft = horizontal marginBottom = vertical @@ -1087,13 +958,12 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func margin(_ vertical: Percent, _ horizontal: Percent) -> PinLayout { func context() -> String { return "margin(vertical: \(vertical.description), horizontal: \(horizontal.description)"} return marginVertical(vertical, context).marginHorizontal(horizontal, context) } - @discardableResult func margin(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat) -> PinLayout { + func margin(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat) -> PinLayout { marginTop = top marginLeft = horizontal marginBottom = bottom @@ -1101,13 +971,11 @@ class PinLayoutImpl: PinLayout { return self } - @discardableResult func margin(_ top: Percent, _ horizontal: Percent, _ bottom: Percent) -> PinLayout { func context() -> String { return "margin(top: \(top.description), horizontal: \(horizontal.description), bottom: \(bottom.description)"} return marginTop(top, context).marginHorizontal(horizontal, context).marginBottom(bottom, context) } - @discardableResult func pinEdges() -> PinLayout { shouldPinEdges = true return self @@ -1134,7 +1002,7 @@ extension PinLayoutImpl { } return self } - + @discardableResult internal func setAspectRatio(_ ratio: CGFloat, context: Context) -> PinLayout { if let fitType = fitType { diff --git a/Sources/Impl/PinSafeArea.swift b/Sources/Impl/PinSafeArea.swift index ba57f4c1..1938dd73 100644 --- a/Sources/Impl/PinSafeArea.swift +++ b/Sources/Impl/PinSafeArea.swift @@ -261,4 +261,3 @@ extension UIView { } } #endif - diff --git a/Sources/Impl/TypesImpl.swift b/Sources/Impl/TypesImpl.swift index 4418fadd..eb1060d2 100644 --- a/Sources/Impl/TypesImpl.swift +++ b/Sources/Impl/TypesImpl.swift @@ -209,4 +209,3 @@ internal extension FitType { return self == .widthFlexible || self == .heightFlexible } } - diff --git a/Sources/NSView+PinLayout.swift b/Sources/NSView+PinLayout.swift index 6e564a13..7536316f 100644 --- a/Sources/NSView+PinLayout.swift +++ b/Sources/NSView+PinLayout.swift @@ -27,5 +27,11 @@ public extension NSView { public var edge: EdgeList { return EdgeListImpl(view: self) } + + // Expose PinLayout's objective-c interface. + @objc public var pinObjc: PinLayoutObjC { + return PinLayoutObjCImpl(view: self, keepTransform: true) + } } + #endif diff --git a/Sources/ObjectiveC/PinLayoutObjC.swift b/Sources/ObjectiveC/PinLayoutObjC.swift index f7d9ade7..0eb16a64 100644 --- a/Sources/ObjectiveC/PinLayoutObjC.swift +++ b/Sources/ObjectiveC/PinLayoutObjC.swift @@ -21,14 +21,9 @@ import Foundation #if os(iOS) || os(tvOS) import UIKit - -// MARK: - PinLayout UIView's extension -public extension UIView { - // Expose PinLayout's objective-c interface. - @objc public var pinObjc: PinLayoutObjC { - return PinLayoutObjCImpl(view: self, keepTransform: true) - } -} +#else +import AppKit +#endif /** We must have a different interface for objective-c. The PinLayout's Swift interface use some @@ -138,35 +133,67 @@ public extension UIView { // // MARK: Layout using relative positioning // - @discardableResult func above(of: UIView) -> PinLayoutObjC - @discardableResult func above(ofViews: [UIView]) -> PinLayoutObjC - @discardableResult func above(of: UIView, aligned: HorizontalAlign) -> PinLayoutObjC - @discardableResult func above(ofViews: [UIView], aligned: HorizontalAlign) -> PinLayoutObjC - - @discardableResult func below(of: UIView) -> PinLayoutObjC - @discardableResult func below(ofViews: [UIView]) -> PinLayoutObjC - @discardableResult func below(of: UIView, aligned: HorizontalAlign) -> PinLayoutObjC - @discardableResult func below(ofViews: [UIView], aligned: HorizontalAlign) -> PinLayoutObjC - - @discardableResult func left(of: UIView) -> PinLayoutObjC - @discardableResult func left(ofViews: [UIView]) -> PinLayoutObjC - @discardableResult func left(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC - @discardableResult func left(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC - - @discardableResult func right(of: UIView) -> PinLayoutObjC - @discardableResult func right(ofViews: [UIView]) -> PinLayoutObjC - @discardableResult func right(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC - @discardableResult func right(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC - - // RTL support - @discardableResult func before(of: UIView) -> PinLayoutObjC - @discardableResult func before(ofViews: [UIView]) -> PinLayoutObjC - @discardableResult func before(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC - @discardableResult func before(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC - @discardableResult func after(of: UIView) -> PinLayoutObjC - @discardableResult func after(ofViews: [UIView]) -> PinLayoutObjC - @discardableResult func after(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC - @discardableResult func after(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC + #if os(iOS) || os(tvOS) + @discardableResult func above(of: UIView) -> PinLayoutObjC + @discardableResult func above(ofViews: [UIView]) -> PinLayoutObjC + @discardableResult func above(of: UIView, aligned: HorizontalAlign) -> PinLayoutObjC + @discardableResult func above(ofViews: [UIView], aligned: HorizontalAlign) -> PinLayoutObjC + + @discardableResult func below(of: UIView) -> PinLayoutObjC + @discardableResult func below(ofViews: [UIView]) -> PinLayoutObjC + @discardableResult func below(of: UIView, aligned: HorizontalAlign) -> PinLayoutObjC + @discardableResult func below(ofViews: [UIView], aligned: HorizontalAlign) -> PinLayoutObjC + + @discardableResult func left(of: UIView) -> PinLayoutObjC + @discardableResult func left(ofViews: [UIView]) -> PinLayoutObjC + @discardableResult func left(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func left(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC + + @discardableResult func right(of: UIView) -> PinLayoutObjC + @discardableResult func right(ofViews: [UIView]) -> PinLayoutObjC + @discardableResult func right(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func right(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC + + // RTL support + @discardableResult func before(of: UIView) -> PinLayoutObjC + @discardableResult func before(ofViews: [UIView]) -> PinLayoutObjC + @discardableResult func before(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func before(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func after(of: UIView) -> PinLayoutObjC + @discardableResult func after(ofViews: [UIView]) -> PinLayoutObjC + @discardableResult func after(of: UIView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func after(ofViews: [UIView], aligned: VerticalAlign) -> PinLayoutObjC + #elseif os(macOS) + @discardableResult func above(of: NSView) -> PinLayoutObjC + @discardableResult func above(ofViews: [NSView]) -> PinLayoutObjC + @discardableResult func above(of: NSView, aligned: HorizontalAlign) -> PinLayoutObjC + @discardableResult func above(ofViews: [NSView], aligned: HorizontalAlign) -> PinLayoutObjC + + @discardableResult func below(of: NSView) -> PinLayoutObjC + @discardableResult func below(ofViews: [NSView]) -> PinLayoutObjC + @discardableResult func below(of: NSView, aligned: HorizontalAlign) -> PinLayoutObjC + @discardableResult func below(ofViews: [NSView], aligned: HorizontalAlign) -> PinLayoutObjC + + @discardableResult func left(of: NSView) -> PinLayoutObjC + @discardableResult func left(ofViews: [NSView]) -> PinLayoutObjC + @discardableResult func left(of: NSView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func left(ofViews: [NSView], aligned: VerticalAlign) -> PinLayoutObjC + + @discardableResult func right(of: NSView) -> PinLayoutObjC + @discardableResult func right(ofViews: [NSView]) -> PinLayoutObjC + @discardableResult func right(of: NSView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func right(ofViews: [NSView], aligned: VerticalAlign) -> PinLayoutObjC + + // RTL support + @discardableResult func before(of: NSView) -> PinLayoutObjC + @discardableResult func before(ofViews: [NSView]) -> PinLayoutObjC + @discardableResult func before(of: NSView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func before(ofViews: [NSView], aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func after(of: NSView) -> PinLayoutObjC + @discardableResult func after(ofViews: [NSView]) -> PinLayoutObjC + @discardableResult func after(of: NSView, aligned: VerticalAlign) -> PinLayoutObjC + @discardableResult func after(ofViews: [NSView], aligned: VerticalAlign) -> PinLayoutObjC + #endif // // MARK: justify / align @@ -179,7 +206,12 @@ public extension UIView { // @discardableResult func width(_ width: CGFloat) -> PinLayoutObjC @discardableResult func width(percent: CGFloat) -> PinLayoutObjC + #if os(iOS) || os(tvOS) @discardableResult func width(of view: UIView) -> PinLayoutObjC + #elseif os(macOS) + @discardableResult func width(of view: NSView) -> PinLayoutObjC + #endif + @discardableResult func minWidth(_ width: CGFloat) -> PinLayoutObjC @discardableResult func minWidth(percent: CGFloat) -> PinLayoutObjC @discardableResult func maxWidth(_ width: CGFloat) -> PinLayoutObjC @@ -187,7 +219,12 @@ public extension UIView { @discardableResult func height(_ height: CGFloat) -> PinLayoutObjC @discardableResult func height(percent: CGFloat) -> PinLayoutObjC + #if os(iOS) || os(tvOS) @discardableResult func height(of view: UIView) -> PinLayoutObjC + #elseif os(macOS) + @discardableResult func height(of view: NSView) -> PinLayoutObjC + #endif + @discardableResult func minHeight(_ height: CGFloat) -> PinLayoutObjC @discardableResult func minHeight(percent: CGFloat) -> PinLayoutObjC @discardableResult func maxHeight(_ height: CGFloat) -> PinLayoutObjC @@ -196,7 +233,11 @@ public extension UIView { @discardableResult func size(_ size: CGSize) -> PinLayoutObjC @discardableResult func size(length: CGFloat) -> PinLayoutObjC @discardableResult func size(percent: CGFloat) -> PinLayoutObjC + #if os(iOS) || os(tvOS) @discardableResult func size(of view: UIView) -> PinLayoutObjC + #elseif os(macOS) + @discardableResult func size(of view: NSView) -> PinLayoutObjC + #endif /** Set the view aspect ratio. @@ -220,17 +261,24 @@ public extension UIView { * AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight) dimensions of an item. */ + #if os(iOS) || os(tvOS) @discardableResult func aspectRatio(of view: UIView) -> PinLayoutObjC + #elseif os(macOS) + @discardableResult func aspectRatio(of view: NSView) -> PinLayoutObjC + #endif + + /** If the layouted view is an UIImageView, this method will set the aspectRatio using the UIImageView's image dimension. For other types of views, this method as no impact. */ + #if os(iOS) || os(tvOS) @discardableResult func aspectRatio() -> PinLayoutObjC + #endif @discardableResult func sizeToFit(_ fitType: Fit) -> PinLayoutObjC - @discardableResult func fitSize() -> PinLayoutObjC // // MARK: Margins @@ -289,7 +337,11 @@ public extension UIView { Set all margins using UIEdgeInsets. This method is particularly useful to set all margins using iOS 11 `UIView.safeAreaInsets`. */ + #if os(iOS) || os(tvOS) @discardableResult func margin(insets: UIEdgeInsets) -> PinLayoutObjC + #elseif os(macOS) + @discardableResult func margin(insets: NSEdgeInsets) -> PinLayoutObjC + #endif /** Set margins using NSDirectionalEdgeInsets. @@ -335,5 +387,3 @@ public extension UIView { case widthFlexible case heightFlexible } - -#endif diff --git a/Sources/ObjectiveC/PinLayoutObjCImpl.swift b/Sources/ObjectiveC/PinLayoutObjCImpl.swift index 89f7cc78..87ad03a7 100644 --- a/Sources/ObjectiveC/PinLayoutObjCImpl.swift +++ b/Sources/ObjectiveC/PinLayoutObjCImpl.swift @@ -19,11 +19,14 @@ #if os(iOS) || os(tvOS) import UIKit +#else +import AppKit +#endif -@objc public class PinLayoutObjCImpl: NSObject, PinLayoutObjC { +@objc class PinLayoutObjCImpl: NSObject, PinLayoutObjC { fileprivate var impl: PinLayoutImpl? - init(view: UIView, keepTransform: Bool) { + init(view: PView, keepTransform: Bool) { impl = PinLayoutImpl(view: view, keepTransform: keepTransform) } @@ -33,589 +36,586 @@ import UIKit } } - public func layout() { + func layout() { // With objective-c PinLayoutObjCImpl instance are sometimes deallocated only after the context has been quit. For this reason // developpers must call the layout: method implicetely. impl?.layout() impl = nil } - - public func top() -> PinLayoutObjC { - impl?.top() + + func top() -> PinLayoutObjC { + _ = impl?.top() return self } - public func top(_ value: CGFloat) -> PinLayoutObjC { - impl?.top(value) + func top(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.top(value) return self } - public func top(percent: CGFloat) -> PinLayoutObjC { - impl?.top(percent%) + func top(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.top(percent%) return self } - public func left() -> PinLayoutObjC { - impl?.left() + func left() -> PinLayoutObjC { + _ = impl?.left() return self } - public func left(_ value: CGFloat) -> PinLayoutObjC { - impl?.left(value) + func left(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.left(value) return self } - public func left(percent: CGFloat) -> PinLayoutObjC { - impl?.left(percent%) + func left(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.left(percent%) return self } - public func bottom() -> PinLayoutObjC { - impl?.bottom() + func bottom() -> PinLayoutObjC { + _ = impl?.bottom() return self } - public func bottom(_ value: CGFloat) -> PinLayoutObjC { - impl?.bottom(value) + func bottom(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.bottom(value) return self } - public func bottom(percent: CGFloat) -> PinLayoutObjC { - impl?.bottom(percent%) + func bottom(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.bottom(percent%) return self } - public func right() -> PinLayoutObjC { - impl?.right() + func right() -> PinLayoutObjC { + _ = impl?.right() return self } - public func right(_ value: CGFloat) -> PinLayoutObjC { - impl?.right(value) + func right(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.right(value) return self } - public func right(percent: CGFloat) -> PinLayoutObjC { - impl?.right(percent%) + func right(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.right(percent%) return self } - public func hCenter() -> PinLayoutObjC { - impl?.hCenter() + func hCenter() -> PinLayoutObjC { + _ = impl?.hCenter() return self } - public func hCenter(_ value: CGFloat) -> PinLayoutObjC { - impl?.hCenter(value) + func hCenter(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.hCenter(value) return self } - public func hCenter(percent: CGFloat) -> PinLayoutObjC { - impl?.hCenter(percent%) + func hCenter(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.hCenter(percent%) return self } - public func vCenter() -> PinLayoutObjC { - impl?.vCenter() + func vCenter() -> PinLayoutObjC { + _ = impl?.vCenter() return self } - public func vCenter(_ value: CGFloat) -> PinLayoutObjC { - impl?.vCenter(value) + func vCenter(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.vCenter(value) return self } - public func vCenter(percent: CGFloat) -> PinLayoutObjC { - impl?.vCenter(percent%) + func vCenter(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.vCenter(percent%) return self } - public func start() -> PinLayoutObjC { - impl?.start() + func start() -> PinLayoutObjC { + _ = impl?.start() return self } - public func start(_ value: CGFloat) -> PinLayoutObjC { - impl?.start(value) + func start(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.start(value) return self } - public func start(percent: CGFloat) -> PinLayoutObjC { - impl?.start(percent%) + func start(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.start(percent%) return self } - public func end() -> PinLayoutObjC { - impl?.end() + func end() -> PinLayoutObjC { + _ = impl?.end() return self } - public func end(_ value: CGFloat) -> PinLayoutObjC { - impl?.end(value) + func end(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.end(value) return self } - public func end(percent: CGFloat) -> PinLayoutObjC { - impl?.end(percent%) + func end(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.end(percent%) return self } - public func top(to edge: VerticalEdge) -> PinLayoutObjC { - impl?.top(to: edge) + func top(to edge: VerticalEdge) -> PinLayoutObjC { + _ = impl?.top(to: edge) return self } - public func vCenter(to edge: VerticalEdge) -> PinLayoutObjC { - impl?.vCenter(to: edge) + func vCenter(to edge: VerticalEdge) -> PinLayoutObjC { + _ = impl?.vCenter(to: edge) return self } - public func bottom(to edge: VerticalEdge) -> PinLayoutObjC { - impl?.bottom(to: edge) + func bottom(to edge: VerticalEdge) -> PinLayoutObjC { + _ = impl?.bottom(to: edge) return self } - public func left(to edge: HorizontalEdge) -> PinLayoutObjC { - impl?.left(to: edge) + func left(to edge: HorizontalEdge) -> PinLayoutObjC { + _ = impl?.left(to: edge) return self } - public func hCenter(to edge: HorizontalEdge) -> PinLayoutObjC { - impl?.hCenter(to: edge) + func hCenter(to edge: HorizontalEdge) -> PinLayoutObjC { + _ = impl?.hCenter(to: edge) return self } - public func right(to edge: HorizontalEdge) -> PinLayoutObjC { - impl?.right(to: edge) + func right(to edge: HorizontalEdge) -> PinLayoutObjC { + _ = impl?.right(to: edge) return self } - public func start(to edge: HorizontalEdge) -> PinLayoutObjC { - impl?.start(to: edge) + func start(to edge: HorizontalEdge) -> PinLayoutObjC { + _ = impl?.start(to: edge) return self } - public func end(to edge: HorizontalEdge) -> PinLayoutObjC { - impl?.end(to: edge) + func end(to edge: HorizontalEdge) -> PinLayoutObjC { + _ = impl?.end(to: edge) return self } - public func all() -> PinLayoutObjC { - impl?.all() + func all() -> PinLayoutObjC { + _ = impl?.all() return self } - public func horizontally() -> PinLayoutObjC { - impl?.horizontally() + func horizontally() -> PinLayoutObjC { + _ = impl?.horizontally() return self } - public func horizontally(_ value: CGFloat) -> PinLayoutObjC { - impl?.horizontally(value) + func horizontally(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.horizontally(value) return self } - public func vertically() -> PinLayoutObjC { - impl?.vertically() + func vertically() -> PinLayoutObjC { + _ = impl?.vertically() return self } - public func vertically(_ value: CGFloat) -> PinLayoutObjC { - impl?.vertically(value) - return self - } - - public func topLeft(to anchor: Anchor) -> PinLayoutObjC { - impl?.topLeft(to: anchor) + func vertically(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.vertically(value) return self } - public func topLeft() -> PinLayoutObjC { - impl?.topLeft() + func topLeft(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.topLeft(to: anchor) return self } - public func topStart(to anchor: Anchor) -> PinLayoutObjC { - impl?.topStart(to: anchor) + func topLeft() -> PinLayoutObjC { + _ = impl?.topLeft() return self } - public func topStart() -> PinLayoutObjC { - impl?.topStart() + func topStart(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.topStart(to: anchor) return self } - public func topCenter(to anchor: Anchor) -> PinLayoutObjC { - impl?.topCenter(to: anchor) + func topStart() -> PinLayoutObjC { + _ = impl?.topStart() return self } - public func topCenter() -> PinLayoutObjC { - impl?.topCenter() + func topCenter(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.topCenter(to: anchor) return self } - public func topRight(to anchor: Anchor) -> PinLayoutObjC { - impl?.topRight(to: anchor) + func topCenter() -> PinLayoutObjC { + _ = impl?.topCenter() return self } - public func topRight() -> PinLayoutObjC { - impl?.topRight() + func topRight(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.topRight(to: anchor) return self } - public func topEnd(to anchor: Anchor) -> PinLayoutObjC { - impl?.topEnd(to: anchor) + func topRight() -> PinLayoutObjC { + _ = impl?.topRight() return self } - public func topEnd() -> PinLayoutObjC { - impl?.topEnd() + func topEnd(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.topEnd(to: anchor) return self } - public func centerLeft(to anchor: Anchor) -> PinLayoutObjC { - impl?.centerLeft(to: anchor) + func topEnd() -> PinLayoutObjC { + _ = impl?.topEnd() return self } - public func centerLeft() -> PinLayoutObjC { - impl?.centerLeft() + func centerLeft(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.centerLeft(to: anchor) return self } - public func centerStart(to anchor: Anchor) -> PinLayoutObjC { - impl?.centerStart(to: anchor) + func centerLeft() -> PinLayoutObjC { + _ = impl?.centerLeft() return self } - public func centerStart() -> PinLayoutObjC { - impl?.centerStart() + func centerStart(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.centerStart(to: anchor) return self } - public func center(to anchor: Anchor) -> PinLayoutObjC { - impl?.center(to: anchor) + func centerStart() -> PinLayoutObjC { + _ = impl?.centerStart() return self } - public func center() -> PinLayoutObjC { - impl?.center() + func center(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.center(to: anchor) return self } - public func centerRight(to anchor: Anchor) -> PinLayoutObjC { - impl?.centerRight(to: anchor) + func center() -> PinLayoutObjC { + _ = impl?.center() return self } - public func centerRight() -> PinLayoutObjC { - impl?.centerRight() + func centerRight(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.centerRight(to: anchor) return self } - public func centerEnd(to anchor: Anchor) -> PinLayoutObjC { - impl?.centerEnd(to: anchor) + func centerRight() -> PinLayoutObjC { + _ = impl?.centerRight() return self } - public func centerEnd() -> PinLayoutObjC { - impl?.centerEnd() + func centerEnd(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.centerEnd(to: anchor) return self } - public func bottomLeft(to anchor: Anchor) -> PinLayoutObjC { - impl?.bottomLeft(to: anchor) + func centerEnd() -> PinLayoutObjC { + _ = impl?.centerEnd() return self } - public func bottomLeft() -> PinLayoutObjC { - impl?.bottomLeft() + func bottomLeft(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.bottomLeft(to: anchor) return self } - public func bottomStart(to anchor: Anchor) -> PinLayoutObjC { - impl?.bottomStart(to: anchor) + func bottomLeft() -> PinLayoutObjC { + _ = impl?.bottomLeft() return self } - public func bottomStart() -> PinLayoutObjC { - impl?.bottomStart() + func bottomStart(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.bottomStart(to: anchor) return self } - public func bottomCenter(to anchor: Anchor) -> PinLayoutObjC { - impl?.bottomCenter(to: anchor) + func bottomStart() -> PinLayoutObjC { + _ = impl?.bottomStart() return self } - public func bottomCenter() -> PinLayoutObjC { - impl?.bottomCenter() + func bottomCenter(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.bottomCenter(to: anchor) return self } - public func bottomRight(to anchor: Anchor) -> PinLayoutObjC { - impl?.bottomRight(to: anchor) + func bottomCenter() -> PinLayoutObjC { + _ = impl?.bottomCenter() return self } - public func bottomRight() -> PinLayoutObjC { - impl?.bottomRight() + func bottomRight(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.bottomRight(to: anchor) return self } - public func bottomEnd(to anchor: Anchor) -> PinLayoutObjC { - impl?.bottomEnd(to: anchor) + func bottomRight() -> PinLayoutObjC { + _ = impl?.bottomRight() return self } - public func bottomEnd() -> PinLayoutObjC { - impl?.bottomEnd() + func bottomEnd(to anchor: Anchor) -> PinLayoutObjC { + _ = impl?.bottomEnd(to: anchor) return self } - public func above(of view: UIView) -> PinLayoutObjC { - impl?.above(of: view) + func bottomEnd() -> PinLayoutObjC { + _ = impl?.bottomEnd() return self } - public func above(ofViews views: [UIView]) -> PinLayoutObjC { - impl?.above(of: views) + func above(of view: PView) -> PinLayoutObjC { + _ = impl?.above(of: view) return self } - public func above(of view: UIView, aligned: HorizontalAlign) -> PinLayoutObjC { - impl?.above(of: view, aligned: aligned) + func above(ofViews views: [PView]) -> PinLayoutObjC { + _ = impl?.above(of: views) return self } - public func above(ofViews views: [UIView], aligned: HorizontalAlign) -> PinLayoutObjC { - impl?.above(of: views, aligned: aligned) + func above(of view: PView, aligned: HorizontalAlign) -> PinLayoutObjC { + _ = impl?.above(of: view, aligned: aligned) return self } - public func below(of view: UIView) -> PinLayoutObjC { - impl?.below(of: view) + func above(ofViews views: [PView], aligned: HorizontalAlign) -> PinLayoutObjC { + _ = impl?.above(of: views, aligned: aligned) return self } - public func below(ofViews views: [UIView]) -> PinLayoutObjC { - impl?.below(of: views) + func below(of view: PView) -> PinLayoutObjC { + _ = impl?.below(of: view) return self } - public func below(of view: UIView, aligned: HorizontalAlign) -> PinLayoutObjC { - impl?.below(of: view, aligned: aligned) + func below(ofViews views: [PView]) -> PinLayoutObjC { + _ = impl?.below(of: views) return self } - public func below(ofViews views: [UIView], aligned: HorizontalAlign) -> PinLayoutObjC { - impl?.below(of: views, aligned: aligned) + func below(of view: PView, aligned: HorizontalAlign) -> PinLayoutObjC { + _ = impl?.below(of: view, aligned: aligned) return self } - public func left(of view: UIView) -> PinLayoutObjC { - impl?.left(of: view) + func below(ofViews views: [PView], aligned: HorizontalAlign) -> PinLayoutObjC { + _ = impl?.below(of: views, aligned: aligned) return self } - public func left(ofViews views: [UIView]) -> PinLayoutObjC { - impl?.left(of: views) + func left(of view: PView) -> PinLayoutObjC { + _ = impl?.left(of: view) return self } - public func left(of view: UIView, aligned: VerticalAlign) -> PinLayoutObjC { - impl?.left(of: view, aligned: aligned) + func left(ofViews views: [PView]) -> PinLayoutObjC { + _ = impl?.left(of: views) return self } - public func left(ofViews views: [UIView], aligned: VerticalAlign) -> PinLayoutObjC { - impl?.left(of: views, aligned: aligned) + func left(of view: PView, aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.left(of: view, aligned: aligned) return self } - public func right(of view: UIView) -> PinLayoutObjC { - impl?.right(of: view) + func left(ofViews views: [PView], aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.left(of: views, aligned: aligned) return self } - public func right(ofViews views: [UIView]) -> PinLayoutObjC { - impl?.right(of: views) + func right(of view: PView) -> PinLayoutObjC { + _ = impl?.right(of: view) return self } - public func right(of view: UIView, aligned: VerticalAlign) -> PinLayoutObjC { - impl?.right(of: view, aligned: aligned) + func right(ofViews views: [PView]) -> PinLayoutObjC { + _ = impl?.right(of: views) return self } - public func right(ofViews views: [UIView], aligned: VerticalAlign) -> PinLayoutObjC { - impl?.right(of: views, aligned: aligned) + func right(of view: PView, aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.right(of: view, aligned: aligned) return self } - public func before(of view: UIView) -> PinLayoutObjC { - impl?.before(of: view) + func right(ofViews views: [PView], aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.right(of: views, aligned: aligned) return self } - public func before(ofViews views: [UIView]) -> PinLayoutObjC { - impl?.before(of: views) + func before(of view: PView) -> PinLayoutObjC { + _ = impl?.before(of: view) return self } - public func before(of view: UIView, aligned: VerticalAlign) -> PinLayoutObjC { - impl?.before(of: view, aligned: aligned) + func before(ofViews views: [PView]) -> PinLayoutObjC { + _ = impl?.before(of: views) return self } - public func before(ofViews views: [UIView], aligned: VerticalAlign) -> PinLayoutObjC { - impl?.before(of: views, aligned: aligned) + func before(of view: PView, aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.before(of: view, aligned: aligned) return self } - public func after(of view: UIView) -> PinLayoutObjC { - impl?.after(of: view) + func before(ofViews views: [PView], aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.before(of: views, aligned: aligned) return self } - public func after(ofViews views: [UIView]) -> PinLayoutObjC { - impl?.after(of: views) + func after(of view: PView) -> PinLayoutObjC { + _ = impl?.after(of: view) return self } - public func after(of view: UIView, aligned: VerticalAlign) -> PinLayoutObjC { - impl?.after(of: view, aligned: aligned) + func after(ofViews views: [PView]) -> PinLayoutObjC { + _ = impl?.after(of: views) return self } - public func after(ofViews views: [UIView], aligned: VerticalAlign) -> PinLayoutObjC { - impl?.after(of: views, aligned: aligned) + func after(of view: PView, aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.after(of: view, aligned: aligned) return self } - public func justify(_ align: HorizontalAlign) -> PinLayoutObjC { - impl?.justify(align) + func after(ofViews views: [PView], aligned: VerticalAlign) -> PinLayoutObjC { + _ = impl?.after(of: views, aligned: aligned) return self } - public func align(_ align: VerticalAlign) -> PinLayoutObjC { - impl?.align(align) + func justify(_ align: HorizontalAlign) -> PinLayoutObjC { + _ = impl?.justify(align) return self } - public func width(_ width: CGFloat) -> PinLayoutObjC { - impl?.width(width) + func align(_ align: VerticalAlign) -> PinLayoutObjC { + _ = impl?.align(align) return self } - public func width(percent: CGFloat) -> PinLayoutObjC { - impl?.width(percent%) + func width(_ width: CGFloat) -> PinLayoutObjC { + _ = impl?.width(width) return self } - public func width(of view: UIView) -> PinLayoutObjC { - impl?.width(of: view) + func width(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.width(percent%) return self } - public func minWidth(_ width: CGFloat) -> PinLayoutObjC { - impl?.minWidth(width) + func width(of view: PView) -> PinLayoutObjC { + _ = impl?.width(of: view) return self } - public func minWidth(percent: CGFloat) -> PinLayoutObjC { - impl?.minWidth(percent%) + func minWidth(_ width: CGFloat) -> PinLayoutObjC { + _ = impl?.minWidth(width) return self } - public func maxWidth(_ width: CGFloat) -> PinLayoutObjC { - impl?.maxWidth(width) + func minWidth(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.minWidth(percent%) return self } - public func maxWidth(percent: CGFloat) -> PinLayoutObjC { - impl?.maxWidth(percent%) + func maxWidth(_ width: CGFloat) -> PinLayoutObjC { + _ = impl?.maxWidth(width) return self } - public func height(_ height: CGFloat) -> PinLayoutObjC { - impl?.height(height) + func maxWidth(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.maxWidth(percent%) return self } - public func height(percent: CGFloat) -> PinLayoutObjC { - impl?.height(percent%) + func height(_ height: CGFloat) -> PinLayoutObjC { + _ = impl?.height(height) return self } - public func height(of view: UIView) -> PinLayoutObjC { - impl?.height(of: view) + func height(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.height(percent%) return self } - public func minHeight(_ height: CGFloat) -> PinLayoutObjC { - impl?.minHeight(height) + func height(of view: PView) -> PinLayoutObjC { + _ = impl?.height(of: view) return self } - public func minHeight(percent: CGFloat) -> PinLayoutObjC { - impl?.minHeight(percent%) + func minHeight(_ height: CGFloat) -> PinLayoutObjC { + _ = impl?.minHeight(height) return self } - public func maxHeight(_ height: CGFloat) -> PinLayoutObjC { - impl?.maxHeight(height) + func minHeight(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.minHeight(percent%) return self } - public func maxHeight(percent: CGFloat) -> PinLayoutObjC { - impl?.maxHeight(percent%) + func maxHeight(_ height: CGFloat) -> PinLayoutObjC { + _ = impl?.maxHeight(height) return self } - public func size(_ size: CGSize) -> PinLayoutObjC { - impl?.size(size) + func maxHeight(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.maxHeight(percent%) return self } - public func size(length: CGFloat) -> PinLayoutObjC { - impl?.size(length) + func size(_ size: CGSize) -> PinLayoutObjC { + _ = impl?.size(size) return self } - public func size(percent: CGFloat) -> PinLayoutObjC { - impl?.size(percent%) + func size(length: CGFloat) -> PinLayoutObjC { + _ = impl?.size(length) return self } - public func size(of view: UIView) -> PinLayoutObjC { - impl?.size(of: view) + func size(percent: CGFloat) -> PinLayoutObjC { + _ = impl?.size(percent%) return self } - public func aspectRatio(_ ratio: CGFloat) -> PinLayoutObjC { - impl?.aspectRatio(ratio) + func size(of view: PView) -> PinLayoutObjC { + _ = impl?.size(of: view) return self } - public func aspectRatio(of view: UIView) -> PinLayoutObjC { - impl?.aspectRatio(of: view) + func aspectRatio(_ ratio: CGFloat) -> PinLayoutObjC { + _ = impl?.aspectRatio(ratio) return self } - public func aspectRatio() -> PinLayoutObjC { - impl?.aspectRatio() + func aspectRatio(of view: PView) -> PinLayoutObjC { + _ = impl?.aspectRatio(of: view) return self } - - public func fitSize() -> PinLayoutObjC { - impl?.fitSize() + + #if os(iOS) || os(tvOS) + func aspectRatio() -> PinLayoutObjC { + _ = impl?.aspectRatio() return self } - - public func sizeToFit(_ fitType: Fit) -> PinLayoutObjC { + #endif + + func sizeToFit(_ fitType: Fit) -> PinLayoutObjC { let type: FitType switch fitType { case .width: type = .width @@ -623,79 +623,77 @@ import UIKit case .widthFlexible: type = .widthFlexible case .heightFlexible: type = .heightFlexible } - impl?.sizeToFit(type) + _ = impl?.sizeToFit(type) return self } - public func marginTop(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginTop(value) + func marginTop(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginTop(value) return self } - public func marginLeft(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginLeft(value) + func marginLeft(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginLeft(value) return self } - public func marginBottom(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginBottom(value) + func marginBottom(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginBottom(value) return self } - public func marginRight(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginRight(value) + func marginRight(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginRight(value) return self } - public func marginStart(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginStart(value) + func marginStart(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginStart(value) return self } - public func marginEnd(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginEnd(value) + func marginEnd(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginEnd(value) return self } - public func marginHorizontal(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginHorizontal(value) + func marginHorizontal(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginHorizontal(value) return self } - public func marginVertical(_ value: CGFloat) -> PinLayoutObjC { - impl?.marginVertical(value) + func marginVertical(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.marginVertical(value) return self } - public func margin(insets: UIEdgeInsets) -> PinLayoutObjC { - impl?.margin(insets) + func margin(insets: PEdgeInsets) -> PinLayoutObjC { + _ = impl?.margin(insets) return self } - public func margin(_ value: CGFloat) -> PinLayoutObjC { - impl?.margin(value) + func margin(_ value: CGFloat) -> PinLayoutObjC { + _ = impl?.margin(value) return self } - public func margin(vertical: CGFloat, horizontal: CGFloat) -> PinLayoutObjC { - impl?.margin(vertical, horizontal) + func margin(vertical: CGFloat, horizontal: CGFloat) -> PinLayoutObjC { + _ = impl?.margin(vertical, horizontal) return self } - public func margin(top: CGFloat, horizontal: CGFloat, bottom: CGFloat) -> PinLayoutObjC { - impl?.margin(top, horizontal, bottom) + func margin(top: CGFloat, horizontal: CGFloat, bottom: CGFloat) -> PinLayoutObjC { + _ = impl?.margin(top, horizontal, bottom) return self } - public func margin(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> PinLayoutObjC { - impl?.margin(top, left, bottom, right) + func margin(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> PinLayoutObjC { + _ = impl?.margin(top, left, bottom, right) return self } - public func pinEdges() -> PinLayoutObjC { - impl?.pinEdges() + func pinEdges() -> PinLayoutObjC { + _ = impl?.pinEdges() return self } } - -#endif diff --git a/Sources/UIView+PinLayout.swift b/Sources/UIView+PinLayout.swift index eca85485..c99c394b 100644 --- a/Sources/UIView+PinLayout.swift +++ b/Sources/UIView+PinLayout.swift @@ -27,5 +27,10 @@ public extension UIView { @objc public var edge: EdgeList { return EdgeListImpl(view: self) } + + // Expose PinLayout's objective-c interface. + @objc public var pinObjc: PinLayoutObjC { + return PinLayoutObjCImpl(view: self, keepTransform: true) + } } #endif From 01347f1c5c02e6f6aaa21232cafa704836cd99cd Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Fri, 25 May 2018 20:59:18 -0400 Subject: [PATCH 002/389] Update --- .../ios/PinLayout-iOS/TestObjectiveC.m | 2 +- build-ci.sh | 88 +++++++++---------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/TestProjects/cocoapods/ios/PinLayout-iOS/TestObjectiveC.m b/TestProjects/cocoapods/ios/PinLayout-iOS/TestObjectiveC.m index 636fb5fd..1491dd1a 100644 --- a/TestProjects/cocoapods/ios/PinLayout-iOS/TestObjectiveC.m +++ b/TestProjects/cocoapods/ios/PinLayout-iOS/TestObjectiveC.m @@ -54,7 +54,7 @@ - (void) layoutSubviews { [[[[[[logo.pinObjc top] left] width:100] aspectRatio] marginWithTop:topLayoutGuide + 10 horizontal:10 bottom:10] layout]; [[[[segmented.pinObjc rightOf:logo aligned:VerticalAlignTop] right] marginHorizontal:10] layout]; - [[[[[[textLabel.pinObjc belowOf:segmented aligned:HorizontalAlignLeft] widthOf:segmented] pinEdges] marginTop:10] fitSize] layout]; + [[[[[[textLabel.pinObjc belowOf:segmented aligned:HorizontalAlignLeft] widthOf:segmented] pinEdges] marginTop:10] sizeToFit:FitWidth] layout]; [[[[[separatorView.pinObjc belowOfViews:@[logo, textLabel] aligned:HorizontalAlignLeft] rightTo:segmented.edge.right] height:1] marginTop:10] layout]; } diff --git a/build-ci.sh b/build-ci.sh index 429830f0..3f858b41 100755 --- a/build-ci.sh +++ b/build-ci.sh @@ -8,65 +8,65 @@ rm -rf $DERIVED_DATA && echo "===============================" && echo "fastlane iOS travis" && echo "===============================" && -time bundle exec fastlane ios travis && +# time bundle exec fastlane ios travis && # echo "===============================" && # echo "fastlane macOS travis" && # echo "===============================" && -# #time bundle exec fastlane mac travis && +# time bundle exec fastlane mac travis && -# echo "===============================" && -# echo "iOS unit test" && -# echo "===============================" && -# time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS -derivedDataPath $DERIVED_DATA -sdk iphonesimulator11.3 \ -# -destination 'platform=iOS Simulator,name=iPhone 7 Plus,OS=11.3' \ -# -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.3' \ -# -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.2'\ -# | xcpretty && +echo "===============================" && +echo "iOS unit test" && +echo "===============================" && +time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS -derivedDataPath $DERIVED_DATA -sdk iphonesimulator11.3 \ + -destination 'platform=iOS Simulator,name=iPhone 7 Plus,OS=11.3' \ + -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.3' \ + -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.2'\ + | xcpretty && -# echo "===============================" && -# echo "macOS unit test" && -# echo "===============================" && -# time xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS -derivedDataPath $DERIVED_DATA -sdk macosx10.13 \ -# | xcpretty +echo "===============================" && +echo "macOS unit test" && +echo "===============================" && +time xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS -derivedDataPath $DERIVED_DATA -sdk macosx10.13 \ + | xcpretty -# echo "===============================" && -# echo " Cocoapods: iOS Empty project" && -# echo "===============================" && -# cd TestProjects/cocoapods/ios && -# rm -rf $DERIVED_DATA && -# pod install && -# time xcodebuild clean build -workspace PinLayout-iOS.xcworkspace -scheme PinLayout-iOS -sdk iphonesimulator11.3 -derivedDataPath $DERIVED_DATA \ -# -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.3' \ -# | xcpretty && -# cd ../../.. +echo "===============================" && +echo " Cocoapods: iOS Empty project" && +echo "===============================" && +cd TestProjects/cocoapods/ios && +rm -rf $DERIVED_DATA && +pod install && +time xcodebuild clean build -workspace PinLayout-iOS.xcworkspace -scheme PinLayout-iOS -sdk iphonesimulator11.3 -derivedDataPath $DERIVED_DATA \ + -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.3' \ + | xcpretty && +cd ../../.. -# echo "===============================" && -# echo " Cocoapods: macOS Empty project" && -# echo "===============================" && -# cd TestProjects/cocoapods/macos && -# rm -rf $DERIVED_DATA && -# pod install && -# time xcodebuild clean build -workspace PinLayout-macOS.xcworkspace -scheme PinLayout-macOS -sdk macosx10.13 -derivedDataPath $DERIVED_DATA \ -# | xcpretty && -# cd ../../.. +echo "===============================" && +echo " Cocoapods: macOS Empty project" && +echo "===============================" && +cd TestProjects/cocoapods/macos && +rm -rf $DERIVED_DATA && +pod install && +time xcodebuild clean build -workspace PinLayout-macOS.xcworkspace -scheme PinLayout-macOS -sdk macosx10.13 -derivedDataPath $DERIVED_DATA \ + | xcpretty && +cd ../../.. -# echo "===============================" && -# echo " Cocoapods: tvOS Empty project" && -# echo "===============================" && -# cd TestProjects/cocoapods/tvos && -# rm -rf $DERIVED_DATA && -# pod install && -# time xcodebuild clean build -workspace PinLayout-tvOS.xcworkspace -scheme PinLayout-tvOS -sdk appletvsimulator11.3 -derivedDataPath $DERIVED_DATA \ -# -destination 'platform=tvOS Simulator,name=Apple TV,OS=11.3' \ -# | xcpretty && -# cd ../../.. +echo "===============================" && +echo " Cocoapods: tvOS Empty project" && +echo "===============================" && +cd TestProjects/cocoapods/tvos && +rm -rf $DERIVED_DATA && +pod install && +time xcodebuild clean build -workspace PinLayout-tvOS.xcworkspace -scheme PinLayout-tvOS -sdk appletvsimulator11.3 -derivedDataPath $DERIVED_DATA \ + -destination 'platform=tvOS Simulator,name=Apple TV,OS=11.3' \ + | xcpretty && +cd ../../.. echo "===============================" && From 4c6d513af7cf2ec1c379797c81166c5cf9991865 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Fri, 25 May 2018 21:18:20 -0400 Subject: [PATCH 003/389] Update travis --- .../carthage/ios/PinLayout-Carthage-iOS/TestObjectiveC.m | 2 +- build-ci.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TestProjects/carthage/ios/PinLayout-Carthage-iOS/TestObjectiveC.m b/TestProjects/carthage/ios/PinLayout-Carthage-iOS/TestObjectiveC.m index 636fb5fd..1491dd1a 100644 --- a/TestProjects/carthage/ios/PinLayout-Carthage-iOS/TestObjectiveC.m +++ b/TestProjects/carthage/ios/PinLayout-Carthage-iOS/TestObjectiveC.m @@ -54,7 +54,7 @@ - (void) layoutSubviews { [[[[[[logo.pinObjc top] left] width:100] aspectRatio] marginWithTop:topLayoutGuide + 10 horizontal:10 bottom:10] layout]; [[[[segmented.pinObjc rightOf:logo aligned:VerticalAlignTop] right] marginHorizontal:10] layout]; - [[[[[[textLabel.pinObjc belowOf:segmented aligned:HorizontalAlignLeft] widthOf:segmented] pinEdges] marginTop:10] fitSize] layout]; + [[[[[[textLabel.pinObjc belowOf:segmented aligned:HorizontalAlignLeft] widthOf:segmented] pinEdges] marginTop:10] sizeToFit:FitWidth] layout]; [[[[[separatorView.pinObjc belowOfViews:@[logo, textLabel] aligned:HorizontalAlignLeft] rightTo:segmented.edge.right] height:1] marginTop:10] layout]; } diff --git a/build-ci.sh b/build-ci.sh index 3f858b41..7bf0b3ce 100755 --- a/build-ci.sh +++ b/build-ci.sh @@ -8,13 +8,13 @@ rm -rf $DERIVED_DATA && echo "===============================" && echo "fastlane iOS travis" && echo "===============================" && -# time bundle exec fastlane ios travis && +time bundle exec fastlane ios travis && # echo "===============================" && # echo "fastlane macOS travis" && # echo "===============================" && -# time bundle exec fastlane mac travis && +time bundle exec fastlane mac travis && echo "===============================" && From b2a59926fa7d3b46151b22c68b5a8422d7d36f26 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Sat, 26 May 2018 08:56:03 -0400 Subject: [PATCH 004/389] Update version to 1.7.4 --- CHANGELOG.md | 10 +++++++++- PinLayout.podspec | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe0a9bb2..cc252f36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,15 @@ # Change Log -## [1.7.3](https://github.com/layoutBox/FlexLayout/releases/tag/1.7.2) +## [1.7.4](https://github.com/layoutBox/FlexLayout/releases/tag/1.7.4) +Released on 2018-05-26 + +### Objective-C support for macOS and tvOS +Add the support of Objective-C to macOS and tvOS. + +Added by [Luc Dion](https://github.com/lucdion) in Pull Request [#138](https://github.com/mirego/PinLayout/pull/138) + +## [1.7.3](https://github.com/layoutBox/FlexLayout/releases/tag/1.7.3) Released on 2018-04-25 ### Add few missing Objective-C Interface properties and methods diff --git a/PinLayout.podspec b/PinLayout.podspec index a1d570cd..27ea861a 100644 --- a/PinLayout.podspec +++ b/PinLayout.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |spec| spec.name = "PinLayout" - spec.version = "1.7.3" + spec.version = "1.7.4" spec.summary = "Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. [iOS/macOS/tvOS]" spec.description = "Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS]" spec.homepage = "https://mirego.github.io/PinLayout/" From d395185f2ad1d4fe49c0e5b3c9e05a96d8c5d410 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Sat, 26 May 2018 09:11:57 -0400 Subject: [PATCH 005/389] Add objective-c CI tests app for macOS and tvOS. --- .gitignore | 7 ++- .../PinLayout-macOS.xcodeproj/project.pbxproj | 12 ++++ .../PinLayout-macOS-Bridging-Header.h | 4 ++ .../macos/PinLayout-macOS/TestObjectiveC.m | 41 +++++++++++++ .../PinLayout-tvOS.xcodeproj/project.pbxproj | 12 ++++ .../PinLayout-tvOS-Bridging-Header.h | 4 ++ .../tvos/PinLayout-tvOS/TestObjectiveC.m | 61 +++++++++++++++++++ 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 TestProjects/cocoapods/macos/PinLayout-macOS/PinLayout-macOS-Bridging-Header.h create mode 100644 TestProjects/cocoapods/macos/PinLayout-macOS/TestObjectiveC.m create mode 100644 TestProjects/cocoapods/tvos/PinLayout-tvOS/PinLayout-tvOS-Bridging-Header.h create mode 100644 TestProjects/cocoapods/tvos/PinLayout-tvOS/TestObjectiveC.m diff --git a/.gitignore b/.gitignore index 0c4e7350..2325e32c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,9 @@ TestProjects/cocoapods/macos/PinLayout-macOS.xcworkspace/ TestProjects/cocoapods/macos/Podfile.lock TestProjects/cocoapods/tvos/PinLayout-tvOS.xcworkspace/ TestProjects/cocoapods/tvos/Podfile.lock - TestProjects/carthage/ios/Cartfile.resolved -TestProjects/carthage/ios/Carthage/ \ No newline at end of file +TestProjects/carthage/ios/Carthage/ + +TestProjects/swift-package-manager + +Example/PinLayoutExampleMacOS \ No newline at end of file diff --git a/TestProjects/cocoapods/macos/PinLayout-macOS.xcodeproj/project.pbxproj b/TestProjects/cocoapods/macos/PinLayout-macOS.xcodeproj/project.pbxproj index f45370fa..953edf48 100644 --- a/TestProjects/cocoapods/macos/PinLayout-macOS.xcodeproj/project.pbxproj +++ b/TestProjects/cocoapods/macos/PinLayout-macOS.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 447D4B571EA571EC002FDFF4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 447D4B561EA571EC002FDFF4 /* Assets.xcassets */; }; D481169C663D06B9487BD94A /* Pods_PinLayout_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD1FED5769AD72F9C3BA80B4 /* Pods_PinLayout_macOS.framework */; }; DF47E42B2088F8B2008599A2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF47E42A2088F8B2008599A2 /* Main.storyboard */; }; + DFF222C520B9932600AC2A84 /* TestObjectiveC.m in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C420B9932600AC2A84 /* TestObjectiveC.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -22,6 +23,8 @@ 5ECB97E9B35D047EBF30646A /* Pods-PinLayout-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayout-macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-PinLayout-macOS/Pods-PinLayout-macOS.release.xcconfig"; sourceTree = ""; }; AD1FED5769AD72F9C3BA80B4 /* Pods_PinLayout_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PinLayout_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DF47E42A2088F8B2008599A2 /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + DFF222BF20B9920E00AC2A84 /* PinLayout-macOS-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PinLayout-macOS-Bridging-Header.h"; sourceTree = ""; }; + DFF222C420B9932600AC2A84 /* TestObjectiveC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestObjectiveC.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,6 +72,8 @@ 447D4B561EA571EC002FDFF4 /* Assets.xcassets */, 447D4B5B1EA571EC002FDFF4 /* Info.plist */, DF47E42A2088F8B2008599A2 /* Main.storyboard */, + DFF222C420B9932600AC2A84 /* TestObjectiveC.m */, + DFF222BF20B9920E00AC2A84 /* PinLayout-macOS-Bridging-Header.h */, ); path = "PinLayout-macOS"; sourceTree = ""; @@ -116,6 +121,7 @@ TargetAttributes = { 447D4B4E1EA571EC002FDFF4 = { CreatedOnToolsVersion = 8.3.1; + LastSwiftMigration = 0930; ProvisioningStyle = Automatic; }; }; @@ -195,6 +201,7 @@ buildActionMask = 2147483647; files = ( 447D4B531EA571EC002FDFF4 /* AppDelegate.swift in Sources */, + DFF222C520B9932600AC2A84 /* TestObjectiveC.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -298,12 +305,15 @@ baseConfigurationReference = 039104F30404DFF00E9EE3EC /* Pods-PinLayout-macOS.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "PinLayout-macOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.mirego.project.PinLayout-macOS"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "PinLayout-macOS/PinLayout-macOS-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; }; name = Debug; @@ -313,12 +323,14 @@ baseConfigurationReference = 5ECB97E9B35D047EBF30646A /* Pods-PinLayout-macOS.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "PinLayout-macOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.mirego.project.PinLayout-macOS"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "PinLayout-macOS/PinLayout-macOS-Bridging-Header.h"; SWIFT_VERSION = 3.0; }; name = Release; diff --git a/TestProjects/cocoapods/macos/PinLayout-macOS/PinLayout-macOS-Bridging-Header.h b/TestProjects/cocoapods/macos/PinLayout-macOS/PinLayout-macOS-Bridging-Header.h new file mode 100644 index 00000000..1b2cb5d6 --- /dev/null +++ b/TestProjects/cocoapods/macos/PinLayout-macOS/PinLayout-macOS-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/TestProjects/cocoapods/macos/PinLayout-macOS/TestObjectiveC.m b/TestProjects/cocoapods/macos/PinLayout-macOS/TestObjectiveC.m new file mode 100644 index 00000000..0b51decb --- /dev/null +++ b/TestProjects/cocoapods/macos/PinLayout-macOS/TestObjectiveC.m @@ -0,0 +1,41 @@ +// +// TestObjectiveC.m +// PinLayoutPodTester +// +// Created by DION, Luc (MTL) on 2017-10-12. +// Copyright Š 2017 Mirego. All rights reserved. +// + +#import + +@import AppKit; +@import PinLayout; + +@interface IntroObjectiveCView: NSView { +} +@end + +@implementation IntroObjectiveCView { + CGFloat topLayoutGuide; + NSImageView* logo; + NSView* separatorView; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + topLayoutGuide = 0; + + logo = [[NSImageView alloc] init]; + separatorView = [[NSView alloc] init]; + } + return self; +} + +- (void)layout { + [super layout]; + + [[[[[logo.pinObjc top] left] width:100] marginWithTop:topLayoutGuide + 10 horizontal:10 bottom:10] layout]; + [[[[separatorView.pinObjc belowOfViews:logo aligned:HorizontalAlignLeft] height:1] marginTop:10] layout]; +} + +@end diff --git a/TestProjects/cocoapods/tvos/PinLayout-tvOS.xcodeproj/project.pbxproj b/TestProjects/cocoapods/tvos/PinLayout-tvOS.xcodeproj/project.pbxproj index 6bef9549..954c6d02 100644 --- a/TestProjects/cocoapods/tvos/PinLayout-tvOS.xcodeproj/project.pbxproj +++ b/TestProjects/cocoapods/tvos/PinLayout-tvOS.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 448160371EA5A76A00FBA809 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 448160361EA5A76A00FBA809 /* AppDelegate.swift */; }; DF4C0F5A2088FBAA00B4C060 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF4C0F592088FBAA00B4C060 /* Main.storyboard */; }; DF4C0F5C2088FBC300B4C060 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF4C0F5B2088FBC300B4C060 /* ViewController.swift */; }; + DFF222C720B993A900AC2A84 /* TestObjectiveC.m in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C620B993A900AC2A84 /* TestObjectiveC.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -22,6 +23,8 @@ 779A6A4C5B9EC1AC279D6A24 /* libPods-PinLayout-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-PinLayout-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DF4C0F592088FBAA00B4C060 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; DF4C0F5B2088FBC300B4C060 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + DFF222BC20B991CF00AC2A84 /* PinLayout-tvOS-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PinLayout-tvOS-Bridging-Header.h"; sourceTree = ""; }; + DFF222C620B993A900AC2A84 /* TestObjectiveC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestObjectiveC.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -60,7 +63,9 @@ 448160361EA5A76A00FBA809 /* AppDelegate.swift */, DF4C0F592088FBAA00B4C060 /* Main.storyboard */, DF4C0F5B2088FBC300B4C060 /* ViewController.swift */, + DFF222C620B993A900AC2A84 /* TestObjectiveC.m */, 4481603F1EA5A76B00FBA809 /* Info.plist */, + DFF222BC20B991CF00AC2A84 /* PinLayout-tvOS-Bridging-Header.h */, ); path = "PinLayout-tvOS"; sourceTree = ""; @@ -115,6 +120,7 @@ TargetAttributes = { 448160321EA5A76A00FBA809 = { CreatedOnToolsVersion = 8.3.1; + LastSwiftMigration = 0930; ProvisioningStyle = Automatic; }; }; @@ -175,6 +181,7 @@ buildActionMask = 2147483647; files = ( DF4C0F5C2088FBC300B4C060 /* ViewController.swift in Sources */, + DFF222C720B993A900AC2A84 /* TestObjectiveC.m in Sources */, 448160371EA5A76A00FBA809 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -279,11 +286,14 @@ isa = XCBuildConfiguration; baseConfigurationReference = 3ACDA03AB2AD6F178CB4A934 /* Pods-PinLayout-tvOS.debug.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "PinLayout-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.mirego.project.PinLayout-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "PinLayout-tvOS/PinLayout-tvOS-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; }; name = Debug; @@ -292,11 +302,13 @@ isa = XCBuildConfiguration; baseConfigurationReference = 6D86E0FD61D49B5CC904E75C /* Pods-PinLayout-tvOS.release.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "PinLayout-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.mirego.project.PinLayout-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "PinLayout-tvOS/PinLayout-tvOS-Bridging-Header.h"; SWIFT_VERSION = 3.0; }; name = Release; diff --git a/TestProjects/cocoapods/tvos/PinLayout-tvOS/PinLayout-tvOS-Bridging-Header.h b/TestProjects/cocoapods/tvos/PinLayout-tvOS/PinLayout-tvOS-Bridging-Header.h new file mode 100644 index 00000000..1b2cb5d6 --- /dev/null +++ b/TestProjects/cocoapods/tvos/PinLayout-tvOS/PinLayout-tvOS-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/TestProjects/cocoapods/tvos/PinLayout-tvOS/TestObjectiveC.m b/TestProjects/cocoapods/tvos/PinLayout-tvOS/TestObjectiveC.m new file mode 100644 index 00000000..1491dd1a --- /dev/null +++ b/TestProjects/cocoapods/tvos/PinLayout-tvOS/TestObjectiveC.m @@ -0,0 +1,61 @@ +// +// TestObjectiveC.m +// PinLayoutPodTester +// +// Created by DION, Luc (MTL) on 2017-10-12. +// Copyright Š 2017 Mirego. All rights reserved. +// + +#import + +@import UIKit; +@import PinLayout; + +@interface IntroObjectiveCView: UIView { +} +@end + +@implementation IntroObjectiveCView { + CGFloat topLayoutGuide; + UIImageView* logo; + UISegmentedControl* segmented; + UILabel* textLabel; + UIView* separatorView; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + topLayoutGuide = 0; + self.backgroundColor = UIColor.whiteColor; + + logo = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"PinLayout-logo" inBundle:nil compatibleWithTraitCollection:nil]]; + [self addSubview:logo]; + + segmented = [[UISegmentedControl alloc] initWithItems: @[@"Intro", @"1", @"2"]]; + [self addSubview:segmented]; + + textLabel = [[UILabel alloc] init]; + textLabel.text = @"Swift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable.\n\nSwift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable."; + textLabel.font = [UIFont systemFontOfSize:14]; + textLabel.numberOfLines = 0; + textLabel.lineBreakMode = NSLineBreakByWordWrapping; + [self addSubview:textLabel]; + + separatorView = [[UIView alloc] init]; + separatorView.backgroundColor = UIColor.grayColor; + + [self addSubview:separatorView]; + } + return self; +} + +- (void) layoutSubviews { + [super layoutSubviews]; + + [[[[[[logo.pinObjc top] left] width:100] aspectRatio] marginWithTop:topLayoutGuide + 10 horizontal:10 bottom:10] layout]; + [[[[segmented.pinObjc rightOf:logo aligned:VerticalAlignTop] right] marginHorizontal:10] layout]; + [[[[[[textLabel.pinObjc belowOf:segmented aligned:HorizontalAlignLeft] widthOf:segmented] pinEdges] marginTop:10] sizeToFit:FitWidth] layout]; + [[[[[separatorView.pinObjc belowOfViews:@[logo, textLabel] aligned:HorizontalAlignLeft] rightTo:segmented.edge.right] height:1] marginTop:10] layout]; +} + +@end From df8c01032b34a913d04ac65a19d234fb24cfa3de Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Fri, 1 Jun 2018 08:45:20 -0400 Subject: [PATCH 006/389] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed4777cd..f4803bed 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@

+ @@ -15,12 +16,12 @@

-

+ From 666ba1a9cf088b98eaf848d65c8aa41b26f39729 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Sun, 27 May 2018 07:44:36 -0400 Subject: [PATCH 007/389] Initial commit --- Example/.swiftlint.yml | 1 + PinLayout.xcodeproj/project.pbxproj | 40 ++- .../contents.xcworkspacedata | 3 - Podfile.lock | 4 +- Sources/Filters.swift | 28 +++ Sources/Impl/PinLayoutImpl+Layouting.swift | 2 +- Sources/Impl/PinLayoutImpl+WrapContent.swift | 98 ++++++++ Sources/Impl/PinLayoutImpl.swift | 16 +- Sources/Impl/TypesImpl.swift | 41 ---- Sources/Pin.swift | 18 -- Sources/PinLayout.swift | 153 +----------- Sources/Types+Description.swift | 62 +++++ Sources/Types.swift | 229 ++++++++++++++++++ Sources/UIView+PinLayout.swift | 1 + Tests/Common/WrapContentSpec.swift | 216 +++++++++++++++++ 15 files changed, 679 insertions(+), 233 deletions(-) create mode 100644 Sources/Filters.swift create mode 100644 Sources/Impl/PinLayoutImpl+WrapContent.swift create mode 100644 Sources/Types+Description.swift create mode 100644 Sources/Types.swift create mode 100644 Tests/Common/WrapContentSpec.swift diff --git a/Example/.swiftlint.yml b/Example/.swiftlint.yml index 0df8a810..adee2693 100644 --- a/Example/.swiftlint.yml +++ b/Example/.swiftlint.yml @@ -24,3 +24,4 @@ disabled_rules: # rule identifiers to exclude from running excluded: # paths to ignore during linting. overridden by `included`. - Pods + - PinLayoutExampleMacOS \ No newline at end of file diff --git a/PinLayout.xcodeproj/project.pbxproj b/PinLayout.xcodeproj/project.pbxproj index 4dcefc0d..d8a6f080 100644 --- a/PinLayout.xcodeproj/project.pbxproj +++ b/PinLayout.xcodeproj/project.pbxproj @@ -47,9 +47,9 @@ 2482908C1E78CFFC00667D08 /* RelativePositionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */; }; 248E4C741F7A883800C0E7F7 /* AspectRatioTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */; }; 248E4C771F7A88D200C0E7F7 /* UIImage+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */; }; - 24949A2E1EF69474003643D3 /* PinLayout+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */; }; + 24949A2E1EF69474003643D3 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* Filters.swift */; }; 249EFE841E64FB4C00165E39 /* PinLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 249EFE7A1E64FB4C00165E39 /* PinLayout.framework */; }; - 24B02B091F2A713000C18179 /* PinLayout+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */; }; + 24B02B091F2A713000C18179 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* Filters.swift */; }; 24B02B0A1F2A713300C18179 /* PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */; }; 24D18D171F3B4381008129EF /* RTLSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D151F3B42E0008129EF /* RTLSpec.swift */; }; 24D18D241F3E37DD008129EF /* Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D231F3E37DD008129EF /* Pin.swift */; }; @@ -62,7 +62,7 @@ DF1A5D352084CFC100725EF5 /* NSView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */; }; DF1A5D362084CFC100725EF5 /* NSView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */; }; DF1A5D372084CFC200725EF5 /* NSView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */; }; - DF1A5D382084CFC600725EF5 /* PinLayout+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */; }; + DF1A5D382084CFC600725EF5 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* Filters.swift */; }; DF1A5D392084CFC600725EF5 /* Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D231F3E37DD008129EF /* Pin.swift */; }; DF1A5D3A2084CFC600725EF5 /* UIView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */; }; DF1A5D3B2084CFD600725EF5 /* PinLayoutImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6C61FC37C1C0054CADD /* PinLayoutImpl.swift */; }; @@ -106,6 +106,14 @@ DFF222B220B877F600AC2A84 /* PinLayoutObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277B1F8E958F00B1AD39 /* PinLayoutObjC.swift */; }; DFF222B320B877F800AC2A84 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; DFF222B420B877F900AC2A84 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; + DFF222C920B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */; }; + DFF222CA20B9994200AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */; }; + DFF222CB20B9994300AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */; }; + DFF222CD20B999BD00AC2A84 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CC20B999BD00AC2A84 /* Types.swift */; }; + DFF222CF20B99A6600AC2A84 /* Types+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CE20B99A6600AC2A84 /* Types+Description.swift */; }; + DFF222E320BACBBF00AC2A84 /* WrapContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */; }; + DFF222E420BACBC000AC2A84 /* WrapContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */; }; + DFF222E520BACBC000AC2A84 /* WrapContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */; }; DFF6F9C72084DCD3004F5AED /* PinLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244DF2F81EF46C500090508B /* PinLayout.framework */; }; DFF6F9CD2084E15A004F5AED /* BasicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C5011E75D88500073BEE /* BasicView.swift */; }; DFF6F9CE2084E15A004F5AED /* AdjustSizeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C4FF1E75D74000073BEE /* AdjustSizeSpec.swift */; }; @@ -188,7 +196,7 @@ 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativePositionSpec.swift; sourceTree = ""; }; 248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AspectRatioTests.swift; sourceTree = ""; }; 248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Color.swift"; sourceTree = ""; }; - 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PinLayout+Filters.swift"; sourceTree = ""; }; + 24949A2D1EF69474003643D3 /* Filters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Filters.swift; sourceTree = ""; }; 249EFE7A1E64FB4C00165E39 /* PinLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PinLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE831E64FB4C00165E39 /* PinLayoutTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PinLayoutTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE8A1E64FB4C00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Common/Info.plist; sourceTree = ""; }; @@ -216,6 +224,10 @@ DFB3ECB02061602E005F226B /* PinSafeArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PinSafeArea.swift; path = Impl/PinSafeArea.swift; sourceTree = ""; }; DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinLayout.swift; sourceTree = ""; }; DFCA5F1420111BCF00180CD7 /* UIScrollViewSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIScrollViewSpec.swift; sourceTree = ""; }; + DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "PinLayoutImpl+WrapContent.swift"; path = "Impl/PinLayoutImpl+WrapContent.swift"; sourceTree = ""; }; + DFF222CC20B999BD00AC2A84 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; + DFF222CE20B99A6600AC2A84 /* Types+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Types+Description.swift"; sourceTree = ""; }; + DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WrapContentSpec.swift; sourceTree = ""; }; DFF6F9C22084DCD3004F5AED /* PinLayoutTests-tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PinLayoutTests-tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -327,9 +339,10 @@ 249EFE7C1E64FB4C00165E39 /* Sources */ = { isa = PBXGroup; children = ( + 24949A2D1EF69474003643D3 /* Filters.swift */, DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */, - 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */, 24D18D231F3E37DD008129EF /* Pin.swift */, + DFF222CC20B999BD00AC2A84 /* Types.swift */, DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */, DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */, DFA06B031E8B38B300B6D5E7 /* Impl */, @@ -382,10 +395,12 @@ 2475B6C41FC37A900054CADD /* PinLayoutImpl+Layouting.swift */, 2475B6C91FC37C1C0054CADD /* PinLayoutImpl+Relative.swift */, 2475B6C81FC37C1C0054CADD /* PinLayoutImpl+Warning.swift */, + DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */, DFB3ECB02061602E005F226B /* PinSafeArea.swift */, 2475B6D21FC37CD40054CADD /* Coordinates.swift */, 243C620E1FC3834B0082C327 /* Percent.swift */, 2475B6CE1FC37C570054CADD /* TypesImpl.swift */, + DFF222CE20B99A6600AC2A84 /* Types+Description.swift */, 2475B6D01FC37C8C0054CADD /* UIView+LTR.swift */, ); name = Impl; @@ -407,6 +422,7 @@ 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */, 242E8DC11EED5982005935FB /* RelativePositionMultipleViewsSpec.swift */, 240F88BF1F0C1ED900280FC8 /* WarningSpec.swift */, + DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */, ); path = Common; sourceTree = ""; @@ -797,10 +813,11 @@ DF1A5D362084CFC100725EF5 /* NSView+PinLayout.swift in Sources */, 243C62041FC37F680082C327 /* PinLayoutImpl.swift in Sources */, 243C62071FC37F6C0082C327 /* PinLayoutImpl+Relative.swift in Sources */, + DFF222CB20B9994300AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, 243B12BC1FC393580072A9C3 /* Percent.swift in Sources */, DFB3ECB72062A937005F226B /* PinSafeArea.swift in Sources */, DF1A5D0420812DE100725EF5 /* UIView+PinLayout.swift in Sources */, - 24B02B091F2A713000C18179 /* PinLayout+Filters.swift in Sources */, + 24B02B091F2A713000C18179 /* Filters.swift in Sources */, 24B02B0A1F2A713300C18179 /* PinLayout.swift in Sources */, 243C620B1FC37F6C0082C327 /* UIView+LTR.swift in Sources */, 243C62091FC37F6C0082C327 /* Coordinates.swift in Sources */, @@ -816,11 +833,14 @@ files = ( 24D18D241F3E37DD008129EF /* Pin.swift in Sources */, 2475B6CA1FC37C1C0054CADD /* PinLayoutImpl.swift in Sources */, + DFF222CF20B99A6600AC2A84 /* Types+Description.swift in Sources */, 241A277E1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift in Sources */, DF1A5D372084CFC200725EF5 /* NSView+PinLayout.swift in Sources */, + DFF222CD20B999BD00AC2A84 /* Types.swift in Sources */, 243C620F1FC3834B0082C327 /* Percent.swift in Sources */, 2475B6CB1FC37C1C0054CADD /* PinLayoutImpl+Coordinates.swift in Sources */, 2475B6C51FC37A900054CADD /* PinLayoutImpl+Layouting.swift in Sources */, + DFF222C920B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, 2475B6CF1FC37C570054CADD /* TypesImpl.swift in Sources */, 2475B6D11FC37C8C0054CADD /* UIView+LTR.swift in Sources */, DFC97CA71E8A8F2C001545D5 /* PinLayout.swift in Sources */, @@ -828,7 +848,7 @@ DF1A5CBB208106A900725EF5 /* UIView+PinLayout.swift in Sources */, 2475B6D31FC37CD40054CADD /* Coordinates.swift in Sources */, 241A277D1F8E958F00B1AD39 /* PinLayoutObjC.swift in Sources */, - 24949A2E1EF69474003643D3 /* PinLayout+Filters.swift in Sources */, + 24949A2E1EF69474003643D3 /* Filters.swift in Sources */, DFB3ECB12061602F005F226B /* PinSafeArea.swift in Sources */, 2475B6CD1FC37C1C0054CADD /* PinLayoutImpl+Relative.swift in Sources */, ); @@ -838,6 +858,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DFF222E320BACBBF00AC2A84 /* WrapContentSpec.swift in Sources */, 240F88BE1F0C066800280FC8 /* JustifyAlignSpec.swift in Sources */, 2469C5001E75D74000073BEE /* AdjustSizeSpec.swift in Sources */, 243B12C81FC3D06F0072A9C3 /* LayoutMethodSpec.swift in Sources */, @@ -872,6 +893,7 @@ DFED154F20852F7E009EF9A7 /* BasicView.swift in Sources */, DFB288AF20854127001F9588 /* PinPointCoordinatesSpec.swift in Sources */, DFB288A320853E82001F9588 /* JustifyAlignSpec.swift in Sources */, + DFF222E420BACBC000AC2A84 /* WrapContentSpec.swift in Sources */, DFED15532085349A009EF9A7 /* RectNimbleMatcher.swift in Sources */, DFB288B12085419B001F9588 /* RelativePositionSpec.swift in Sources */, DFB288B2208541B7001F9588 /* RelativePositionMultipleViewsSpec.swift in Sources */, @@ -897,11 +919,12 @@ DF1A5D412084CFD600725EF5 /* Coordinates.swift in Sources */, DF1A5D422084CFD600725EF5 /* Percent.swift in Sources */, DF1A5D3E2084CFD600725EF5 /* PinLayoutImpl+Relative.swift in Sources */, + DFF222CA20B9994200AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, DF1A5D442084CFD600725EF5 /* UIView+LTR.swift in Sources */, DF1A5D352084CFC100725EF5 /* NSView+PinLayout.swift in Sources */, DF1A5D3A2084CFC600725EF5 /* UIView+PinLayout.swift in Sources */, DFED155120853085009EF9A7 /* PinLayout.swift in Sources */, - DF1A5D382084CFC600725EF5 /* PinLayout+Filters.swift in Sources */, + DF1A5D382084CFC600725EF5 /* Filters.swift in Sources */, DF1A5D392084CFC600725EF5 /* Pin.swift in Sources */, DF1A5D3D2084CFD600725EF5 /* PinLayoutImpl+Layouting.swift in Sources */, DF1A5D3C2084CFD600725EF5 /* PinLayoutImpl+Coordinates.swift in Sources */, @@ -914,6 +937,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DFF222E520BACBC000AC2A84 /* WrapContentSpec.swift in Sources */, DFF6F9DC2084E15A004F5AED /* RelativePositionMultipleViewsSpec.swift in Sources */, DFABC023208781EE00CB6494 /* Types+UIKit.swift in Sources */, DFF6F9DB2084E15A004F5AED /* RelativePositionSpec.swift in Sources */, diff --git a/PinLayout.xcworkspace/contents.xcworkspacedata b/PinLayout.xcworkspace/contents.xcworkspacedata index 3be1104b..16192094 100644 --- a/PinLayout.xcworkspace/contents.xcworkspacedata +++ b/PinLayout.xcworkspace/contents.xcworkspacedata @@ -10,7 +10,4 @@ - - diff --git a/Podfile.lock b/Podfile.lock index d8eb96e6..1c98d1a9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,6 @@ PODS: - Nimble (7.0.3) - - PinLayout (1.7.3) + - PinLayout (1.7.4) - Quick (1.2.0) - Reveal-SDK (10) - SwiftLint (0.25.1) @@ -25,7 +25,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Nimble: 7f5a9c447a33002645a071bddafbfb24ea70e0ac - PinLayout: 04488e8fc8d19b59760bdf99a16deff7bfac422d + PinLayout: e20545b1fd5110133e0b03bed61f196161af8b36 Quick: 58d203b1c5e27fff7229c4c1ae445ad7069a7a08 Reveal-SDK: 7869ddf1f902cabbb07a1f0dd06bd25861a126f7 SwiftLint: ce933681be10c3266e82576dad676fa815a602e9 diff --git a/Sources/Filters.swift b/Sources/Filters.swift new file mode 100644 index 00000000..400ca72e --- /dev/null +++ b/Sources/Filters.swift @@ -0,0 +1,28 @@ +// Copyright (c) 2017 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if os(iOS) || os(tvOS) +import UIKit + +// Filter out all hidden views (isHidden is true or alpha is 0) +public func visible(_ views: [UIView]) -> [UIView] { + return views.filter({ !$0.isHidden && $0.alpha > 0 }) +} + +#endif diff --git a/Sources/Impl/PinLayoutImpl+Layouting.swift b/Sources/Impl/PinLayoutImpl+Layouting.swift index 405bae96..367a4dc0 100644 --- a/Sources/Impl/PinLayoutImpl+Layouting.swift +++ b/Sources/Impl/PinLayoutImpl+Layouting.swift @@ -23,7 +23,7 @@ import AppKit #endif -// MARK - UIView's frame computation methods +// MARK: UIView's frame computation methods extension PinLayoutImpl { public func layout() { apply() diff --git a/Sources/Impl/PinLayoutImpl+WrapContent.swift b/Sources/Impl/PinLayoutImpl+WrapContent.swift new file mode 100644 index 00000000..06d2a928 --- /dev/null +++ b/Sources/Impl/PinLayoutImpl+WrapContent.swift @@ -0,0 +1,98 @@ +// Copyright (c) 2018 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if os(iOS) || os(tvOS) +import UIKit +#else +import AppKit +#endif + +extension PinLayoutImpl { + func wrapContent() -> PinLayout { + return wrapContent(.all, padding: .zero, { return "wrapContent()" }) + } + + func wrapContent(_ type: WrapType) -> PinLayout { + return wrapContent(type, padding: .zero, { return "wrapContent(\(type.description)" }) + } + + @discardableResult + private func wrapContent(_ type: WrapType, padding: PPadding, _ context: Context) -> PinLayout { + let subviews = view.subviews + guard !subviews.isEmpty else { return self } + let firstViewFrame = subviews[0].frame + var minX = firstViewFrame.minX + var maxX = firstViewFrame.maxX + var minY = firstViewFrame.minY + var maxY = firstViewFrame.maxY + + for var i in 1.. maxX { + maxX = frame.maxX + } + if frame.minY < minY { + minY = frame.minY + } + if frame.maxY > maxY { + maxY = frame.maxY + } + } + + var offsetDx: CGFloat = 0 + var offsetDy: CGFloat = 0 + + if type == .all || type == .width { + let contentWidth = maxX - minX + if contentWidth >= 0 { + setWidth(contentWidth, context) + } + + offsetDx = -minX +// let contentWidth = view.subviews.max(by: { subview1, subview2 in +// subview1.frame.maxX < subview2.frame.maxX +// })?.frame.maxX ?? 0 + } + + if type == .all || type == .height { + let contentHeight = maxY - minY + if contentHeight >= 0 { + setHeight(contentHeight, context) + } + + offsetDy = -minY +// let contentHeight = view.subviews.max(by: { subview1, subview2 in +// subview1.frame.maxY < subview2.frame.maxY +// })?.frame.maxY ?? 0 + } + + if offsetDx != 0 || offsetDy != 0 { + subviews.forEach { (view) in + let viewRect = Coordinates.getViewRect(view, keepTransform: keepTransform) + let newRect = viewRect.offsetBy(dx: offsetDx, dy: offsetDy) + Coordinates.setViewRect(view, toRect: newRect, keepTransform: keepTransform) + } + } + + return self + } +} diff --git a/Sources/Impl/PinLayoutImpl.swift b/Sources/Impl/PinLayoutImpl.swift index ae01e5e9..2d07b3b8 100644 --- a/Sources/Impl/PinLayoutImpl.swift +++ b/Sources/Impl/PinLayoutImpl.swift @@ -728,14 +728,8 @@ class PinLayoutImpl: PinLayout { func context() -> String { return "size(of \(viewDescription(view)))" } return setSize(view.bounds.size, context) } - -// func wrapSubViews() -> PinLayout { -// let neededWidth = view.subviews.max(by: { subview1, subview2 in subview1.frame.maxX < subview2.frame.maxX })?.frame.maxX ?? 0 -// let neededHeight = view.subviews.max(by: { subview1, subview2 in subview1.frame.maxY < subview2.frame.maxY })?.frame.maxY ?? 0 -// -// return setSize(CGSize(width: neededWidth, height: neededHeight), { return "wrapSubViews()" }) -// } - + + @discardableResult func aspectRatio(_ ratio: CGFloat) -> PinLayout { return setAspectRatio(ratio, context: { "aspectRatio(\(ratio))" }) } @@ -761,7 +755,7 @@ class PinLayoutImpl: PinLayout { #endif func sizeToFit(_ fitType: FitType) -> PinLayout { - return setFitSize(fitType: fitType, { return "sizeToFit(\(fitType.name))" }) + return setFitSize(fitType: fitType, { return "sizeToFit(\(fitType.description))" }) } #if os(iOS) || os(tvOS) @@ -992,7 +986,7 @@ extension PinLayoutImpl { } else if fitType != nil && legacyFitSize { warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with fitSize().") } else if let currentFitType = self.fitType, currentFitType != fitType { - warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(currentFitType.name)).") + warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(currentFitType.description)).") } else { if fitType == nil { legacyFitSize = true @@ -1006,7 +1000,7 @@ extension PinLayoutImpl { @discardableResult internal func setAspectRatio(_ ratio: CGFloat, context: Context) -> PinLayout { if let fitType = fitType { - warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(fitType.name)).") + warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(fitType.description)).") } else if legacyFitSize { warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with fitSize().") } else if ratio <= 0 { diff --git a/Sources/Impl/TypesImpl.swift b/Sources/Impl/TypesImpl.swift index eb1060d2..94526a7a 100644 --- a/Sources/Impl/TypesImpl.swift +++ b/Sources/Impl/TypesImpl.swift @@ -28,28 +28,6 @@ import Foundation typealias Context = () -> String typealias Size = (width: CGFloat?, height: CGFloat?) -extension HorizontalAlign { - var description: String { - switch self { - case .left: return "left" - case .center: return "center" - case .right: return "right" - case .start: return "start" - case .end: return "end" - } - } -} - -extension VerticalAlign { - var description: String { - switch self { - case .top: return "top" - case .center: return "center" - case .bottom: return "bottom" - } - } -} - class EdgeListImpl: EdgeList { internal let view: PView @@ -185,26 +163,7 @@ class AnchorImpl: Anchor { } } -extension CGFloat { - public var description: String { - if self.truncatingRemainder(dividingBy: 1) == 0.0 { - return "\(Int(self))" - } else { - return "\(self)" - } - } -} - internal extension FitType { - var name: String { - switch self { - case .width: return ".width" - case .height: return ".height" - case .widthFlexible: return ".widthFlexible" - case .heightFlexible: return ".heightFlexible" - } - } - var isFlexible: Bool { return self == .widthFlexible || self == .heightFlexible } diff --git a/Sources/Pin.swift b/Sources/Pin.swift index 30a33003..ca74db56 100644 --- a/Sources/Pin.swift +++ b/Sources/Pin.swift @@ -19,24 +19,6 @@ import Foundation -@objc public enum LayoutDirection: Int { - case auto - case ltr - case rtl -} - -/// Control how PinLayout will calls `UIView.safeAreaInsetsDidChange` when the `UIView.pin.safeArea` change. -/// This support is usefull only on iOS 8/9/10. On iOS 11 `UIView.safeAreaInsetsDidChange` is supported -/// natively so this settings have no impact. -@objc public enum PinSafeAreaInsetsDidChangeMode: Int { - /// PinLayout won't call `UIView.safeAreaInsetsDidChange` on iOS 8/9/10. - case disable - /// PinLayout will call `UIView.safeAreaInsetsDidChange` only if the UIView implement the PinSafeAreaInsetsUpdate protocol. - case optIn - /// PinLayout will automatically calls `UIView.safeAreaInsetsDidChange` if the view has implemented this method. - case always -} - @objc public class Pin: NSObject { @objc public static var layoutDirection = LayoutDirection.ltr diff --git a/Sources/PinLayout.swift b/Sources/PinLayout.swift index e456a11b..9a659ad9 100644 --- a/Sources/PinLayout.swift +++ b/Sources/PinLayout.swift @@ -23,85 +23,6 @@ import UIKit import AppKit #endif -/* - UIView's anchors point - ====================== - - topLeft topCenter topRight - o-------------o--------------o - | | - | | - | | - | | - | | - | center | - centerLeft o o o centerRight - | | - | | - | | - | | - | | - | | - o-------------o--------------o - bottomLeft bottomCenter bottomLeft - - */ - -/// UIViews's anchor definition -@objc public protocol Anchor { -} - -/// UIViews's list of anchors. -@objc public protocol AnchorList { - var topLeft: Anchor { get } - var topCenter: Anchor { get } - var topRight: Anchor { get } - var centerLeft: Anchor { get } - var center: Anchor { get } - var centerRight: Anchor { get } - var bottomLeft: Anchor { get } - var bottomCenter: Anchor { get } - var bottomRight: Anchor { get } - - // RTL support - var topStart: Anchor { get } - var topEnd: Anchor { get } - var centerStart: Anchor { get } - var centerEnd: Anchor { get } - var bottomStart: Anchor { get } - var bottomEnd: Anchor { get } -} - -/* - UIView's Edges - ====================== - top - +-----------------+ - | | - | | - | hCenter | - left | + | right - | vCenter | - | | - | | - +-----------------+ - bottom -*/ - -/// UIViews's list of edges -@objc public protocol EdgeList { - var top: VerticalEdge { get } - var vCenter: VerticalEdge { get } - var bottom: VerticalEdge { get } - var left: HorizontalEdge { get } - var hCenter: HorizontalEdge { get } - var right: HorizontalEdge { get } - - // RTL support - var start: HorizontalEdge { get } - var end: HorizontalEdge { get } -} - /// PinLayout interface public protocol PinLayout { @@ -387,8 +308,10 @@ public protocol PinLayout { @discardableResult func size(of view: NSView) -> PinLayout #endif - // @discardableResult func wrapSubViews() -> PinLayout - // @discardableResult func wrapSubViews(insets: UIEdgeInsets) -> PinLayout + @discardableResult func wrapContent() -> PinLayout + @discardableResult func wrapContent(_ type: WrapType) -> PinLayout + @discardableResult func wrapContent(padding: PPadding) -> PinLayout + @discardableResult func wrapContent(_ type: WrapType, padding: PPadding) -> PinLayout /** Set the view aspect ratio. @@ -620,71 +543,3 @@ public protocol PinLayout { */ func layout() } - -/// Horizontal alignment used with relative positionning methods: above(of relativeView:, aligned:), below(of relativeView:, aligned:) -/// -/// - left: left aligned -/// - center: center aligned -/// - right: right aligned -@objc public enum HorizontalAlign: Int { - case left - case center - case right - - // RTL support - case start - case end -} - -/// Vertical alignment used with relative positionning methods: left(of relativeView:, aligned:), right(of relativeView:, aligned:) -/// -/// - top: top aligned -/// - center: center aligned -/// - bottom: bottom aligned -@objc public enum VerticalAlign: Int { - case top - case center - case bottom -} - -/// UIView's horizontal edges (left/right) definition -@objc public protocol HorizontalEdge { -} - -/// UIView's vertical edges (top/bottom) definition -@objc public protocol VerticalEdge { -} - -public enum FitType { - /** - **Adjust the view's height** based on the reference width. - * If properties related to the width have been pinned (e.g: width, left & right, margins), - the **reference width will be determined by these properties**, else the **current view's width** - will be used. - * The resulting width will always **match the reference width**. - */ - case width - /** - **Adjust the view's width** based on the reference height. - * If properties related to the height have been pinned (e.g: height, top & bottom, margins), - the reference height will be determined by these properties, else the **current view's height** - will be used. - * The resulting height will always **match the reference height*. - */ - case height - - /** - Similar to `.width`, except that PinLayout won't constrain the resulting width to - match the reference width. The resulting width may be smaller of bigger depending on the view's - sizeThatFits(..) method result. For example a single line UILabel may returns a smaller width if its - string is smaller than the reference width. - */ - case widthFlexible - /** - Similar to `.height`, except that PinLayout won't constrain the resulting height to - match the reference height. The resulting height may be smaller of bigger depending on the view's - sizeThatFits(..) method result. - */ - case heightFlexible -} - diff --git a/Sources/Types+Description.swift b/Sources/Types+Description.swift new file mode 100644 index 00000000..28946b2a --- /dev/null +++ b/Sources/Types+Description.swift @@ -0,0 +1,62 @@ +// +// Types+Description.swift +// PinLayout-iOS +// +// Created by Luc Dion on 2018-05-26. +// Copyright Š 2018 mcswiftlayyout.mirego.com. All rights reserved. +// + +import Foundation + +extension HorizontalAlign { + var description: String { + switch self { + case .left: return "left" + case .center: return "center" + case .right: return "right" + case .start: return "start" + case .end: return "end" + } + } +} + +extension VerticalAlign { + var description: String { + switch self { + case .top: return "top" + case .center: return "center" + case .bottom: return "bottom" + } + } +} + +extension CGFloat { + public var description: String { + if self.truncatingRemainder(dividingBy: 1) == 0.0 { + return "\(Int(self))" + } else { + return "\(self)" + } + } +} + +extension FitType { + var description: String { + switch self { + case .width: return ".width" + case .height: return ".height" + case .widthFlexible: return ".widthFlexible" + case .heightFlexible: return ".heightFlexible" + } + } +} + +extension WrapType { + var description: String { + switch self { + case .all: return ".all" + case .width: return ".width" + case .height: return ".height" + } + } +} diff --git a/Sources/Types.swift b/Sources/Types.swift new file mode 100644 index 00000000..32f691c3 --- /dev/null +++ b/Sources/Types.swift @@ -0,0 +1,229 @@ +// Copyright (c) 2018 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + + +/* + UIView's anchors point + ====================== + + topLeft topCenter topRight + o-------------o--------------o + | | + | | + | | + | | + | | + | center | + centerLeft o o o centerRight + | | + | | + | | + | | + | | + | | + o-------------o--------------o + bottomLeft bottomCenter bottomLeft + + */ + +/// UIViews's anchor definition +@objc public protocol Anchor { +} + +/// UIViews's list of anchors. +@objc public protocol AnchorList { + var topLeft: Anchor { get } + var topCenter: Anchor { get } + var topRight: Anchor { get } + var centerLeft: Anchor { get } + var center: Anchor { get } + var centerRight: Anchor { get } + var bottomLeft: Anchor { get } + var bottomCenter: Anchor { get } + var bottomRight: Anchor { get } + + // RTL support + var topStart: Anchor { get } + var topEnd: Anchor { get } + var centerStart: Anchor { get } + var centerEnd: Anchor { get } + var bottomStart: Anchor { get } + var bottomEnd: Anchor { get } +} + +/* + UIView's Edges + ====================== + top + +-----------------+ + | | + | | + | hCenter | + left | + | right + | vCenter | + | | + | | + +-----------------+ + bottom + */ + +/// UIViews's list of edges +@objc public protocol EdgeList { + var top: VerticalEdge { get } + var vCenter: VerticalEdge { get } + var bottom: VerticalEdge { get } + var left: HorizontalEdge { get } + var hCenter: HorizontalEdge { get } + var right: HorizontalEdge { get } + + // RTL support + var start: HorizontalEdge { get } + var end: HorizontalEdge { get } +} + +/// Horizontal alignment used with relative positionning methods: above(of relativeView:, aligned:), below(of relativeView:, aligned:) +/// +/// - left: left aligned +/// - center: center aligned +/// - right: right aligned +@objc public enum HorizontalAlign: Int { + case left + case center + case right + + // RTL support + case start + case end +} + +/// Vertical alignment used with relative positionning methods: left(of relativeView:, aligned:), right(of relativeView:, aligned:) +/// +/// - top: top aligned +/// - center: center aligned +/// - bottom: bottom aligned +@objc public enum VerticalAlign: Int { + case top + case center + case bottom +} + +/// UIView's horizontal edges (left/right) definition +@objc public protocol HorizontalEdge { +} + +/// UIView's vertical edges (top/bottom) definition +@objc public protocol VerticalEdge { +} + +public enum FitType { + /** + **Adjust the view's height** based on the reference width. + * If properties related to the width have been pinned (e.g: width, left & right, margins), + the **reference width will be determined by these properties**, else the **current view's width** + will be used. + * The resulting width will always **match the reference width**. + */ + case width + /** + **Adjust the view's width** based on the reference height. + * If properties related to the height have been pinned (e.g: height, top & bottom, margins), + the reference height will be determined by these properties, else the **current view's height** + will be used. + * The resulting height will always **match the reference height*. + */ + case height + + /** + Similar to `.width`, except that PinLayout won't constrain the resulting width to + match the reference width. The resulting width may be smaller of bigger depending on the view's + sizeThatFits(..) method result. For example a single line UILabel may returns a smaller width if its + string is smaller than the reference width. + */ + case widthFlexible + /** + Similar to `.height`, except that PinLayout won't constrain the resulting height to + match the reference height. The resulting height may be smaller of bigger depending on the view's + sizeThatFits(..) method result. + */ + case heightFlexible +} + +public enum WrapType { + /** + */ + case all + /** + */ + case width + /** + */ + case height +} + +public struct PPadding { + let top: CGFloat + let left: CGFloat + let bottom: CGFloat + let right: CGFloat + + static var zero: PPadding { + return PPadding(0) + } + + init(_ all: CGFloat) { + top = all + left = all + bottom = all + right = all + } + + init(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) { + self.top = top + self.left = left + self.bottom = bottom + self.right = right + } + + init(h: CGFloat, v: CGFloat) { + top = v + left = h + bottom = v + right = h + } +} + +@objc public enum LayoutDirection: Int { + case auto + case ltr + case rtl +} + +/// Control how PinLayout will calls `UIView.safeAreaInsetsDidChange` when the `UIView.pin.safeArea` change. +/// This support is usefull only on iOS 8/9/10. On iOS 11 `UIView.safeAreaInsetsDidChange` is supported +/// natively so this settings have no impact. +@objc public enum PinSafeAreaInsetsDidChangeMode: Int { + /// PinLayout won't call `UIView.safeAreaInsetsDidChange` on iOS 8/9/10. + case disable + /// PinLayout will call `UIView.safeAreaInsetsDidChange` only if the UIView implement the PinSafeAreaInsetsUpdate protocol. + case optIn + /// PinLayout will automatically calls `UIView.safeAreaInsetsDidChange` if the view has implemented this method. + case always +} diff --git a/Sources/UIView+PinLayout.swift b/Sources/UIView+PinLayout.swift index c99c394b..7ac26804 100644 --- a/Sources/UIView+PinLayout.swift +++ b/Sources/UIView+PinLayout.swift @@ -33,4 +33,5 @@ public extension UIView { return PinLayoutObjCImpl(view: self, keepTransform: true) } } + #endif diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift new file mode 100644 index 00000000..e877d8b1 --- /dev/null +++ b/Tests/Common/WrapContentSpec.swift @@ -0,0 +1,216 @@ +// Copyright (c) 2018 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Quick +import Nimble +import PinLayout + +class WrapContentSpec: QuickSpec { + override func spec() { + var viewController: PViewController! + var rootView: BasicView! + + /* + root + | + - aView + | | + | |- aViewChild + |- aViewChild2 + |- aViewChild3 + */ + var aView: BasicView! + var aViewChild: BasicView! + var aViewChild2: BasicView! + var aViewChild3: BasicView! + + beforeSuite { + _pinlayoutSetUnitTest(displayScale: 2) + } + + beforeEach { + Pin.lastWarningText = nil + + viewController = PViewController() + viewController.view = BasicView() + + rootView = BasicView() + viewController.view.addSubview(rootView) + + aView = BasicView() + aView.sizeThatFitsExpectedArea = 40 * 40 + rootView.addSubview(aView) + + aViewChild = BasicView() + aView.addSubview(aViewChild) + + aViewChild2 = BasicView() + aView.addSubview(aViewChild2) + + aViewChild3 = BasicView() + aView.addSubview(aViewChild3) + + rootView.frame = CGRect(x: 0, y: 100, width: 400, height: 400) + } + + describe("wrapContent") { + it("wrap and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.all) should have the same result") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.all) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.width) + wrapContent(.height) should have the same result") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.width) + aView.pin.wrapContent(.height) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.all) and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.all) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.width) and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.width) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 120.0, width: 60.0, height: 60.0))) + } + it("wrapContent(.height) and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.height) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 0.0, width: 60.0, height: 60.0))) + } + it("wrap and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 180, y: 140, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 220, y: 180, width: 60, height: 60) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 120.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 20.0, y: 20.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 60.0, y: 60.0, width: 60.0, height: 60.0))) + } + + it("wrap when views are of size zero") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 0, height: 0) + aViewChild2.frame = CGRect(x: 180, y: 140, width: 0, height: 0) + aViewChild3.frame = CGRect(x: 220, y: 180, width: 0, height: 0) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 20.0, y: 20.0, width: 0.0, height: 0.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 60.0, y: 60.0, width: 0.0, height: 0.0))) + } + + it("wrap with subviews with negative position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: -40, y: -40, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 350, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 350, y: -100, width: 60, height: 60) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 450.0, height: 280.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 60.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 390.0, y: 220.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 390.0, y: 0.0, width: 60.0, height: 60.0))) + } + it("wrap and update subviews position") { + + } + it("wrap and update subviews position") { + // warning + aView.pin.wrapContent().width(20) + } + + it("wrap and update subviews position") { + // warning + aView.pin.width(20).wrapContent() + } + + it("wrap and update subviews position") { + // warning + aView.pin.height(20).wrapContent() + } + } + } +} From 2de27085f715c578f131c343632cbc4ed60e0b91 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Fri, 1 Jun 2018 18:45:19 -0400 Subject: [PATCH 008/389] Initial commit --- .gitignore | 3 +- README.md | 48 ++++- Sources/Impl/PinLayoutImpl+WrapContent.swift | 37 ++-- Sources/PinLayout+Filters.swift | 28 --- Sources/PinLayout.swift | 42 ++++- Sources/Types+Description.swift | 4 +- Sources/Types.swift | 45 +---- Tests/Common/WrapContentSpec.swift | 188 +++++++++++++++++-- 8 files changed, 294 insertions(+), 101 deletions(-) delete mode 100644 Sources/PinLayout+Filters.swift diff --git a/.gitignore b/.gitignore index 2325e32c..491ff75e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,10 @@ TestProjects/cocoapods/macos/PinLayout-macOS.xcworkspace/ TestProjects/cocoapods/macos/Podfile.lock TestProjects/cocoapods/tvos/PinLayout-tvOS.xcworkspace/ TestProjects/cocoapods/tvos/Podfile.lock + TestProjects/carthage/ios/Cartfile.resolved TestProjects/carthage/ios/Carthage/ TestProjects/swift-package-manager -Example/PinLayoutExampleMacOS \ No newline at end of file +Example/PinLayoutExampleMacOS diff --git a/README.md b/README.md index f4803bed..9c7fd543 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * Swift 3.2+ / Swift 4.0 / Objective-C ### Recent features +* :star: Add methods `wrapConten(...)` that adjust the view's width & height to wrap all its subviews. See [wrapContent](#wrapCcontent) for more information. + * :star: PinLayout now support macOS. See [macOS Support](#macos_support) for more information. * :star: PinLayout expose the `safeAreaInsets` through [`UIView.pin.safeArea`](#safeAreaInsets), this property support not only iOS 11, but is also backward compatible for earlier iOS releases (7/8/9/10). See [safeAreaInsets support](#safeAreaInsets) for more information. @@ -61,6 +63,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * [Aspect Ratio](#aspect_ratio) * [Margins](#margins) * [safeAreaInsets support](#safeAreaInsets) + * [WrapContent](#wrapCcontent) * [justify, align](#justify_align) * [UIView's transforms](#uiview_transform) * [Warnings](#warnings) @@ -1134,8 +1137,51 @@ This example runs perfectly on a iPhone X (iOS 11), but it also runs on any devi
+ +## WrapContent - +The following methods are useful to adjust the view's width and/or height to wrap all its subviews. These method also adjust subviews position to create a tight wrap. + +**Methods:** + +* **`wrapContent()`** +Bla. +* **`wrapContent(padding: CGFloat)`** +Bla. +* **`wrapContent(padding: UIEdgeInsets)`** +Bla. +* **`wrapContent(:WrapType)`** +Bla. +* **`wrapContent(:WrapType, padding: CGFloat)`** +Bla. +* **`wrapContent(:WrapType, padding: UIEdgeInsets)`** +Bla. + +TABLE SHOWING DIFFERENCES!!! + +###### Usage examples: +```swift + view.pin.wrapContent().center() // wrap all subviews and centered the view inside its parent. + view.pin.wrapContent(padding: 20) // wrap all subviews with a padding of 20 pixels all around +``` + + +###### Example: +...: + + + + +```swift + viewA.pin..... +``` + +
+ + + + + ## justify() / align() **Methods:** diff --git a/Sources/Impl/PinLayoutImpl+WrapContent.swift b/Sources/Impl/PinLayoutImpl+WrapContent.swift index 06d2a928..d89e07f7 100644 --- a/Sources/Impl/PinLayoutImpl+WrapContent.swift +++ b/Sources/Impl/PinLayoutImpl+WrapContent.swift @@ -28,12 +28,27 @@ extension PinLayoutImpl { return wrapContent(.all, padding: .zero, { return "wrapContent()" }) } + func wrapContent(padding: CGFloat) -> PinLayout { + return wrapContent(.all, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) + } + + func wrapContent(padding: UIEdgeInsets) -> PinLayout { + return wrapContent(.all, padding: padding, { return "wrapContent(padding: \(insetsDescription(padding))" }) + } + func wrapContent(_ type: WrapType) -> PinLayout { return wrapContent(type, padding: .zero, { return "wrapContent(\(type.description)" }) } - @discardableResult - private func wrapContent(_ type: WrapType, padding: PPadding, _ context: Context) -> PinLayout { + func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout { + return wrapContent(type, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) + } + + func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout { + return wrapContent(type, padding: padding, { return "wrapContent(\(type.description), padding: \(insetsDescription(padding))" }) + } + + private func wrapContent(_ type: WrapType, padding: UIEdgeInsets, _ context: Context) -> PinLayout { let subviews = view.subviews guard !subviews.isEmpty else { return self } let firstViewFrame = subviews[0].frame @@ -61,28 +76,22 @@ extension PinLayoutImpl { var offsetDx: CGFloat = 0 var offsetDy: CGFloat = 0 - if type == .all || type == .width { - let contentWidth = maxX - minX + if type == .all || type == .horizontally { + let contentWidth = maxX - minX + padding.left + padding.right if contentWidth >= 0 { setWidth(contentWidth, context) } - offsetDx = -minX -// let contentWidth = view.subviews.max(by: { subview1, subview2 in -// subview1.frame.maxX < subview2.frame.maxX -// })?.frame.maxX ?? 0 + offsetDx = -minX + padding.left } - if type == .all || type == .height { - let contentHeight = maxY - minY + if type == .all || type == .vertically { + let contentHeight = maxY - minY + padding.top + padding.bottom if contentHeight >= 0 { setHeight(contentHeight, context) } - offsetDy = -minY -// let contentHeight = view.subviews.max(by: { subview1, subview2 in -// subview1.frame.maxY < subview2.frame.maxY -// })?.frame.maxY ?? 0 + offsetDy = -minY + padding.top } if offsetDx != 0 || offsetDy != 0 { diff --git a/Sources/PinLayout+Filters.swift b/Sources/PinLayout+Filters.swift deleted file mode 100644 index 400ca72e..00000000 --- a/Sources/PinLayout+Filters.swift +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017 Luc Dion -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#if os(iOS) || os(tvOS) -import UIKit - -// Filter out all hidden views (isHidden is true or alpha is 0) -public func visible(_ views: [UIView]) -> [UIView] { - return views.filter({ !$0.isHidden && $0.alpha > 0 }) -} - -#endif diff --git a/Sources/PinLayout.swift b/Sources/PinLayout.swift index 9a659ad9..543f2e85 100644 --- a/Sources/PinLayout.swift +++ b/Sources/PinLayout.swift @@ -308,10 +308,48 @@ public protocol PinLayout { @discardableResult func size(of view: NSView) -> PinLayout #endif + /** + Adjust the view's width & height to wrap all its subviews. The method also adjust subviews position to create a tight wrap. + */ @discardableResult func wrapContent() -> PinLayout + /** + Adjust the view's width & height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - padding: Specify a padding value. + */ + @discardableResult func wrapContent(padding: CGFloat) -> PinLayout + /** + Adjust the view's width & height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - padding: Specify a padding using an UIEdgeInsets. + */ + @discardableResult func wrapContent(padding: UIEdgeInsets) -> PinLayout + + /** + Adjust the view's width AND/OR height to wrap all its subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + */ @discardableResult func wrapContent(_ type: WrapType) -> PinLayout - @discardableResult func wrapContent(padding: PPadding) -> PinLayout - @discardableResult func wrapContent(_ type: WrapType, padding: PPadding) -> PinLayout + /** + Adjust the view's width AND/OR height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + - padding: Specify a padding value. + */ + @discardableResult func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout + /** + Adjust the view's width AND/OR height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + - padding: Specify a padding using an UIEdgeInsets. + */ + @discardableResult func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout /** Set the view aspect ratio. diff --git a/Sources/Types+Description.swift b/Sources/Types+Description.swift index 28946b2a..ccfad56f 100644 --- a/Sources/Types+Description.swift +++ b/Sources/Types+Description.swift @@ -55,8 +55,8 @@ extension WrapType { var description: String { switch self { case .all: return ".all" - case .width: return ".width" - case .height: return ".height" + case .horizontally: return ".horizontally" + case .vertically: return ".vertically" } } } diff --git a/Sources/Types.swift b/Sources/Types.swift index 32f691c3..77cce2b0 100644 --- a/Sources/Types.swift +++ b/Sources/Types.swift @@ -167,47 +167,12 @@ public enum FitType { } public enum WrapType { - /** - */ + /// Adjust the view's width AND height to wrap all its subviews. case all - /** - */ - case width - /** - */ - case height -} - -public struct PPadding { - let top: CGFloat - let left: CGFloat - let bottom: CGFloat - let right: CGFloat - - static var zero: PPadding { - return PPadding(0) - } - - init(_ all: CGFloat) { - top = all - left = all - bottom = all - right = all - } - - init(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) { - self.top = top - self.left = left - self.bottom = bottom - self.right = right - } - - init(h: CGFloat, v: CGFloat) { - top = v - left = h - bottom = v - right = h - } + /// Adjust only the view's width to wrap all its subviews. The view's height won't be modified. + case horizontally + /// Adjust only the view's height to wrap all its subviews. The view's width won't be modified. + case vertically } @objc public enum LayoutDirection: Int { diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift index e877d8b1..eaaa684c 100644 --- a/Tests/Common/WrapContentSpec.swift +++ b/Tests/Common/WrapContentSpec.swift @@ -104,8 +104,8 @@ class WrapContentSpec: QuickSpec { aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) - aView.pin.wrapContent(.width) - aView.pin.wrapContent(.height) + aView.pin.wrapContent(.horizontally) + aView.pin.wrapContent(.vertically) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) @@ -133,7 +133,7 @@ class WrapContentSpec: QuickSpec { aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) - aView.pin.wrapContent(.width) + aView.pin.wrapContent(.horizontally) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 100.0))) expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 120.0, width: 100.0, height: 40.0))) @@ -146,7 +146,7 @@ class WrapContentSpec: QuickSpec { aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) - aView.pin.wrapContent(.height) + aView.pin.wrapContent(.vertically) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 60.0))) expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 0.0, width: 100.0, height: 40.0))) @@ -194,22 +194,184 @@ class WrapContentSpec: QuickSpec { expect(aViewChild2.frame).to(equal(CGRect(x: 390.0, y: 220.0, width: 60.0, height: 60.0))) expect(aViewChild3.frame).to(equal(CGRect(x: 390.0, y: 0.0, width: 60.0, height: 60.0))) } + } + + describe("wrapContent with padding") { it("wrap and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(padding: 10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 280.0, height: 80.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 10.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 110.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 210.0, y: 10.0, width: 60.0, height: 60.0))) } - it("wrap and update subviews position") { - // warning - aView.pin.wrapContent().width(20) + it("wrap and update subviews position + center") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(padding: 10).center() + + expect(aView.frame).to(equal(CGRect(x: 60.0, y: 160.0, width: 280.0, height: 80.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 10.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 110.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 210.0, y: 10.0, width: 60.0, height: 60.0))) } - it("wrap and update subviews position") { - // warning - aView.pin.width(20).wrapContent() + it("wrap horizontally + padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.horizontally, padding: 10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 280.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 10.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 110.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 210.0, y: 120.0, width: 60.0, height: 60.0))) } - it("wrap and update subviews position") { - // warning - aView.pin.height(20).wrapContent() + it("wrap vertically + padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + + aView.pin.wrapContent(.vertically, padding: 10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) + } + + it("wrap horizontally + negative padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 160, width: 60, height: 60) + aView.pin.wrapContent(.horizontally, padding: -10) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 240.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: -10.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 90.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 190.0, y: 160.0, width: 60.0, height: 60.0))) + } + + it("wrap vertically + negative padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 160, width: 60, height: 60) + + aView.pin.wrapContent(.vertically, padding: -10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 80.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: -10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: -10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) + } + + + it("wrap all + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 220.0, y: 30.0, width: 60.0, height: 60.0))) + } + + it("wrap all + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 220.0, y: 30.0, width: 60.0, height: 60.0))) + + } + + it("wrap horizontally + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.horizontally, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 220.0, y: 140.0, width: 60.0, height: 60.0))) + + } + + + it("wrap vertically + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.vertically, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) + + } + + it("wrap all + negative padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: -10, left: -20, bottom: -30, right: -40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 40.0))) + expect(aViewChild.frame).to(equal(CGRect(x: -20.0, y: -10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 80.0, y: -10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 180.0, y: 10.0, width: 60.0, height: 60.0))) + } + } + + describe("wrapContent + min/max") { + it("wrap all + maxWidth + maxHeight") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 130, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + + aView.pin.wrapContent().maxWidth(200).maxHeight(50) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 50.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 20.0, width: 60.0, height: 60.0))) + } + + it("wrap all + minWidth + minHeight") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 130, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + + aView.pin.wrapContent().minWidth(300).minHeight(100) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 300.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 20.0, width: 60.0, height: 60.0))) } } } From 7b39081d5fe1da00f3a7ecbd3143abaae4545750 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Sat, 2 Jun 2018 07:11:58 -0400 Subject: [PATCH 009/389] Update for tvOS and macOS --- .../xcschemes/PinLayoutSample.xcscheme | 2 +- PinLayout.xcodeproj/project.pbxproj | 22 ++++++++++++++----- .../xcschemes/PinLayout-iOS.xcscheme | 2 +- .../xcschemes/PinLayout-macOS.xcscheme | 2 +- .../xcschemes/PinLayout-tvOS.xcscheme | 2 +- Sources/Impl/PinLayoutImpl+WrapContent.swift | 16 +++++++------- Sources/PinLayout.swift | 9 ++++++++ Sources/Types+Description.swift | 6 ++++- Tests/Common/WrapContentSpec.swift | 17 +++++++------- 9 files changed, 51 insertions(+), 27 deletions(-) diff --git a/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme b/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme index d6642870..06ff0930 100644 --- a/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme +++ b/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme @@ -1,6 +1,6 @@ PinLayout { - return wrapContent(.all, padding: .zero, { return "wrapContent()" }) + return wrapContent(.all, padding: PEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), { return "wrapContent()" }) } func wrapContent(padding: CGFloat) -> PinLayout { - return wrapContent(.all, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) + return wrapContent(.all, padding: PEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) } - func wrapContent(padding: UIEdgeInsets) -> PinLayout { + func wrapContent(padding: PEdgeInsets) -> PinLayout { return wrapContent(.all, padding: padding, { return "wrapContent(padding: \(insetsDescription(padding))" }) } func wrapContent(_ type: WrapType) -> PinLayout { - return wrapContent(type, padding: .zero, { return "wrapContent(\(type.description)" }) + return wrapContent(type, padding: PEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), { return "wrapContent(\(type.description)" }) } func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout { - return wrapContent(type, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) + return wrapContent(type, padding: PEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) } - func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout { + func wrapContent(_ type: WrapType, padding: PEdgeInsets) -> PinLayout { return wrapContent(type, padding: padding, { return "wrapContent(\(type.description), padding: \(insetsDescription(padding))" }) } - private func wrapContent(_ type: WrapType, padding: UIEdgeInsets, _ context: Context) -> PinLayout { + private func wrapContent(_ type: WrapType, padding: PEdgeInsets, _ context: Context) -> PinLayout { let subviews = view.subviews guard !subviews.isEmpty else { return self } let firstViewFrame = subviews[0].frame @@ -57,7 +57,7 @@ extension PinLayoutImpl { var minY = firstViewFrame.minY var maxY = firstViewFrame.maxY - for var i in 1.. PinLayout + #elseif os(macOS) + @discardableResult func wrapContent(padding: NSEdgeInsets) -> PinLayout + #endif /** Adjust the view's width AND/OR height to wrap all its subviews. @@ -349,7 +353,12 @@ public protocol PinLayout { - type: Specify the wrap type (.all, .horizontally, .vertically) - padding: Specify a padding using an UIEdgeInsets. */ + #if os(iOS) || os(tvOS) @discardableResult func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout + #elseif os(macOS) + @discardableResult func wrapContent(_ type: WrapType, padding: NSEdgeInsets) -> PinLayout + #endif + /** Set the view aspect ratio. diff --git a/Sources/Types+Description.swift b/Sources/Types+Description.swift index ccfad56f..8a0a7dd7 100644 --- a/Sources/Types+Description.swift +++ b/Sources/Types+Description.swift @@ -6,7 +6,11 @@ // Copyright Š 2018 mcswiftlayyout.mirego.com. All rights reserved. // -import Foundation +#if os(iOS) || os(tvOS) +import UIKit +#else +import AppKit +#endif extension HorizontalAlign { var description: String { diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift index eaaa684c..ff56ae01 100644 --- a/Tests/Common/WrapContentSpec.swift +++ b/Tests/Common/WrapContentSpec.swift @@ -279,13 +279,12 @@ class WrapContentSpec: QuickSpec { expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) } - it("wrap all + padding UIEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) @@ -297,7 +296,7 @@ class WrapContentSpec: QuickSpec { aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(.all, padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) @@ -305,12 +304,12 @@ class WrapContentSpec: QuickSpec { } - it("wrap horizontally + padding UIEdgeInsets") { + it("wrap horizontally + padding PEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.horizontally, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(.horizontally, padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 100.0))) expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 120.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 120.0, width: 60.0, height: 60.0))) @@ -319,12 +318,12 @@ class WrapContentSpec: QuickSpec { } - it("wrap vertically + padding UIEdgeInsets") { + it("wrap vertically + padding PEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.vertically, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(.vertically, padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 120.0))) expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 10.0, width: 60.0, height: 60.0))) @@ -332,12 +331,12 @@ class WrapContentSpec: QuickSpec { } - it("wrap all + negative padding UIEdgeInsets") { + it("wrap all + negative padding PEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: -10, left: -20, bottom: -30, right: -40)) + aView.pin.wrapContent(.all, padding: PEdgeInsets(top: -10, left: -20, bottom: -30, right: -40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 40.0))) expect(aViewChild.frame).to(equal(CGRect(x: -20.0, y: -10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 80.0, y: -10.0, width: 60.0, height: 60.0))) From 174137d2569310a60b4b676b0647cd1e70f11024 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Mon, 4 Jun 2018 22:28:50 -0400 Subject: [PATCH 010/389] Add wrapContent documentation. --- README.md | 49 +++++++++++++---------- docs/images/wrapContent_all.png | Bin 0 -> 25924 bytes docs/images/wrapContent_before.png | Bin 0 -> 25602 bytes docs/images/wrapContent_example_1.png | Bin 0 -> 60959 bytes docs/images/wrapContent_horizontally.png | Bin 0 -> 26242 bytes docs/images/wrapContent_padding.png | Bin 0 -> 25830 bytes docs/images/wrapContent_vertically.png | Bin 0 -> 25552 bytes 7 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 docs/images/wrapContent_all.png create mode 100644 docs/images/wrapContent_before.png create mode 100644 docs/images/wrapContent_example_1.png create mode 100644 docs/images/wrapContent_horizontally.png create mode 100644 docs/images/wrapContent_padding.png create mode 100644 docs/images/wrapContent_vertically.png diff --git a/README.md b/README.md index 9c7fd543..a134fc6c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * Swift 3.2+ / Swift 4.0 / Objective-C ### Recent features -* :star: Add methods `wrapConten(...)` that adjust the view's width & height to wrap all its subviews. See [wrapContent](#wrapCcontent) for more information. +* :star: Add `wrapContent()` methods that adjust view's width & height to wrap all its subviews. See [wrapContent](#wrapContent) for more information. * :star: PinLayout now support macOS. See [macOS Support](#macos_support) for more information. @@ -1137,50 +1137,57 @@ This example runs perfectly on a iPhone X (iOS 11), but it also runs on any devi
- + ## WrapContent -The following methods are useful to adjust the view's width and/or height to wrap all its subviews. These method also adjust subviews position to create a tight wrap. +The following methods are useful to adjust view's width and/or height to wrap all its subviews. These methods also adjust subviews position to create a tight wrap. **Methods:** * **`wrapContent()`** -Bla. -* **`wrapContent(padding: CGFloat)`** -Bla. -* **`wrapContent(padding: UIEdgeInsets)`** -Bla. +**`wrapContent(padding: CGFloat)`** +**`wrapContent(padding: UIEdgeInsets)`** +Adjust the view's width and height to wrap all its subviews. The method also adjusts subviews position to create a tight wrap. It is also possible to specify an optional padding around all subviews. * **`wrapContent(:WrapType)`** -Bla. -* **`wrapContent(:WrapType, padding: CGFloat)`** -Bla. -* **`wrapContent(:WrapType, padding: UIEdgeInsets)`** -Bla. - -TABLE SHOWING DIFFERENCES!!! +**`wrapContent(:WrapType, padding: CGFloat)`** **`wrapContent(:WrapType, padding: UIEdgeInsets)`** +Adjust the view's width AND/OR height to wrap all its subviews. WrapType values are `.horizontally`/`.vertically`/`.all` It is also possible to specify an optional padding around all subviews. ###### Usage examples: ```swift view.pin.wrapContent().center() // wrap all subviews and centered the view inside its parent. view.pin.wrapContent(padding: 20) // wrap all subviews with a padding of 20 pixels all around + view.pin.wrapContent(.horizontally) ``` - ###### Example: -...: +This example show the result of different `wrapContent()` method calls. +Here is the initial state: - + +| Source code | Result | Description | +|---------------------|----------|-------------------| +| `view.pin.wrapContent()` | | Adjust the view's height and width to tight fit its subviews. | +| `view.pin.wrapContent(padding: 10)` | | Adjust the view's height and width and add a padding of 10 pixels around its subviews. | +| `view.pin.wrapContent(.horizontally)` | | Adjust only the view's width. | +| `view.pin.wrapContent(.vertically)` | | Adjust only the view's height. | + + +###### Example: +This example shows how a view (`containerView`) with two subviews (`imageView` and `label`), can be adjusted to the size of its subviews and then centered inside its parent. + + ```swift - viewA.pin..... + label.pin.below(of: imageView, aligned: .center).marginTop(4) + containerView.pin.wrapContent().center() ``` +* Line 1: Position the label below the imageView aligned on its center with a top margin of 4 pixels. +* Line 2: Adjust the `containerView`'s size and position its subviews to create a tight wrap around them, and then it center the `containerView` inside its parent (superview).
- - ## justify() / align() diff --git a/docs/images/wrapContent_all.png b/docs/images/wrapContent_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0f00ca0f08a6ad8bd097828e69b1252e4c901d57 GIT binary patch literal 25924 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 literal 0 HcmV?d00001 diff --git a/docs/images/wrapContent_before.png b/docs/images/wrapContent_before.png new file mode 100644 index 0000000000000000000000000000000000000000..ad081829f7d61ddffbf6f33896f78a802ffc0e90 GIT binary patch literal 25602 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 YDgT+?-JJ&f@4CuYugmAi-n{#N0G`TvF#rGn literal 0 HcmV?d00001 diff --git a/docs/images/wrapContent_example_1.png b/docs/images/wrapContent_example_1.png new file mode 100644 index 0000000000000000000000000000000000000000..38ca574f4b5225b47726a16b01e3d71225637a91 GIT binary patch literal 60959 zcmeFZbyQXF_by6zBPG%;0vizNmXef4YSW@fcc&oTp>&skfOKu??vn15?!0S*pYQpe zbMN^6&basdbI15GmI8b2wbp#!Ip1eK^O^7Fi;{vACfZXp7#J8#8R^%`Ffd3MFfgzU zC`iC7a30|%FfbUj=HlW?GUDQtO14&}<`%$9(qG~dkX2P=h&ngoXlZFHMHrREtVZ~y zOK}mh(O!w+Ni$L*_y&{ds)AYagTN9R5*8m}jo;$BX(71jMbY5f5=Bu7)byU)6M2qRgPn|ovKs*?+{c&B$y-o{T-a|Td~rZR>I?%X##yPqkq zprx@RZk1dMX*JB|k}cIXRj7$Ah#W*$p~<2w5^Z8#>{-sa@n=H~p$NZk=|=aT!~nsF z6zDiA@fhoNNk;cM-y576gqRo^2z=G)ija-nkP28%PF%Wqp8;a#Fyv7rN$Y&N^i)sJ zdRJQRE2Tdo$-H>w+sMIS(gBwykw_d=E!3mihQ6tTr5}Unmp)Nhb~1+9UzY?sMI7g) zSrTQw^3Y0>N7No67IztVy%rK?l@lWT)?v{5^1bN5;+lLg@o?)JB4Y0;SVF+yrc9w& zCzb+-^I5ZQEP>#&2(IIDu^dmDu1_wAKWL1ukC$5MOA(Ptb`OV-Tx=ZPdfF%JkPaZ= zQsN-M(nq$$quGie;Z&Y-o%lqh;yAgLlbVfirFt zP=dMDmux)B!jz6VCG3(k_GO5yupyg8KL16tIE?*DYL@Jrn50vcJSmP?4ukqLu6R)V zD5AtN#SsTAvU()qH)8)*PHc6$amr`IcP!XTs2P3-LDqglGBxmcEk?u)7g7NW<*1S# z_#zB_PdRjSx6j9yOqG73lY6^~-zxDBv^aQU?qM(=c6u0mVja5vQ+Uh&CmMI$*p1`O z1nqSci)W}xxw0(@8O`@UZYj391zB+j;b%8I+KWyD=7+62c8%QG<$6@ZAhp^{; zL=i-#Q7|)Teh0xC25ZuU2k|faA<*DTV?_IBQ*H&}L{ZvBN=P#)hpSR)N4;CsSY@=u ztM#_0bc$rnCUOaL7h{hNF3fVxC;1Rqmv#4^=V_pV#OSb2C5~<=s}%F_Q+w=p5vi}) zGPs8nP7wLLVdZd*z@HN_*TWGF-)eHifBy2rMH5xsXB>Q8M(>Y4c~NrP~V)xUh6t;Qe@-{xbgdzc9quGknYZto^N# znp6b+onBK%iN0j0gE(=0Nfb?%e?enOyT?$4!yh!)28;J4TfUs$B_>naLRqLFu`;zX z(B9WRZcO|tJv|?szL<}b8CguJ%BY;LH1*wDXQ}X)N`PoN+H~x$OgOb&cSRR-*G#wk zD)TD&5v4?&p~7Kq+glDsbf&mik66yw>sapK;9$vM@?d-d#9;I%%mmnssT#Y=H_~cZ z@7}@}sN~~q+ioj-KtIJg#SD|=%(@(oHovS~t99_cAWV*WO?|8CbieBm$yerV# zDjbnDDK9T5Z$5gtCbovQCf=hFd#&2_-1NE6bBj2a=i|?%)GP}y@<-IjRI^ko)OuB& ziu9B`awU~HRnXN}3R%==avk4%{}w(Rw&i1w<$>$Le~Zy5m6C5+GN3%D#HO}TG@m

f{@4 zNvEp4S985}@UB;`8Lrfgr>=P?S0^M_o>wGSA5S87&Yuopx?><9eZ){87BKq&x=qsR zd$VqC+MH2hkeJbCU1acWDLtz8ZNuBBVb3h&jweP=D=$~LI=*+@(j(F1%dIDlCCzft zeXIL+BtMyy%IRTcY8n5&s;wBZn^YUm+uJbIFmTg^*#B#idNQ+PxsGmlWR7FhHp`@* z;KQ0>dv#$|onhF!`giEX-0z%1=|WG5nV)HMp2cI1cP!+#nwH=zx*Zr~0lb-3{NgEB_ zmsRLTqQ{B2> z(46D-`JVhf0rm`b*_#G-A6^iC1E~tZKr};?PV^Jx1LP2*2Ei5&6&n%X7P}JH6*CL0 z^2h!4t5rQ<&T#7oPw_kTd*|vyyUsMMyw9DVH3Ec#%Yt#FUdoFwgr=3b{<@VOl{PRI ze-dOU@jcuX=M#Af>Fvzx<+jZ)Rk%mLeEw4P0