Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
tevelee committed Jul 14, 2024
1 parent e9ef30b commit 02c969a
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 51 deletions.
12 changes: 10 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ let package = Package(
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")
],
targets: [
.target(name: "Flow", exclude: ["Example"], swiftSettings: [.swiftLanguageVersion(.v6)]),
.testTarget(name: "FlowTests", dependencies: ["Flow"], swiftSettings: [.swiftLanguageVersion(.v6)])
.target(
name: "Flow",
exclude: ["Example"],
swiftSettings: [.swiftLanguageVersion(.v6)]
),
.testTarget(
name: "FlowTests",
dependencies: ["Flow"],
swiftSettings: [.swiftLanguageVersion(.v6)]
)
]
)
77 changes: 37 additions & 40 deletions Sources/Flow/Internal/Layout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ struct FlowLayout: Sendable {
private struct ItemWithSpacing<T> {
var item: T
var size: Size
var spacing: CGFloat = 0
var leadingSpace: CGFloat = 0

mutating func append(_ item: Item, size: Size, spacing: CGFloat) where Self == ItemWithSpacing<Line> {
self.item.append(.init(item: item, size: size, spacing: spacing))
self.item.append(.init(item: item, size: size, leadingSpace: spacing))
self.size = Size(breadth: self.size.breadth + spacing + size.breadth, depth: max(self.size.depth, size.depth))
}
}
Expand All @@ -37,11 +37,10 @@ struct FlowLayout: Sendable {
guard !subviews.isEmpty else { return .zero }

let lines = calculateLayout(in: proposedSize, of: subviews, cache: cache)
let spacings = lines.sum(of: \.spacing)
let size = lines
var size = lines
.map(\.size)
.reduce(.zero, breadth: max, depth: +)
.adding(spacings, on: .vertical)
size[.vertical] += lines.sum(of: \.leadingSpace)
return CGSize(size: size, axis: axis)
}

Expand All @@ -54,57 +53,55 @@ struct FlowLayout: Sendable {
) {
guard !subviews.isEmpty else { return }

var reversedBreadth = self.reversedBreadth
var target = bounds.origin.size(on: axis)
var reversedBreadth = self.reversedBreadth

let lines = calculateLayout(in: proposal, of: subviews, cache: cache)

for line in lines {
if reversedDepth {
target.depth -= line.size.depth + line.spacing
} else {
target.depth += line.spacing
}
if reversedBreadth {
target.breadth = switch axis {
case .horizontal: bounds.maxX
case .vertical: bounds.maxY
}
} else {
target.breadth = switch axis {
case .horizontal: bounds.minX
case .vertical: bounds.minY
}
}
for item in line.item {
if reversedBreadth {
target.breadth -= item.size.breadth + item.spacing
} else {
target.breadth += item.spacing
adjust(&target, for: line, on: .vertical, reversed: reversedDepth) { target in
target.breadth = reversedBreadth ? bounds.maximumValue(on: axis) : bounds.minimumValue(on: axis)

for item in line.item {
adjust(&target, for: item, on: .horizontal, reversed: reversedBreadth) { target in
alignAndPlace(item, in: line, at: target)
}
}
alignAndPlace(item, in: line, at: target)
if !reversedBreadth {
target.breadth += item.size.breadth

if alternatingReversedBreadth {
reversedBreadth.toggle()
}
}
if alternatingReversedBreadth {
reversedBreadth.toggle()
}
if !reversedDepth {
target.depth += line.size.depth
}
}
}

@usableFromInline
func makeCache(_ subviews: some Subviews) -> FlowLayoutCache {
FlowLayoutCache(subviews, axis: axis)
}

private func adjust<T>(
_ target: inout Size,
for item: ItemWithSpacing<T>,
on axis: Axis,
reversed: Bool,
body: (inout Size) -> Void
) {
let leadingSpace = item.leadingSpace
let size = item.size[axis]
target[axis] += reversed ? -leadingSpace-size : leadingSpace
body(&target)
target[axis] += reversed ? 0 : size
}

private func alignAndPlace(
_ item: Line.Element,
in line: Lines.Element,
at placement: Size
) {
var placement = placement
let proposedSize = ProposedViewSize(size: Size(breadth: item.size.breadth, depth: line.size.depth), axis: axis)
let size = Size(breadth: item.size.breadth, depth: line.size.depth)
let proposedSize = ProposedViewSize(size: size, axis: axis)
let depth = item.size.depth
if depth > 0 {
placement.depth += (align(item.item.subview.dimensions(proposedSize)) / depth) * (line.size.depth - depth)
Expand Down Expand Up @@ -167,7 +164,7 @@ struct FlowLayout: Sendable {
}
for index in lines.indices.dropFirst() {
let spacing = self.lineSpacing ?? lineSpacings[index].distance(to: lineSpacings[index.advanced(by: -1)], along: axis.perpendicular)
lines[index].spacing = spacing
lines[index].leadingSpace = spacing
}
}

Expand All @@ -188,7 +185,7 @@ struct FlowLayout: Sendable {
.map { offset, subview in
SubviewProperties(
indexInLine: offset,
spacing: subview.spacing,
spacing: subview.leadingSpace,
cache: subview.item.cache
)
}
Expand Down Expand Up @@ -225,7 +222,7 @@ struct FlowLayout: Sendable {
if justification.isStretchingSpaces {
let distributedSpace = remainingSpace / Double(count - 1)
for index in line.item.indices.dropFirst() {
line.item[index].spacing += distributedSpace
line.item[index].leadingSpace += distributedSpace
remainingSpace -= distributedSpace
}
}
Expand Down
6 changes: 6 additions & 0 deletions Sources/Flow/Internal/LineBreaking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ protocol LineBreaking {

@usableFromInline
struct FlowLineBreaker: LineBreaking {
@inlinable
init() {}

@inlinable
func wrapItemsToLines(sizes: [CGFloat], spacings: [CGFloat], in availableSpace: CGFloat) -> [Int] {
var breakpoints: [Int] = []
Expand All @@ -34,6 +37,9 @@ struct FlowLineBreaker: LineBreaking {

@usableFromInline
struct KnuthPlassLineBreaker: LineBreaking {
@inlinable
init() {}

@inlinable
func wrapItemsToLines(sizes: [CGFloat], spacings: [CGFloat], in availableSpace: CGFloat) -> [Int] {
let count = sizes.count
Expand Down
29 changes: 21 additions & 8 deletions Sources/Flow/Internal/Size.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,6 @@ struct Size: Sendable {
@usableFromInline
static let zero = Size(breadth: 0, depth: 0)

@usableFromInline
func adding(_ value: CGFloat, on axis: Axis) -> Size {
var size = self
size[axis] += value
return size
}

@usableFromInline
subscript(axis: Axis) -> CGFloat {
get {
Expand All @@ -34,7 +27,8 @@ struct Size: Sendable {
}
}

private func keyPath(on axis: Axis) -> WritableKeyPath<Size, CGFloat> {
@usableFromInline
func keyPath(on axis: Axis) -> WritableKeyPath<Size, CGFloat> {
switch axis {
case .horizontal: \.breadth
case .vertical: \.depth
Expand Down Expand Up @@ -95,6 +89,7 @@ extension CGSize: FixedOrientation2DCoordinate {
}
}

@inlinable
static var infinity: CGSize {
CGSize(
width: CGFloat.infinity,
Expand All @@ -117,3 +112,21 @@ extension ProposedViewSize: FixedOrientation2DCoordinate {
}
}
}

extension CGRect {
@inlinable
func minimumValue(on axis: Axis) -> CGFloat {
switch axis {
case .horizontal: minX
case .vertical: minY
}
}

@inlinable
func maximumValue(on axis: Axis) -> CGFloat {
switch axis {
case .horizontal: maxX
case .vertical: maxY
}
}
}
2 changes: 1 addition & 1 deletion Tests/FlowTests/Utils/TestSubview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SwiftUI
import XCTest
@testable import Flow

final class TestSubview: Subview, CustomStringConvertible {
final class TestSubview: Flow.Subview, CustomStringConvertible {
var spacing = ViewSpacing()
var priority: Double = 1
var placement: (position: CGPoint, size: CGSize)?
Expand Down

0 comments on commit 02c969a

Please sign in to comment.