Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layoutable and SizeCalculable protocols #148

Merged
merged 11 commits into from
Jun 15, 2018
2 changes: 1 addition & 1 deletion PinLayout.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ Pod::Spec.new do |spec|
spec.tvos.deployment_target = '9.0'
spec.tvos.frameworks = 'Foundation', 'CoreGraphics', 'UIKit'

spec.osx.deployment_target = '10.9'
spec.osx.deployment_target = '10.10'
spec.osx.frameworks = 'Foundation', 'CoreGraphics', 'AppKit'
end
44 changes: 26 additions & 18 deletions PinLayout.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ target 'PinLayoutSample' do
end

#target 'PinLayoutMacOsSample' do
# platform :osx, '10.9'
# platform :osx, '10.10'
# project 'Example/PinLayoutMacOsSample.xcodeproj'
#
# pod 'PinLayout', :path => './'
Expand Down
42 changes: 21 additions & 21 deletions Sources/Impl/Coordinates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,69 +23,69 @@ import UIKit
import AppKit
#endif

public func _pinlayoutSetUnitTest(displayScale: CGFloat) {
Coordinates.displayScale = displayScale
}
#if os(iOS) || os(tvOS)
internal var displayScale: CGFloat = UIScreen.main.scale
#elseif os(OSX)
internal var displayScale: CGFloat = NSScreen.main?.backingScaleFactor ?? 2.0
#endif
internal var onePixelLength: CGFloat = 1 / displayScale

