Skip to content

Commit

Permalink
AlignmentID
Browse files Browse the repository at this point in the history
  • Loading branch information
danielctull committed Jan 6, 2025
1 parent 10d5b99 commit 2492aec
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 14 deletions.
10 changes: 8 additions & 2 deletions Sources/TerminalUI/Modifiers/Layout/FixedFrame.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ extension View {

public func frame(
width: Horizontal? = nil,
height: Vertical? = nil
height: Vertical? = nil,
alignment: Alignment = .center
) -> some View {
FixedFrame(content: self, width: width, height: height)
FixedFrame(
content: self,
width: width,
height: height,
alignment: alignment)
}
}

Expand All @@ -14,6 +19,7 @@ private struct FixedFrame<Content: View>: Builtin, View {
let content: Content
let width: Horizontal?
let height: Vertical?
let alignment: Alignment

func size(
for proposal: ProposedSize,
Expand Down
81 changes: 73 additions & 8 deletions Sources/TerminalUI/Primitives/Alignment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,83 @@ extension Alignment {
public static var bottomTrailing: Self { Self(horizontal: .trailing, vertical: .bottom) }
}

// MARK: - AlignmentID

public protocol AlignmentID: Equatable {
static func defaultValue(in size: Size) -> Int
}

// MARK: - AlignmentKey

public struct AlignmentKey: Equatable, Hashable, Sendable {

fileprivate let id: any AlignmentID.Type

public static func == (lhs: AlignmentKey, rhs: AlignmentKey) -> Bool {
String(describing: lhs.id) == String(describing: rhs.id)
}

public func hash(into hasher: inout Hasher) {
hasher.combine(String(describing: id))
}
}

// MARK: - Horizontal Alignment

public enum HorizontalAlignment: Equatable, Hashable, Sendable {
case leading
case center
case trailing
public struct HorizontalAlignment: Equatable, Hashable, Sendable {
let id: AlignmentKey
}

extension HorizontalAlignment {
public init(_ id: any AlignmentID.Type) {
self.id = AlignmentKey(id: id)
}
}

extension HorizontalAlignment {
public static var leading: Self { Self(HorizontalLeading.self) }
public static var center: Self { Self(HorizontalCenter.self) }
public static var trailing: Self { Self(HorizontalTrailing.self) }
}

private enum HorizontalLeading: AlignmentID {
static func defaultValue(in size: Size) -> Int { 1 }
}

private enum HorizontalCenter: AlignmentID {
static func defaultValue(in size: Size) -> Int { Int(size.width) / 2 }
}

private enum HorizontalTrailing: AlignmentID {
static func defaultValue(in size: Size) -> Int { Int(size.width) }
}

// MARK: - Vertical Alignment

public enum VerticalAlignment: Equatable, Hashable, Sendable {
case top
case center
case bottom
public struct VerticalAlignment: Equatable, Hashable, Sendable {
let id: AlignmentKey
}

extension VerticalAlignment {
public init(_ id: any AlignmentID.Type) {
self.id = AlignmentKey(id: id)
}
}

extension VerticalAlignment {
public static var top: Self { Self(VerticalTop.self) }
public static var center: Self { Self(VerticalCenter.self) }
public static var bottom: Self { Self(VerticalBottom.self) }
}

private enum VerticalTop: AlignmentID {
static func defaultValue(in size: Size) -> Int { 1 }
}

private enum VerticalCenter: AlignmentID {
static func defaultValue(in size: Size) -> Int { Int(size.height) / 2 }
}

private enum VerticalBottom: AlignmentID {
static func defaultValue(in size: Size) -> Int { Int(size.height) }
}
6 changes: 6 additions & 0 deletions Sources/TerminalUI/Primitives/Dimensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,9 @@ extension Vertical {
Vertical(-vertical.value)
}
}

extension Int {
init(_ vertical: Vertical) {
self = vertical.value
}
}
8 changes: 4 additions & 4 deletions Sources/TerminalUI/Primitives/Size.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

package struct Size {
public struct Size {

package let width: Horizontal
package let height: Vertical
public let width: Horizontal
public let height: Vertical

package init(width: Horizontal, height: Vertical) {
public init(width: Horizontal, height: Vertical) {
self.width = width
self.height = height
}
Expand Down
24 changes: 24 additions & 0 deletions Tests/TerminalUITests/Modifiers/Layout/FixedFrameTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,28 @@ struct FixedFrameTests {
Position(x: 2, y: 2): pixel,
])
}

@Test("alignment", arguments: Array<(
Alignment, Horizontal, Vertical
)>([
(.topLeading, 1, 1),
(.top, 2, 1),
(.topTrailing, 3, 1),
(.leading, 1, 2),
(.center, 2, 2),
(.trailing, 3, 2),
(.bottomLeading, 1, 3),
(.bottom, 2, 3),
(.bottomTrailing, 3, 3),
]))
func alignment(alignment: Alignment, x: Horizontal, y: Vertical) {

canvas.render {
view
.frame(width: 1, height: 1)
.frame(width: 3, height: 3, alignment: alignment)
}

#expect(canvas.pixels == [Position(x: x, y: y): pixel])
}
}

0 comments on commit 2492aec

Please sign in to comment.