diff --git a/Katana/Plastic/Anchor.swift b/Katana/Plastic/Anchor.swift index 39ab5966..5ab00546 100644 --- a/Katana/Plastic/Anchor.swift +++ b/Katana/Plastic/Anchor.swift @@ -32,16 +32,21 @@ public struct Anchor: Equatable { /// the `PlasticView` to which the anchor is associated to let view: PlasticView - + + /// the offset at which this anchor will be set, with respect to the anchor it will be assigned to + var offset: Value + /** Creates an anchor with a given type, related to a specific `PlasticView` - parameter kind: the kind of the anchor - parameter view: the view the anchor pertains to + - parameter offset: the offset at which this anchor will be set, with respect to the anchor it will be assigned to */ - init(kind: Kind, view: PlasticView) { + init(kind: Kind, view: PlasticView, offset: Value = .zero) { self.kind = kind self.view = view + self.offset = offset } /** @@ -51,27 +56,30 @@ public struct Anchor: Equatable { var coordinate: CGFloat { let absoluteOrigin = self.view.absoluteOrigin let size = self.view.frame - + let coord: CGFloat + switch self.kind { case .left: - return absoluteOrigin.x + coord = absoluteOrigin.x case .right: - return absoluteOrigin.x + size.width + coord = absoluteOrigin.x + size.width case .centerX: - return absoluteOrigin.x + size.width / 2.0 + coord = absoluteOrigin.x + size.width / 2.0 case .top: - return absoluteOrigin.y + coord = absoluteOrigin.y case .bottom: - return absoluteOrigin.y + size.height + coord = absoluteOrigin.y + size.height case .centerY: - return absoluteOrigin.y + size.height / 2.0 + coord = absoluteOrigin.y + size.height / 2.0 } + + return coord + view.scaleValue(offset) } /** @@ -85,4 +93,32 @@ public struct Anchor: Equatable { public static func == (lhs: Anchor, rhs: Anchor) -> Bool { return lhs.kind == rhs.kind && lhs.view === rhs.view } + + /** + Create an anchor equal to `lhs`, but with an offset equal to `lhs.offset + rhs` + */ + public static func + (lhs: Anchor, rhs: Value) -> Anchor { + return Anchor(kind: lhs.kind, view: lhs.view, offset: lhs.offset + rhs) + } + + /** + Create an anchor equal to `lhs`, but with an offset equal to `lhs.offset - rhs` + */ + public static func - (lhs: Anchor, rhs: Value) -> Anchor { + return Anchor(kind: lhs.kind, view: lhs.view, offset: lhs.offset + -rhs) + } + + /** + Create an anchor equal to `lhs`, but with an offset equal to `lhs.offset + Value.scalable(rhs)` + */ + public static func + (lhs: Anchor, rhs: CGFloat) -> Anchor { + return lhs + .scalable(rhs) + } + + /** + Create an anchor equal to `lhs`, but with an offset equal to `lhs.offset - Value.scalable(rhs)` + */ + public static func - (lhs: Anchor, rhs: CGFloat) -> Anchor { + return lhs - .scalable(rhs) + } } diff --git a/Katana/Plastic/Array+Plastic.swift b/Katana/Plastic/Array+Plastic.swift index 955ffce3..f6fb220d 100644 --- a/Katana/Plastic/Array+Plastic.swift +++ b/Katana/Plastic/Array+Plastic.swift @@ -40,13 +40,13 @@ extension Array where Element: PlasticView { } let leftmostOffset = (right.coordinate - left.coordinate - totalWidth) / 2.0 - firstView.setLeft(left, offset: Value.fixed(leftmostOffset)) + firstView.left = left + .fixed(leftmostOffset) for (index, view) in otherViews.enumerated() { let leftwardView = self[index] // take prev view let scaledSpacing = scaledSpacings[index] let anchor = Anchor(kind: .right, view: leftwardView) - view.setLeft(anchor, offset: .fixed(scaledSpacing)) + view.left = anchor + .fixed(scaledSpacing) } } @@ -80,13 +80,13 @@ extension Array where Element: PlasticView { } let upmostOffset = (bottom.coordinate - top.coordinate - totalHeight) / 2.0 - firstView.setTop(top, offset: .fixed(upmostOffset)) + firstView.top = top + .fixed(upmostOffset) for (index, view) in otherViews.enumerated() { let upperView = self[index] let scaledSpacing = scaledSpacings[index] let anchor = Anchor(kind: .bottom, view: upperView) - view.setTop(anchor, offset: .fixed(scaledSpacing)) + view.top = anchor + .fixed(scaledSpacing) } } @@ -144,12 +144,12 @@ extension Array where Element: PlasticView { view.width = .fixed(width) if index == 0 { - view.setLeft(left, offset: insets.left) + view.left = left + insets.left } else { let leftwardView = self[index-1] let spacing = spacings[index-1] - view.setLeft(leftwardView.right, offset: spacing) + view.left = leftwardView.right + spacing } } } @@ -207,12 +207,12 @@ extension Array where Element: PlasticView { view.height = .fixed(height) if index == 0 { - view.setTop(top, offset: insets.top) + view.top = top + insets.top } else { let upperView = self[index-1] let spacing = spacings[index - 1] - view.setTop(upperView.bottom, offset: spacing) + view.top = upperView.bottom + spacing } } } diff --git a/Katana/Plastic/EdgeInsets.swift b/Katana/Plastic/EdgeInsets.swift index c403049d..4ad97bbd 100644 --- a/Katana/Plastic/EdgeInsets.swift +++ b/Katana/Plastic/EdgeInsets.swift @@ -24,7 +24,7 @@ public struct EdgeInsets: Equatable { public let right: Value /// an instance of `EdgeInsets` with all the insets equal to zero - public static let zero = EdgeInsets(0, 0, 0, 0) + public static let zero: EdgeInsets = .scalable(0, 0, 0, 0) /** Creates an instance of `EdgeInsets` where all the insets are not scalable @@ -54,55 +54,6 @@ public struct EdgeInsets: Equatable { return EdgeInsets(top: .scalable(top), left: .scalable(left), bottom: .scalable(bottom), right: .scalable(right)) } - /** - Creates an instance of `EdgeInsets` where all the insets are scalable - - - parameter top: the value of the top inset - - parameter left: the value of the left inset - - parameter bottom: the value of the bottom inset - - parameter right: the value of the right inset - - - returns: an instance of `EdgeInsets` where all the insets are not scalable - - - warning: Always prefer the static method `scalable(_:_:_:_:)` instead of this constructor - */ - public init(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) { - self.top = Value(top) - self.left = Value(left) - self.bottom = Value(bottom) - self.right = Value(right) - } - - - /** - Creates an instance of `EdgeInsets` with the given values - - - parameter scalableTop: the scalable value of the top inset - - parameter fixedTop: the fixed value of the top inset - - parameter scalableLeft: the scalable value of the left inset - - parameter fixedLeft: the fixed value of the left inset - - parameter scalableBottom: the scalable value of the bottom inset - - parameter fixedBottom: the fixed value of the bottom inset - - parameter scalableRight: the scalable value of the right inset - - parameter fixedRight: the fixed value of the right inset - - - returns: an instance of `EdgeInsets` with the given values - */ - public init(scalableTop: CGFloat, - fixedTop: CGFloat, - scalableLeft: CGFloat, - fixedLeft: CGFloat, - scalableBottom: CGFloat, - fixedBottom: CGFloat, - scalableRight: CGFloat, - fixedRight: CGFloat) { - - self.top = Value(scalable: scalableTop, fixed: fixedTop) - self.left = Value(scalable: scalableLeft, fixed: fixedLeft) - self.bottom = Value(scalable: scalableBottom, fixed: fixedBottom) - self.right = Value(scalable: scalableRight, fixed: fixedRight) - } - /** Creates an instance of `EdgeInsets` with the given value diff --git a/Katana/Plastic/PlasticView+Convenience.swift b/Katana/Plastic/PlasticView+Convenience.swift index 7a70bdf7..2b570b03 100644 --- a/Katana/Plastic/PlasticView+Convenience.swift +++ b/Katana/Plastic/PlasticView+Convenience.swift @@ -18,8 +18,8 @@ extension PlasticView { - parameter insets: the insets to use when filling the view frame. Only the left and right insets are used. */ public func fillHorizontally(_ view: PlasticView, insets: EdgeInsets = .zero) { - self.setLeft(view.left, offset: insets.left) - self.setRight(view.right, offset: -insets.right) + self.left = view.left + insets.left + self.right = view.right - insets.right } /** @@ -30,8 +30,8 @@ extension PlasticView { - parameter insets: the insets to use when filling the view frame. Only the left and right insets are used */ public func fillVertically(_ view: PlasticView, insets: EdgeInsets = .zero) { - self.setTop(view.top, offset: insets.top) - self.setBottom(view.bottom, offset: -insets.bottom) + self.top = view.top + insets.top + self.bottom = view.bottom - insets.bottom } /** @@ -81,10 +81,11 @@ extension PlasticView { bottom: Anchor, right: Anchor, insets: EdgeInsets = .zero) { - self.setLeft(left, offset: insets.left) - self.setRight(right, offset: -insets.right) - self.setTop(top, offset: insets.top) - self.setBottom(bottom, offset: -insets.bottom) + + self.left = left + insets.left + self.right = right - insets.right + self.top = top + insets.top + self.bottom = bottom - insets.bottom } /** @@ -106,10 +107,7 @@ extension PlasticView { aspectRatio: CGFloat = 1, insets: EdgeInsets = .zero) { - self.setLeft(left, offset: insets.left) - self.setRight(right, offset: -insets.right) - self.setTop(top, offset: insets.top) - self.setBottom(bottom, offset: -insets.bottom) + self.fill(top: top, left: left, bottom: bottom, right: right, insets: insets) let width = self.width.unscaledValue let height = self.height.unscaledValue @@ -133,7 +131,7 @@ extension PlasticView { */ public func centerBetween(left: Anchor, right: Anchor) { let offset: Value = .fixed((right.coordinate - left.coordinate) / 2.0) - self.setCenterX(left, offset: offset) + self.centerX = left + offset } /** @@ -145,7 +143,7 @@ extension PlasticView { */ public func centerBetween(top: Anchor, bottom: Anchor) { let offset: Value = .fixed((bottom.coordinate - top.coordinate) / 2.0) - self.setCenterY(top, offset: offset) + self.centerY = top + offset } /** @@ -167,9 +165,9 @@ extension PlasticView { - parameter insets: the insets to use when aligning edges */ public func coverLeft(_ view: PlasticView, insets: EdgeInsets = .zero) { - self.setLeft(view.left, offset: insets.left) - self.setTop(view.top, offset: insets.top) - self.setBottom(view.bottom, offset: -insets.bottom) + self.left = view.left + insets.left + self.top = view.top + insets.top + self.bottom = view.bottom - insets.bottom } /** @@ -180,9 +178,9 @@ extension PlasticView { - parameter insets: the insets to use when aligning edges */ public func coverRight(_ view: PlasticView, insets: EdgeInsets = .zero) { - self.setRight(view.right, offset: -insets.right) - self.setTop(view.top, offset: insets.top) - self.setBottom(view.bottom, offset: -insets.bottom) + self.right = view.right - insets.right + self.top = view.top + insets.top + self.bottom = view.bottom - insets.bottom } /** @@ -193,9 +191,9 @@ extension PlasticView { - parameter insets: the insets to use when aligning edges */ public func asHeader(_ view: PlasticView, insets: EdgeInsets = EdgeInsets.zero) { - self.setLeft(view.left, offset: insets.left) - self.setRight(view.right, offset: -insets.right) - self.setTop(view.top, offset: insets.top) + self.left = view.left + insets.left + self.right = view.right - insets.right + self.top = view.top + insets.top } /** @@ -206,8 +204,8 @@ extension PlasticView { - parameter insets: the insets to use when aligning edges */ public func asFooter(_ view: PlasticView, insets: EdgeInsets = EdgeInsets.zero) { - self.setLeft(view.left, offset: insets.left) - self.setRight(view.right, offset: -insets.right) - self.setBottom(view.bottom, offset: -insets.bottom) + self.left = view.left + insets.left + self.right = view.right - insets.right + self.bottom = view.bottom - insets.bottom } } diff --git a/Katana/Plastic/PlasticView.swift b/Katana/Plastic/PlasticView.swift index f0bc3c12..0fe1c2ac 100644 --- a/Katana/Plastic/PlasticView.swift +++ b/Katana/Plastic/PlasticView.swift @@ -160,30 +160,21 @@ public class PlasticView { } set(newValue) { - setHeight(newValue) - } - } + self.constraintY = .height - /** - Sets a new height for the instance - - - parameter value: the new height - */ - private func setHeight(_ value: Value) { - self.constraintY = .height - - let newHeight = max(scaleValue(value), 0) - var newTop = self.top.coordinate - - if oldestConstraintY == .bottom { - newTop = self.bottom.coordinate - newHeight - - } else if oldestConstraintY == .centerY { - newTop = self.centerY.coordinate - newHeight / 2.0 + let newHeight = max(scaleValue(newValue), 0) + var newTop = self.top.coordinate + + if oldestConstraintY == .bottom { + newTop = self.bottom.coordinate - newHeight + + } else if oldestConstraintY == .centerY { + newTop = self.centerY.coordinate - newHeight / 2.0 + } + + self.updateY(newTop) + self.updateHeight(newHeight) } - - self.updateY(newTop) - self.updateHeight(newHeight) } @@ -194,74 +185,55 @@ public class PlasticView { } set(newValue) { - setWidth(newValue) - } - } - - /** - Sets a new width for the instance - - - parameter value: the new width - */ - private func setWidth(_ value: Value) { - self.constraintX = .width - - let newWidth = max(scaleValue(value), 0) - var newLeft = self.left.coordinate - - if self.oldestConstraintX == .right { - newLeft = self.right.coordinate - newWidth - - } else if self.oldestConstraintX == .centerX { - newLeft = self.centerX.coordinate - newWidth / 2.0 + self.constraintX = .width + + let newWidth = max(scaleValue(newValue), 0) + var newLeft = self.left.coordinate + + if self.oldestConstraintX == .right { + newLeft = self.right.coordinate - newWidth + + } else if self.oldestConstraintX == .centerX { + newLeft = self.centerX.coordinate - newWidth / 2.0 + } + + self.updateX(newLeft) + self.updateWidth(newWidth) } - - self.updateX(newLeft) - self.updateWidth(newWidth) } /** The bottom anchor of the instance. - Setting its value has the same effect of invoking `setBottom(_:offset:)` with an offset equal to `.zero` + Setting its value sets the view's bottom edge position equal to the given anchor */ public var bottom: Anchor { get { return Anchor(kind: .bottom, view: self) } - + set(newValue) { - setBottom(newValue) - } - } + self.constraintY = .bottom - /** - Sets the view's bottom edge position equal to the given anchor - - - parameter anchor: the anchor - - parameter offset: an optional offset to use with respect to the anchor. The default value is `.zero` - */ - public func setBottom(_ anchor: Anchor, offset: Value = Value.zero) { - self.constraintY = .bottom - - let newBottom = anchor.coordinate + scaleValue(offset) - var newHeight = scaleValue(self.height) - - if oldestConstraintY == .top { - newHeight = max(newBottom - self.top.coordinate, 0) - - } else if oldestConstraintY == .centerY { - newHeight = max(2 * (newBottom - self.centerY.coordinate), 0) + let newBottom = newValue.coordinate + var newHeight = scaleValue(self.height) + + if oldestConstraintY == .top { + newHeight = max(newBottom - self.top.coordinate, 0) + + } else if oldestConstraintY == .centerY { + newHeight = max(2 * (newBottom - self.centerY.coordinate), 0) + } + + self.updateY(newBottom - newHeight) + self.updateHeight(newHeight) } - - self.updateY(newBottom - newHeight) - self.updateHeight(newHeight) } /** The top anchor of the instance. - Setting its value has the same effect of invoking `setTop(_:offset:)` with an offset equal to `.zero` + Setting its value sets the view's top edge position equal to the given anchor */ public var top: Anchor { get { @@ -269,37 +241,27 @@ public class PlasticView { } set(newValue) { - setTop(newValue) - } - } + self.constraintY = .top - /** - Sets the view's top edge position equal to the given anchor - - - parameter anchor: the anchor - - parameter offset: an optional offset to use with respect to the anchor. The default value is `.zero` - */ - public func setTop(_ anchor: Anchor, offset: Value = Value.zero) { - self.constraintY = .top + let newTop = newValue.coordinate + var newHeight = scaleValue(self.height) - let newTop = anchor.coordinate + scaleValue(offset) - var newHeight = scaleValue(self.height) - - if self.constraintY == .bottom { - newHeight = max(self.bottom.coordinate - newTop, 0) - - } else if self.constraintY == .centerY { - newHeight = max(2.0 * (self.centerY.coordinate - newTop), 0.0) + if self.constraintY == .bottom { + newHeight = max(self.bottom.coordinate - newTop, 0) + + } else if self.constraintY == .centerY { + newHeight = max(2.0 * (self.centerY.coordinate - newTop), 0.0) + } + + self.updateY(newTop) + self.updateHeight(newHeight) } - - self.updateY(newTop) - self.updateHeight(newHeight) } /** The right anchor of the instance. - Setting its value has the same effect of invoking `setRight(_:offset:)` with an offset equal to `.zero` + Setting its value sets the view's right edge position equal to the given anchor */ public var right: Anchor { get { @@ -307,38 +269,27 @@ public class PlasticView { } set(newValue) { - setRight(newValue) - } - } - - /** - Sets the view's right edge position equal to the given anchor - - - parameter anchor: the anchor - - parameter offset: an optional offset to use with respect to the anchor. The default value is `.zero` - */ - public func setRight(_ anchor: Anchor, offset: Value = Value.zero) { - self.constraintX = .right - - let newRight = anchor.coordinate + scaleValue(offset) - var newWidth = scaleValue(self.width) - - if self.oldestConstraintX == .left { - newWidth = max(newRight - self.left.coordinate, 0.0) - - } else if self.oldestConstraintX == .centerX { - newWidth = max(2.0 * (newRight - self.centerX.coordinate), 0.0) + self.constraintX = .right + + let newRight = newValue.coordinate + var newWidth = scaleValue(self.width) + + if self.oldestConstraintX == .left { + newWidth = max(newRight - self.left.coordinate, 0.0) + + } else if self.oldestConstraintX == .centerX { + newWidth = max(2.0 * (newRight - self.centerX.coordinate), 0.0) + } + + self.updateX(newRight - newWidth) + self.updateWidth(newWidth) } - - self.updateX(newRight - newWidth) - self.updateWidth(newWidth) } - /** The left anchor of the instance. - Setting its value has the same effect of invoking `setLeft(_:offset:)` with an offset equal to `.zero` + Setting its value sets the view's left edge position equal to the given anchor */ public var left: Anchor { get { @@ -346,38 +297,28 @@ public class PlasticView { } set(newValue) { - setLeft(newValue) - } - } - - /** - Sets the view's left edge position equal to the given anchor - - - parameter anchor: the anchor - - parameter offset: an optional offset to use with respect to the anchor. The default value is `.zero` - */ - public func setLeft(_ anchor: Anchor, offset: Value = Value.zero) { - self.constraintX = .left - - let newLeft = anchor.coordinate + scaleValue(offset) - var newWidth = scaleValue(self.width) - - if self.oldestConstraintX == .right { - newWidth = max(self.right.coordinate - newLeft, 0) - - } else if self.oldestConstraintX == .centerX { - newWidth = max(2.0 * (self.centerX.coordinate - newLeft), 0.0) + self.constraintX = .left + + let newLeft = newValue.coordinate + var newWidth = scaleValue(self.width) + + if self.oldestConstraintX == .right { + newWidth = max(self.right.coordinate - newLeft, 0) + + } else if self.oldestConstraintX == .centerX { + newWidth = max(2.0 * (self.centerX.coordinate - newLeft), 0.0) + } + + // update coords + self.updateX(newLeft) + self.updateWidth(newWidth) } - - // update coords - self.updateX(newLeft) - self.updateWidth(newWidth) } /** The horizontal center anchor of the instance. - Setting its value has the same effect of invoking `setCenterX(_:offset:)` with an offset equal to `.zero` + Setting its value sets the view's horizontal center position equal to the given anchor */ public var centerX: Anchor { get { @@ -385,71 +326,51 @@ public class PlasticView { } set(newValue) { - setCenterX(newValue) - } - } - - /** - Sets the view's horizontal center position equal to the given anchor - - - parameter anchor: the anchor - - parameter offset: an optional offset to use with respect to the anchor. The default value is `.zero` - */ - public func setCenterX(_ anchor: Anchor, offset: Value = Value.zero) { - self.constraintX = .centerX - - let newCenterX = anchor.coordinate + scaleValue(offset) - var newWidth = scaleValue(self.width) - - if self.oldestConstraintX == .left { - newWidth = max(2.0 * (newCenterX - self.left.coordinate), 0.0) - - } else if self.oldestConstraintX == .right { - newWidth = max(2.0 * (self.right.coordinate - newCenterX), 0.0) + self.constraintX = .centerX + + let newCenterX = newValue.coordinate + var newWidth = scaleValue(self.width) + + if self.oldestConstraintX == .left { + newWidth = max(2.0 * (newCenterX - self.left.coordinate), 0.0) + + } else if self.oldestConstraintX == .right { + newWidth = max(2.0 * (self.right.coordinate - newCenterX), 0.0) + } + + // update coords + self.updateX(newCenterX - newWidth / 2.0) + self.updateWidth(newWidth) } - - // update coords - self.updateX(newCenterX - newWidth / 2.0) - self.updateWidth(newWidth) } /** The vertical center anchor of the instance. - Setting its value has the same effect of invoking `setCenterY(_:offset:)` with an offset equal to `.zero` + Setting its value sets the view's vertical center position equal to the given anchor */ public var centerY: Anchor { get { return Anchor(kind: .centerY, view: self) } - + set(newValue) { - setCenterY(newValue) - } - } - - /** - Sets the view's vertical center position equal to the given anchor - - - parameter anchor: the anchor - - parameter offset: an optional offset to use with respect to the anchor. The default value is `.zero` - */ - public func setCenterY(_ anchor: Anchor, offset: Value = Value.zero) { - self.constraintY = .centerY - - let newCenterY = anchor.coordinate + scaleValue(offset) - var newHeight = scaleValue(self.height) - - if self.oldestConstraintY == .top { - newHeight = max(2.0 * (newCenterY - self.top.coordinate), 0.0) - - } else if self.oldestConstraintY == .bottom { - newHeight = max(2.0 * (self.bottom.coordinate - newCenterY), 0.0) + self.constraintY = .centerY + + let newCenterY = newValue.coordinate + var newHeight = scaleValue(self.height) + + if self.oldestConstraintY == .top { + newHeight = max(2.0 * (newCenterY - self.top.coordinate), 0.0) + + } else if self.oldestConstraintY == .bottom { + newHeight = max(2.0 * (self.bottom.coordinate - newCenterY), 0.0) + } + + // update coords + self.updateY(newCenterY - newHeight / 2.0) + self.updateHeight(newHeight) } - - // update coords - self.updateY(newCenterY - newHeight / 2.0) - self.updateHeight(newHeight) } /// The size of the instance diff --git a/Katana/Plastic/Size.swift b/Katana/Plastic/Size.swift index 383b5023..655e9ab5 100644 --- a/Katana/Plastic/Size.swift +++ b/Katana/Plastic/Size.swift @@ -16,7 +16,7 @@ public struct Size: Equatable { public let height: Value /// an instance of `Size` where both the width and the height are zero - public static let zero = Size(0, 0) + public static let zero: Size = .scalable(0, 0) /** Creates an instance of `Size` where both widht and height are fixed @@ -42,36 +42,6 @@ public struct Size: Equatable { return Size(width: .scalable(width), height: .scalable(height)) } - /** - Creates an instance of `Size` where both widht and height are scalable - - - parameter width: the value of the width - - parameter height: the value of the height - - - returns: an instance of `Size` where both width and height are scalable - - - warning: Always prefer the static method `scalable(_:_:)` instead of this constructor - */ - public init(_ width: CGFloat, _ height: CGFloat) { - self.width = Value(width) - self.height = Value(height) - } - - /** - Creates an instance of `Size` with the given values - - - parameter scalableWidth: the scalable part of width - - parameter fixedWidth: the fixed part of width - - parameter scalableHeight: the scalable part of height - - parameter fixedHeight: the fixed part of height - - - returns: an instance of `Size` with the given values - */ - public init(scalableWidth: CGFloat, fixedWidth: CGFloat, scalableHeight: CGFloat, fixedHeight: CGFloat) { - self.width = Value(scalable: scalableWidth, fixed: fixedWidth) - self.height = Value(scalable: scalableHeight, fixed: fixedHeight) - } - /** Creates an instance of `Size` with the given value diff --git a/Katana/Plastic/Value.swift b/Katana/Plastic/Value.swift index 5f971cf9..c0396314 100644 --- a/Katana/Plastic/Value.swift +++ b/Katana/Plastic/Value.swift @@ -28,7 +28,7 @@ public struct Value: Equatable { } /// an instance of `Value` with a value equals to 0 - public static let zero = Value(0) + public static let zero: Value = .scalable(0) /** Creates a fixed instance of `Value` @@ -37,7 +37,7 @@ public struct Value: Equatable { - returns: an instance of `Value` with the given fixed value */ public static func fixed(_ fixed: CGFloat) -> Value { - return Value.init(scalable: 0, fixed: fixed) + return Value(scalable: 0, fixed: fixed) } /** @@ -47,20 +47,7 @@ public struct Value: Equatable { - returns: an instance of `Value` with the given scalable value */ public static func scalable(_ scalable: CGFloat) -> Value { - return Value.init(scalable: scalable, fixed: 0) - } - - /** - Creates a scalable instance of `Value` - - - parameter scalable: the value of the instance - - returns: an instance of `Value` with the given scalable value - - - warning: Always prefer the static method `scalable(_:)` instead of this constructor - */ - public init(_ scalable: CGFloat) { - self.scalable = scalable - self.fixed = 0 + return Value(scalable: scalable, fixed: 0) } /** @@ -111,6 +98,20 @@ public struct Value: Equatable { public static func * (lhs: Value, rhs: CGFloat) -> Value { return Value(scalable: lhs.scalable * rhs, fixed: lhs.fixed * rhs) } + + /** + Implements the multiplication assignment for the `Value` instances + + - parameter lhs: the `Value` instance that will be updated by multiplying itself by `rhs` + - parameter rhs: the value by which `lhs` will be multiplied + + - warning: this method is different from `scale(by:)` since it scales both + scalable and fixed parts, whereas `scale(by:)` scales only the scalable + part + */ + public static func *= (lhs: inout Value, rhs: CGFloat) { + lhs = lhs * rhs + } /** Implements the addition for the `Value` instances @@ -122,6 +123,37 @@ public struct Value: Equatable { public static func + (lhs: Value, rhs: Value) -> Value { return Value(scalable: lhs.scalable + rhs.scalable, fixed: lhs.fixed + rhs.fixed) } + + /** + Implements addition assignment for the `Value` instances + + - parameter lhs: the `Value` instance that will be updated by adding `rhs` to itself + - parameter rhs: the `Value` instance that will be added to `lhs` + */ + public static func += (lhs: inout Value, rhs: Value) { + lhs = lhs + rhs + } + + /** + Implements the subtraction for the `Value` instances + + - parameter lhs: the first instance + - parameter rhs: the second instance + - returns: an instance of `Value` where the fixed and scalable parts are the difference of the parts of the two operators + */ + public static func - (lhs: Value, rhs: Value) -> Value { + return Value(scalable: lhs.scalable - rhs.scalable, fixed: lhs.fixed - rhs.fixed) + } + + /** + Implements subtraction assignment for the `Value` instances + + - parameter lhs: the `Value` instance that will be updated by subtracting `rhs` to itself + - parameter rhs: the `Value` instance that will be subtracted to `lhs` + */ + public static func -= (lhs: inout Value, rhs: Value) { + lhs = lhs - rhs + } /** Implements the division for the `Value` instances @@ -133,6 +165,16 @@ public struct Value: Equatable { public static func / (lhs: Value, rhs: CGFloat) -> Value { return Value(scalable: lhs.scalable / rhs, fixed: lhs.fixed / rhs) } + + /** + Implements the division assignment for the `Value` instance + + - parameter lhs: the `Value` instance that will be updated by dividing itself by `rhs` + - parameter rhs: the value by which `lhs` will be divided + */ + public static func /= (lhs: inout Value, rhs: CGFloat) { + lhs = lhs / rhs + } /** Imlementation of the `Equatable` protocol. diff --git a/KatanaTests/Plastic/PlasticBasicLayoutTests.swift b/KatanaTests/Plastic/PlasticBasicLayoutTests.swift index 219488f5..89479aa7 100644 --- a/KatanaTests/Plastic/PlasticBasicLayoutTests.swift +++ b/KatanaTests/Plastic/PlasticBasicLayoutTests.swift @@ -69,15 +69,15 @@ class PlasticBasicLayoutTests: XCTestCase { XCTAssertEqual(v1.frame.origin.y, v2Frame.origin.y) // margin fixed - v1.setTop(v2.top, offset: .fixed(50)) + v1.top = v2.top + .fixed(50) XCTAssertEqual(v1.frame.origin.y, v2Frame.origin.y + 50) // margin scalable - v1.setTop(v2.top, offset: .scalable(50)) + v1.top = v2.top + .scalable(50) XCTAssertEqual(v1.frame.origin.y, v2Frame.origin.y + 50 * multiplier) // negative margin - v1.setTop(v2.top, offset: .scalable(-50)) + v1.top = v2.top + .scalable(-50) XCTAssertEqual(v1.frame.origin.y, v2Frame.origin.y - 50 * multiplier) } @@ -95,15 +95,15 @@ class PlasticBasicLayoutTests: XCTestCase { XCTAssertEqual(v1.frame.origin.x, v2Frame.origin.x) // margin fixed - v1.setLeft(v2.left, offset: .fixed(50)) + v1.left = v2.left + .fixed(50) XCTAssertEqual(v1.frame.origin.x, v2Frame.origin.x + 50) // margin scalable - v1.setLeft(v2.left, offset: .scalable(50)) + v1.left = v2.left + .scalable(50) XCTAssertEqual(v1.frame.origin.x, v2Frame.origin.x + 50 * multiplier) // negative margin - v1.setLeft(v2.left, offset: .scalable(-50)) + v1.left = v2.left + .scalable(-50) XCTAssertEqual(v1.frame.origin.x, v2Frame.origin.x - 50 * multiplier) } @@ -148,15 +148,15 @@ y v | | | | XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height - v1.frame.size.height) // margin fixed - v1.setBottom(v2.bottom, offset: .fixed(50)) + v1.bottom = v2.bottom + .fixed(50) XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height - v1.frame.size.height + 50) // margin scalable - v1.setBottom(v2.bottom, offset: .scalable(50)) + v1.bottom = v2.bottom + .scalable(50) XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height - v1.frame.size.height + 50 * multiplier) // negative margin - v1.setBottom(v2.bottom, offset: .scalable(-50)) + v1.bottom = v2.bottom + .scalable(-50) XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height - v1.frame.size.height - 50 * multiplier) } @@ -200,15 +200,15 @@ y v XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width - v1.frame.size.width) // margin fixed - v1.setRight(v2.right, offset: .fixed(50)) + v1.right = v2.right + .fixed(50) XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width - v1.frame.size.width + 50) // margin scalable - v1.setRight(v2.right, offset: .scalable(50)) + v1.right = v2.right + .scalable(50) XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width - v1.frame.size.width + 50 * multiplier) // negative - v1.setRight(v2.right, offset: .scalable(-50)) + v1.right = v2.right + .scalable(-50) XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width - v1.frame.size.width - 50 * multiplier) } @@ -254,15 +254,15 @@ y v XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width / 2.0 - v1.frame.size.width / 2.0) // margin fixed - v1.setCenterX(v2.centerX, offset: .fixed(50)) + v1.centerX = v2.centerX + .fixed(50) XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width / 2.0 - v1.frame.size.width / 2.0 + 50) // margin scalable - v1.setCenterX(v2.centerX, offset: .scalable(50)) + v1.centerX = v2.centerX + .scalable(50) XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width / 2.0 - v1.frame.size.width / 2.0 + 50 * multiplier) // negative margin - v1.setCenterX(v2.centerX, offset: .scalable(-50)) + v1.centerX = v2.centerX + .scalable(-50) XCTAssertEqual(v1.frame.origin.x, v2.frame.origin.x + v2.frame.size.width / 2.0 - v1.frame.size.width / 2.0 - 50 * multiplier) } @@ -308,16 +308,26 @@ y v XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height / 2.0 - v1.frame.size.height / 2.0) // margin fixed - v1.setCenterY(v2.centerY, offset: .fixed(50)) + v1.centerY = v2.centerY + .fixed(50) XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height / 2.0 - v1.frame.size.height / 2.0 + 50) // margin scalable - v1.setCenterY(v2.centerY, offset: .scalable(50)) + v1.centerY = v2.centerY + .scalable(50) XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height / 2.0 - v1.frame.size.height / 2.0 + 50 * multiplier) + + // margin scalable with CGFloat + v1.centerY = v2.centerY + 150 + XCTAssertEqual(v1.frame.origin.y, + v2.frame.origin.y + v2.frame.size.height / 2.0 - v1.frame.size.height / 2.0 + 150 * multiplier) + + // negative margin scalable with CGFloat + v1.centerY = v2.centerY - 150 + XCTAssertEqual(v1.frame.origin.y, + v2.frame.origin.y + v2.frame.size.height / 2.0 - v1.frame.size.height / 2.0 - 150 * multiplier) // negative margin - v1.setCenterY(v2.centerY, offset: .scalable(-50)) + v1.centerY = v2.centerY + .scalable(-50) XCTAssertEqual(v1.frame.origin.y, v2.frame.origin.y + v2.frame.size.height / 2.0 - v1.frame.size.height / 2.0 - 50 * multiplier) } @@ -335,4 +345,5 @@ y v v1.size = .scalable(300, 300) XCTAssertEqual(v1.frame.size, CGSize(width: 300 * multiplier, height: 300 * multiplier)) } + } diff --git a/KatanaTests/Plastic/PlasticDimensionsTests.swift b/KatanaTests/Plastic/PlasticDimensionsTests.swift index 3de2fbe3..44dac511 100644 --- a/KatanaTests/Plastic/PlasticDimensionsTests.swift +++ b/KatanaTests/Plastic/PlasticDimensionsTests.swift @@ -63,14 +63,14 @@ class PlasticDimensionsTests: XCTestCase { } func testSizeShouldBeScalable() { - let size = Size(scalableWidth: 10, fixedWidth: 20, scalableHeight: 100, fixedHeight: 300) + let size = Size(width: Value(scalable: 10, fixed: 20), height: Value(scalable: 100, fixed: 300)) let scaled = size.scale(by: 100) XCTAssertEqual(scaled.width, 10 * 100 + 20) XCTAssertEqual(scaled.height, 100 * 100 + 300) } func testSizeCanBeMutliplied() { - let size = Size(scalableWidth: 10, fixedWidth: 20, scalableHeight: 100, fixedHeight: 300) + let size = Size(width: Value(scalable: 10, fixed: 20), height: Value(scalable: 100, fixed: 300)) let multipliedSize = size * 100 XCTAssertEqual(multipliedSize.width.scalable, 10 * 100) XCTAssertEqual(multipliedSize.width.fixed, 20 * 100) @@ -79,8 +79,8 @@ class PlasticDimensionsTests: XCTestCase { } func testSizeCanBeAdded() { - let size1 = Size(scalableWidth: 10, fixedWidth: 20, scalableHeight: 100, fixedHeight: 300) - let size2 = Size(scalableWidth: 20, fixedWidth: 30, scalableHeight: 90, fixedHeight: 10) + let size1 = Size(width: Value(scalable: 10, fixed: 20), height: Value(scalable: 100, fixed: 300)) + let size2 = Size(width: Value(scalable: 20, fixed: 30), height: Value(scalable: 90, fixed: 10)) let total = size1 + size2 XCTAssertEqual(total.width.scalable, 10 + 20) @@ -90,7 +90,7 @@ class PlasticDimensionsTests: XCTestCase { } func testSizeCanBeDivided() { - let size = Size(scalableWidth: 10, fixedWidth: 20, scalableHeight: 100, fixedHeight: 300) + let size = Size(width: Value(scalable: 10, fixed: 20), height: Value(scalable: 100, fixed: 300)) let dividedSize = size / 100 XCTAssertEqual(dividedSize.width.scalable, 10 / 100) XCTAssertEqual(dividedSize.width.fixed, 20 / 100) @@ -107,17 +107,11 @@ class PlasticDimensionsTests: XCTestCase { } func testEdgeInsetsShouldBeScalable() { - let insets = EdgeInsets( - scalableTop: 10, - fixedTop: 20, - scalableLeft: 100, - fixedLeft: 300, - scalableBottom: 200, - fixedBottom: 50, - scalableRight: 100, - fixedRight: 99 - ) - + let insets = EdgeInsets(top: Value(scalable: 10, fixed: 20), + left: Value(scalable: 100, fixed: 300), + bottom: Value(scalable: 200, fixed: 50), + right: Value(scalable: 100, fixed: 99)) + let scaled = insets.scale(by: 5) XCTAssertEqual(scaled.top, 10 * 5 + 20) XCTAssertEqual(scaled.left, 100 * 5 + 300) @@ -126,16 +120,10 @@ class PlasticDimensionsTests: XCTestCase { } func testEdgeInsetsCanBeMutliplied() { - let insets = EdgeInsets( - scalableTop: 10, - fixedTop: 20, - scalableLeft: 100, - fixedLeft: 300, - scalableBottom: 200, - fixedBottom: 50, - scalableRight: 100, - fixedRight: 99 - ) + let insets = EdgeInsets(top: Value(scalable: 10, fixed: 20), + left: Value(scalable: 100, fixed: 300), + bottom: Value(scalable: 200, fixed: 50), + right: Value(scalable: 100, fixed: 99)) let multiplied = insets * 5 XCTAssertEqual(multiplied.top.scalable, 10 * 5) @@ -149,27 +137,15 @@ class PlasticDimensionsTests: XCTestCase { } func testEdgeInsetsCanBeAdded() { - let value1 = EdgeInsets( - scalableTop: 10, - fixedTop: 20, - scalableLeft: 100, - fixedLeft: 300, - scalableBottom: 200, - fixedBottom: 50, - scalableRight: 100, - fixedRight: 99 - ) - - let value2 = EdgeInsets( - scalableTop: 11, - fixedTop: 201, - scalableLeft: 10, - fixedLeft: 12, - scalableBottom: 56, - fixedBottom: 11, - scalableRight: 8, - fixedRight: 991 - ) + let value1 = EdgeInsets(top: Value(scalable: 10, fixed: 20), + left: Value(scalable: 100, fixed: 300), + bottom: Value(scalable: 200, fixed: 50), + right: Value(scalable: 100, fixed: 99)) + + let value2 = EdgeInsets(top: Value(scalable: 11, fixed: 201), + left: Value(scalable: 10, fixed: 12), + bottom: Value(scalable: 56, fixed: 11), + right: Value(scalable: 8, fixed: 991)) let sum = value1 + value2 @@ -184,16 +160,10 @@ class PlasticDimensionsTests: XCTestCase { } func testEdgeInsetsCanBeDivided() { - let insets = EdgeInsets( - scalableTop: 10, - fixedTop: 20, - scalableLeft: 100, - fixedLeft: 300, - scalableBottom: 200, - fixedBottom: 50, - scalableRight: 100, - fixedRight: 99 - ) + let insets = EdgeInsets(top: Value(scalable: 10, fixed: 20), + left: Value(scalable: 100, fixed: 300), + bottom: Value(scalable: 200, fixed: 50), + right: Value(scalable: 100, fixed: 99)) let divided = insets / 5 XCTAssertEqual(divided.top.scalable, 10 / 5)