1+ import Foundation
2+
13public enum LayoutSystem {
24 static func width( forHeight height: Int , aspectRatio: Double ) -> Int {
35 roundSize ( Double ( height) * aspectRatio)
@@ -11,6 +13,18 @@ public enum LayoutSystem {
1113 Int ( size. rounded ( . towardZero) )
1214 }
1315
16+ /// Clamps a value to a range given optional lower and upper bounds.
17+ static func clamp< T: Comparable > ( _ value: T , minimum: T ? = nil , maximum: T ? = nil ) -> T {
18+ var value = value
19+ if let minimum {
20+ value = max ( value, minimum)
21+ }
22+ if let maximum {
23+ value = min ( value, maximum)
24+ }
25+ return value
26+ }
27+
1428 static func aspectRatio( of frame: SIMD2 < Double > ) -> Double {
1529 if frame. x == 0 || frame. y == 0 {
1630 // Even though we could technically compute an aspect ratio when the
@@ -47,14 +61,14 @@ public enum LayoutSystem {
4761 public struct LayoutableChild {
4862 private var computeLayout :
4963 (
50- _ proposedSize: SIMD2 < Int > ,
64+ _ proposedSize: SizeProposal ,
5165 _ environment: EnvironmentValues
5266 ) -> ViewLayoutResult
5367 private var _commit : ( ) -> ViewLayoutResult
5468 var tag : String ?
5569
5670 public init (
57- computeLayout: @escaping ( SIMD2 < Int > , EnvironmentValues ) -> ViewLayoutResult ,
71+ computeLayout: @escaping ( SizeProposal , EnvironmentValues ) -> ViewLayoutResult ,
5872 commit: @escaping ( ) -> ViewLayoutResult ,
5973 tag: String ? = nil
6074 ) {
@@ -64,7 +78,7 @@ public enum LayoutSystem {
6478 }
6579
6680 public func computeLayout(
67- proposedSize: SIMD2 < Int > ,
81+ proposedSize: SizeProposal ,
6882 environment: EnvironmentValues ,
6983 dryRun: Bool = false
7084 ) -> ViewLayoutResult {
@@ -84,7 +98,7 @@ public enum LayoutSystem {
8498 public static func computeStackLayout< Backend: AppBackend > (
8599 container: Backend . Widget ,
86100 children: [ LayoutableChild ] ,
87- proposedSize: SIMD2 < Int > ,
101+ proposedSize: SizeProposal ,
88102 environment: EnvironmentValues ,
89103 backend: Backend ,
90104 inheritStackLayoutParticipation: Bool = false
@@ -103,7 +117,7 @@ public enum LayoutSystem {
103117 var isHidden = [ Bool] ( repeating: false , count: children. count)
104118 let flexibilities = children. enumerated ( ) . map { i, child in
105119 let result = child. computeLayout (
106- proposedSize: proposedSize ,
120+ proposedSize: . ideal ,
107121 environment: environment
108122 )
109123 isHidden [ i] = !result. participatesInStackLayouts
@@ -118,11 +132,19 @@ public enum LayoutSystem {
118132 !hidden
119133 } . count
120134 let totalSpacing = max ( visibleChildrenCount - 1 , 0 ) * spacing
121- let sortedChildren = zip ( children. enumerated ( ) , flexibilities)
122- . sorted { first, second in
123- first. 1 <= second. 1
124- }
125- . map ( \. 0 )
135+
136+ let sortedChildren : [ ( offset: Int , element: LayoutSystem . LayoutableChild ) ]
137+ if orientation == . vertical && proposedSize. height == nil
138+ || orientation == . horizontal && proposedSize. width == nil
139+ {
140+ sortedChildren = Array ( children. enumerated ( ) )
141+ } else {
142+ sortedChildren = zip ( children. enumerated ( ) , flexibilities)
143+ . sorted { first, second in
144+ first. 1 <= second. 1
145+ }
146+ . map ( \. 0 )
147+ }
126148
127149 var spaceUsedAlongStackAxis = 0
128150 var childrenRemaining = visibleChildrenCount
@@ -149,25 +171,35 @@ public enum LayoutSystem {
149171 continue
150172 }
151173
152- let proposedWidth : Double
153- let proposedHeight : Double
174+ let proposedWidth : Double ?
175+ let proposedHeight : Double ?
154176 switch orientation {
155177 case . horizontal:
156- proposedWidth =
157- Double ( max ( proposedSize. x - spaceUsedAlongStackAxis - totalSpacing, 0 ) )
158- / Double( childrenRemaining)
159- proposedHeight = Double ( proposedSize. y)
178+ if let parentProposedWidth = proposedSize. width {
179+ proposedWidth = Double ( max (
180+ parentProposedWidth - spaceUsedAlongStackAxis - totalSpacing,
181+ 0
182+ ) ) / Double( childrenRemaining)
183+ } else {
184+ proposedWidth = nil
185+ }
186+ proposedHeight = proposedSize. height. map ( Double . init)
160187 case . vertical:
161- proposedHeight =
162- Double ( max ( proposedSize. y - spaceUsedAlongStackAxis - totalSpacing, 0 ) )
163- / Double( childrenRemaining)
164- proposedWidth = Double ( proposedSize. x)
188+ if let parentProposedHeight = proposedSize. height {
189+ proposedHeight = Double ( max (
190+ parentProposedHeight - spaceUsedAlongStackAxis - totalSpacing,
191+ 0
192+ ) ) / Double( childrenRemaining)
193+ } else {
194+ proposedHeight = nil
195+ }
196+ proposedWidth = proposedSize. width. map ( Double . init)
165197 }
166198
167199 let childResult = child. computeLayout (
168- proposedSize: SIMD2 < Int > (
169- Int ( proposedWidth . rounded ( . towardZero) ) ,
170- Int ( proposedHeight . rounded ( . towardZero) )
200+ proposedSize: SizeProposal (
201+ proposedWidth . map { Int ( $0 . rounded ( . towardZero) ) } ,
202+ proposedHeight . map { Int ( $0 . rounded ( . towardZero) ) }
171203 ) ,
172204 environment: environment
173205 )
0 commit comments