From f715337425971b51188e16e90dcb7696ef63a5c7 Mon Sep 17 00:00:00 2001
From: Daniel Tull
Date: Tue, 24 Dec 2024 13:54:01 +0000
Subject: [PATCH] HStack 2
---
Sources/TerminalUI/Layouts/HStack.swift | 68 +++++++++++++++++++
.../TerminalUI/Primitives/Dimensions.swift | 6 ++
Sources/TerminalUI/Views/HStack.swift | 47 -------------
3 files changed, 74 insertions(+), 47 deletions(-)
create mode 100644 Sources/TerminalUI/Layouts/HStack.swift
delete mode 100644 Sources/TerminalUI/Views/HStack.swift
diff --git a/Sources/TerminalUI/Layouts/HStack.swift b/Sources/TerminalUI/Layouts/HStack.swift
new file mode 100644
index 0000000..c0e5152
--- /dev/null
+++ b/Sources/TerminalUI/Layouts/HStack.swift
@@ -0,0 +1,68 @@
+
+struct HStack {
+ private let children: [any View]
+ @Mutable private var sizes: [Size] = []
+}
+
+extension HStack: Builtin, View {
+
+ func size(
+ for proposal: ProposedSize,
+ environment: EnvironmentValues
+ ) -> Size {
+
+ let flexibility = children.map { child in
+ let min = ProposedSize(width: 0, height: proposal.height)
+ let max = ProposedSize(width: .max, height: proposal.height)
+ let smallest = child._size(for: min)
+ let largest = child._size(for: max)
+ return largest.width - smallest.width
+ }
+
+ var indices = children.indices
+ .sorted { flexibility[$0] < flexibility[$1] }
+
+ sizes = Array(repeating: .zero, count: children.count)
+ var remaining = proposal.width
+
+ while !indices.isEmpty {
+
+ let proposal = ProposedSize(
+ width: remaining / indices.count,
+ height: proposal.height)
+
+ let index = indices.removeFirst()
+
+ let child = children[index]
+ let size = child._size(for: proposal, environment: environment)
+ sizes[index] = size
+ remaining -= size.width
+ if remaining < 0 { remaining = 0 }
+ }
+
+ let width = sizes.map(\.width).reduce(0, +)
+ let height = sizes.map(\.height).reduce(0, +)
+ return Size(width: width, height: height)
+ }
+
+ func render(
+ in canvas: any Canvas,
+ size: Size,
+ environment: EnvironmentValues
+ ) {
+ var x: Horizontal = 0
+ for (child, childSize) in zip(children, sizes) {
+ let canvas = canvas.translateBy(x: x, y: 0)
+ child._render(in: canvas, size: childSize, environment: environment)
+ x += childSize.width
+ }
+ }
+}
+
+extension Horizontal {
+ fileprivate static var max: Self { Self(Int.max) }
+}
+
+extension Size {
+ fileprivate static var zero: Size { Size(width: 0, height: 0) }
+}
diff --git a/Sources/TerminalUI/Primitives/Dimensions.swift b/Sources/TerminalUI/Primitives/Dimensions.swift
index 0b26fa9..0679777 100644
--- a/Sources/TerminalUI/Primitives/Dimensions.swift
+++ b/Sources/TerminalUI/Primitives/Dimensions.swift
@@ -56,6 +56,12 @@ extension Horizontal {
}
}
+extension Horizontal {
+ static func / (lhs: Horizontal, rhs: Int) -> Horizontal {
+ Horizontal(lhs.value / rhs)
+ }
+}
+
// MARK: - Vertical
/// A measurement of the vertical dimension.
diff --git a/Sources/TerminalUI/Views/HStack.swift b/Sources/TerminalUI/Views/HStack.swift
deleted file mode 100644
index 4733ddf..0000000
--- a/Sources/TerminalUI/Views/HStack.swift
+++ /dev/null
@@ -1,47 +0,0 @@
-
-struct HStack {
- private let children: [any View]
- @Mutable private var sizes: [Size] = []
-}
-
-extension HStack: Builtin, View {
-
- func size(
- for proposal: ProposedSize,
- environment: EnvironmentValues
- ) -> Size {
-
- let flexibility: [Horizontal] = children.map { child in
- let min = ProposedSize(width: 0, height: proposal.height)
- let max = ProposedSize(width: .max, height: proposal.height)
- let lower = child._size(for: min)
- let upper = child._size(for: max)
- return upper.width - lower.width
- }
-
- var remainingIndices = children.indices
- .sorted { lhs, rhs in flexibility[lhs] < flexibility[rhs] }
-
-
-
-
- Size(width: proposal.width, height: proposal.height)
- }
-
- func render(
- in canvas: any Canvas,
- size: Size,
- environment: EnvironmentValues
- ) {
- var x: Horizontal = 0
- for (child, childSize) in zip(children, sizes) {
- let canvas = canvas.translateBy(x: x, y: 0)
- child._render(in: canvas, size: childSize, environment: environment)
- x += childSize.width
- }
- }
-}
-
-extension Horizontal {
- fileprivate static var max: Self { Self(Int.max) }
-}