final class Coordinates {
#if os(iOS) || os(tvOS)
internal static var displayScale: CGFloat = UIScreen.main.scale
#elseif os(OSX)
internal static var displayScale: CGFloat = NSScreen.main?.backingScaleFactor ?? 2.0
#endif
internal static var onePixelLength: CGFloat = 1 / displayScale
public func _pinlayoutSetUnitTest(scale: CGFloat) {
displayScale = scale
}

static func hCenter(_ view: PView, keepTransform: Bool) -> CGFloat {
final class Coordinates<View: Layoutable> {
static func hCenter(_ view: View, keepTransform: Bool) -> CGFloat {
let rect = view.getRect(keepTransform: keepTransform)
return rect.minX + (rect.width / 2)
}

static func vCenter(_ view: PView, keepTransform: Bool) -> CGFloat {
static func vCenter(_ view: View, keepTransform: Bool) -> CGFloat {
let rect = view.getRect(keepTransform: keepTransform)
return rect.minY + (rect.height / 2)
}

static func topLeft(_ view: PView, keepTransform: Bool) -> CGPoint {
static func topLeft(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX, y: rect.minY)
}

static func topCenter(_ view: PView, keepTransform: Bool) -> CGPoint {
static func topCenter(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX + (rect.width / 2), y: rect.minY)
}

static func topRight(_ view: PView, keepTransform: Bool) -> CGPoint {
static func topRight(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX + rect.width, y: rect.minY)
}

static func centerLeft(_ view: PView, keepTransform: Bool) -> CGPoint {
static func centerLeft(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX, y: rect.minY + (rect.height / 2))
}

static func center(_ view: PView, keepTransform: Bool) -> CGPoint {
static func center(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX + (rect.width / 2), y: rect.minY + (rect.height / 2))
}

static func centerRight(_ view: PView, keepTransform: Bool) -> CGPoint {
static func centerRight(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX + rect.width, y: rect.minY + (rect.height / 2))
}

static func bottomLeft(_ view: PView, keepTransform: Bool) -> CGPoint {
static func bottomLeft(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX, y: rect.minY + rect.height)
}

static func bottomCenter(_ view: PView, keepTransform: Bool) -> CGPoint {
static func bottomCenter(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX + (rect.width / 2), y: rect.minY + rect.height)
}

static func bottomRight(_ view: PView, keepTransform: Bool) -> CGPoint {
static func bottomRight(_ view: View, keepTransform: Bool) -> CGPoint {
let rect = view.getRect(keepTransform: keepTransform)
return CGPoint(x: rect.minX + rect.width, y: rect.minY + rect.height)
}
Expand Down
14 changes: 7 additions & 7 deletions Sources/Impl/PinLayoutImpl+Coordinates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import AppKit
#endif

extension PinLayoutImpl {
extension PinLayout {
internal func top(_ context: Context) {
setTop(0, context)
}
Expand Down Expand Up @@ -361,26 +361,26 @@ extension PinLayoutImpl {
}
}

fileprivate func computeCoordinates(_ point: CGPoint, _ layoutSuperview: PView, _ referenceSuperview: PView) -> CGPoint {
fileprivate func computeCoordinates(_ point: CGPoint, _ layoutSuperview: View, _ referenceSuperview: View) -> CGPoint {
if layoutSuperview == referenceSuperview {
return point // same superview => no coordinates conversion required.
} else if referenceSuperview == layoutSuperview.superview {
} else if referenceSuperview == layoutSuperview.superview as? View {
let layoutSuperviewRect = layoutSuperview.getRect(keepTransform: keepTransform)
return CGPoint(x: point.x - layoutSuperviewRect.origin.x,
y: point.y - layoutSuperviewRect.origin.y)
// TOOD: Handle all cases. computeCoordinates should compute coordinates using only untransformed
// coordinates, but UIView.convert(...) below use transformed coordinates!
// Currently we only support 1 and 2 levels.
} else {
return referenceSuperview.convert(point, to: layoutSuperview)
return referenceSuperview.convert(point, to: layoutSuperview as? View.View)
}
}

internal func computeCoordinates(forAnchors anchors: [Anchor], _ context: Context) -> [CGPoint]? {
guard let layoutSuperview = layoutSuperview(context) else { return nil }
var results: [CGPoint] = []
anchors.forEach({ (anchor) in
let anchor = anchor as! AnchorImpl
let anchor = anchor as! AnchorImpl<View>
if let referenceSuperview = referenceSuperview(anchor.view, context) {
results.append(computeCoordinates(anchor.point(keepTransform: keepTransform),
layoutSuperview, referenceSuperview))
Expand All @@ -396,7 +396,7 @@ extension PinLayoutImpl {
}

internal func computeCoordinate(forEdge edge: HorizontalEdge, _ context: Context) -> CGFloat? {
let edge = edge as! HorizontalEdgeImpl
let edge = edge as! HorizontalEdgeImpl<View>
guard let layoutSuperview = layoutSuperview(context) else { return nil }
guard let referenceSuperview = referenceSuperview(edge.view, context) else { return nil }

Expand All @@ -405,7 +405,7 @@ extension PinLayoutImpl {
}

internal func computeCoordinate(forEdge edge: VerticalEdge, _ context: Context) -> CGFloat? {
let edge = edge as! VerticalEdgeImpl
let edge = edge as! VerticalEdgeImpl<View>
guard let layoutSuperview = layoutSuperview(context) else { return nil }
guard let referenceSuperview = referenceSuperview(edge.view, context) else { return nil }

Expand Down
46 changes: 24 additions & 22 deletions Sources/Impl/PinLayoutImpl+Layouting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@
#endif

// MARK: UIView's frame computation methods
extension PinLayoutImpl {
extension PinLayout {
/**
The method will execute PinLayout commands immediately. This method is **required only if your
source codes should also work in Xcode Playgrounds**. Outside of playgrounds, PinLayout executes
this method implicitly, it is not necessary to call it.

Examples:
```swift
view.pin.top(20).width(100).layout()
```
*/
public func layout() {
apply()
}
Expand All @@ -35,7 +45,7 @@ extension PinLayoutImpl {
isLayouted = true
}

private func apply(onView view: PView) {
private func apply(onView view: View) {
displayLayoutWarnings()

var newRect = view.getRect(keepTransform: keepTransform)
Expand Down Expand Up @@ -183,7 +193,7 @@ extension PinLayoutImpl {
}
}
}

private func computeSize() -> Size {
var size = resolveSize()

Expand Down Expand Up @@ -227,6 +237,10 @@ extension PinLayoutImpl {
}

private func computeLegacyFitSize(size: Size) -> Size {
guard let sizeCalculableView = view as? SizeCalculable else {
assertionFailure("Should not occurs, protocol conformance is checked before assigning adjustSizeType")
return size
}
guard size.width != nil || size.height != nil else {
warn("fitSize() won't be applied, neither the width nor the height can be determined.")
return size
Expand All @@ -243,11 +257,7 @@ extension PinLayoutImpl {
fitHeight = height
}

#if os(iOS) || os(tvOS)
let sizeThatFits = view.sizeThatFits(CGSize(width: fitWidth, height: fitHeight))
#else
let sizeThatFits = view.intrinsicContentSize
#endif
let sizeThatFits = sizeCalculableView.sizeThatFits(CGSize(width: fitWidth, height: fitHeight))

if fitWidth != .greatestFiniteMagnitude && (sizeThatFits.width > fitWidth) {
size.width = fitWidth
Expand All @@ -265,6 +275,11 @@ extension PinLayoutImpl {
}

private func computeSizeToFit(adjustSizeType: AdjustSizeType, size: Size) -> Size {
guard let sizeCalculableView = view as? SizeCalculable else {
assertionFailure("Should not occurs, protocol conformance is checked before assigning adjustSizeType")
return size
}

var fitWidth = CGFloat.greatestFiniteMagnitude
var fitHeight = CGFloat.greatestFiniteMagnitude
var size = size
Expand All @@ -287,20 +302,7 @@ extension PinLayoutImpl {
assertionFailure("Should not occured")
}

#if os(iOS) || os(tvOS)
let sizeThatFits = view.sizeThatFits(CGSize(width: fitWidth, height: fitHeight))
#else
let sizeThatFits: CGSize
if #available(OSX 10.10, *) {
if let control = view as? NSControl {
sizeThatFits = control.sizeThatFits(CGSize(width: fitWidth, height: fitHeight))
} else {
sizeThatFits = view.intrinsicContentSize
}
} else {
sizeThatFits = view.intrinsicContentSize
}
#endif
let sizeThatFits = sizeCalculableView.sizeThatFits(CGSize(width: fitWidth, height: fitHeight))

if fitWidth != .greatestFiniteMagnitude {
size.width = adjustSizeType.isFlexible ? sizeThatFits.width : fitWidth
Expand Down
Loading