Skip to content

Commit 3b77ec2

Browse files
committed
Fix ViewGraphNode layout caching; fixes fixedSize (+tests)
1 parent 94ff1cc commit 3b77ec2

File tree

2 files changed

+95
-11
lines changed

2 files changed

+95
-11
lines changed

Sources/SwiftCrossUI/ViewGraph/ViewGraphNode.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,16 +218,18 @@ public class ViewGraphNode<NodeView: View, Backend: AppBackend>: Sendable {
218218
// If the view has already been updated this update cycle and claims
219219
// to be fixed size (maximumSize == minimumSize) then reuse the current
220220
// result.
221-
let maximumSize = SIMD2(
222-
currentLayout.size.maximumWidth,
223-
currentLayout.size.maximumHeight
224-
)
225-
let minimumSize = SIMD2(
226-
Double(currentLayout.size.minimumWidth),
227-
Double(currentLayout.size.minimumHeight)
228-
)
229-
if maximumSize == minimumSize {
230-
return currentLayout
221+
if lastProposedSize.concrete != nil && proposedSize.concrete != nil {
222+
let maximumSize = SIMD2(
223+
currentLayout.size.maximumWidth,
224+
currentLayout.size.maximumHeight
225+
)
226+
let minimumSize = SIMD2(
227+
Double(currentLayout.size.minimumWidth),
228+
Double(currentLayout.size.minimumHeight)
229+
)
230+
if maximumSize == minimumSize {
231+
return currentLayout
232+
}
231233
}
232234
}
233235

Tests/SwiftCrossUITests/SwiftCrossUITests.swift

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ struct SwiftCrossUITests {
9191
)
9292
backend.setChild(ofWindow: window, to: viewGraph.rootNode.widget.into())
9393

94+
// We have to run this twice due to the computeLayout/commit change
95+
// to the View protocol. This should get neater once ViewGraph uses
96+
// computeLayout/commit as well instead of updates with dryRun.
97+
_ = viewGraph.update(
98+
proposedSize: SIMD2(200, 200),
99+
environment: environment,
100+
dryRun: true
101+
)
94102
let result = viewGraph.update(
95103
proposedSize: SIMD2(200, 200),
96104
environment: environment,
@@ -111,8 +119,82 @@ struct SwiftCrossUITests {
111119
)
112120
}
113121

114-
/// Snapshots an AppKit view to a TIFF image.
122+
@Test("Ensures that basic AppKitBackend text layout works as expected")
123+
@MainActor
124+
func testTextLayout() {
125+
let backend = AppKitBackend()
126+
let text = Text("Lorem ipsum dolor sit amet")
127+
let widget = text.asWidget(backend: backend)
128+
let environment = EnvironmentValues(backend: backend)
129+
let children = text.children(backend: backend, snapshots: nil, environment: environment)
130+
let idealLayout = text.computeLayout(
131+
widget,
132+
children: children,
133+
proposedSize: .ideal,
134+
environment: environment,
135+
backend: backend
136+
)
137+
let fixedHeightLayout = text.computeLayout(
138+
widget,
139+
children: children,
140+
proposedSize: SizeProposal(idealLayout.size.size.x / 2, nil),
141+
environment: environment,
142+
backend: backend
143+
)
144+
let layout = text.computeLayout(
145+
widget,
146+
proposedSize: SizeProposal(idealLayout.size.size.x / 2, 1000),
147+
environment: environment,
148+
backend: backend
149+
)
150+
#expect(
151+
idealLayout.size.size.y != fixedHeightLayout.size.size.y,
152+
"Halving text width didn't affect text height"
153+
)
154+
#expect(fixedHeightLayout.size == layout.size, "Excess height changed text size")
155+
}
156+
157+
@Test("Ensures that the fixedSize layout works as expected")
115158
@MainActor
159+
func testFixedSizeLayout() {
160+
let backend = AppKitBackend()
161+
let text = Text("Lorem ipsum dolor sit amet")
162+
.fixedSize(horizontal: false, vertical: true)
163+
let window = backend.createWindow(withDefaultSize: SIMD2(200, 200))
164+
let environment = EnvironmentValues(backend: backend)
165+
.with(\.window, window)
166+
let children = text.children(backend: backend, snapshots: nil, environment: environment)
167+
let widget = text.asWidget(children, backend: backend)
168+
let idealLayout = text.computeLayout(
169+
widget,
170+
children: children,
171+
proposedSize: .ideal,
172+
environment: environment,
173+
backend: backend
174+
)
175+
let fixedHeightLayout = text.computeLayout(
176+
widget,
177+
children: children,
178+
proposedSize: SizeProposal(idealLayout.size.size.x / 2, nil),
179+
environment: environment,
180+
backend: backend
181+
)
182+
let layout = text.computeLayout(
183+
widget,
184+
children: children,
185+
proposedSize: SizeProposal(idealLayout.size.size.x / 2, 1000),
186+
environment: environment,
187+
backend: backend
188+
)
189+
#expect(
190+
idealLayout.size.size.y != fixedHeightLayout.size.size.y,
191+
"Halving text width didn't affect text height"
192+
)
193+
#expect(fixedHeightLayout.size == layout.size, "Excess height changed text size")
194+
}
195+
196+
@MainActor
197+
/// Snapshots an AppKit view to a TIFF image.
116198
static func snapshotView(_ view: NSView) throws -> Data {
117199
view.wantsLayer = true
118200
view.layer?.backgroundColor = CGColor.white

0 commit comments

Comments
 (0)