Skip to content

Commit a23c437

Browse files
committed
Use idealSize of content for contentSize windows, fix idealSize propagation
Also fixed some Gtk-specific window resizing issues.
1 parent df2b4e5 commit a23c437

File tree

11 files changed

+106
-20
lines changed

11 files changed

+106
-20
lines changed

Examples/Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/Gtk/Widgets/CustomRootWidget.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import CGtk
2+
import Dispatch
23
import GtkCustomWidgets
34

45
/// A custom widget made specifically for SwiftCrossUI. This widget provides the
@@ -50,7 +51,15 @@ public class CustomRootWidget: Widget {
5051
}
5152

5253
public func setResizeHandler(_ handler: @escaping (Size) -> Void) {
53-
let box = SignalBox1<Size>(callback: handler)
54+
let box = SignalBox1<Size> { size in
55+
// Ensure that the handler can't mess with the current update.
56+
// Otherwise if it goes and updates the whole view hierarchy then
57+
// Gtk gets annoyed cause everything kinda gets pulled out from
58+
// under it.
59+
DispatchQueue.main.async {
60+
handler(size)
61+
}
62+
}
5463
gtk_custom_root_widget_set_resize_callback(
5564
castedPointer(),
5665
{ data, size in

Sources/Gtk/Widgets/PopoverMenu.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ public class PopoverMenu: Popover {
149149
gtk_popover_popup(castedPointer())
150150

151151
gtk_widget_get_preferred_size(widgetPointer, &menuMinimumSize, &menuNaturalSize)
152-
print(menuNaturalSize)
153152

154153
// TODO: Figure out why this is actually happening and whether it's just specific to
155154
// my machines. Probably just some weird menu CSS from the default themes, but

Sources/GtkBackend/GtkBackend.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ public final class GtkBackend: AppBackend {
9393
windowSize.height - childSize.height
9494
)
9595
window.size = Size(
96-
width: decorationsSize.x + newSize.x,
97-
height: decorationsSize.y + newSize.y
96+
width: newSize.x,
97+
height: newSize.y
9898
)
9999
child.preemptAllocatedSize(allocatedWidth: newSize.x, allocatedHeight: newSize.y)
100100
}

Sources/SwiftCrossUI/LayoutSystem.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ public enum LayoutSystem {
150150

151151
let size: SIMD2<Int>
152152
let idealSize: SIMD2<Int>
153+
let idealWidthForProposedHeight: Int
154+
let idealHeightForProposedWidth: Int
153155
let minimumWidth: Int
154156
let minimumHeight: Int
155157
let maximumWidth: Double?
@@ -169,6 +171,10 @@ public enum LayoutSystem {
169171
maximumWidth =
170172
renderedChildren.map(\.maximumWidth).reduce(0, +) + Double(totalSpacing)
171173
maximumHeight = renderedChildren.map(\.maximumHeight).max()
174+
idealWidthForProposedHeight =
175+
renderedChildren.map(\.idealWidthForProposedHeight).reduce(0, +) + totalSpacing
176+
idealHeightForProposedWidth =
177+
renderedChildren.map(\.idealHeightForProposedWidth).max() ?? 0
172178
case .vertical:
173179
size = SIMD2<Int>(
174180
renderedChildren.map(\.size.x).max() ?? 0,
@@ -183,6 +189,10 @@ public enum LayoutSystem {
183189
maximumWidth = renderedChildren.map(\.maximumWidth).max()
184190
maximumHeight =
185191
renderedChildren.map(\.maximumHeight).reduce(0, +) + Double(totalSpacing)
192+
idealWidthForProposedHeight =
193+
renderedChildren.map(\.idealWidthForProposedHeight).max() ?? 0
194+
idealHeightForProposedWidth =
195+
renderedChildren.map(\.idealHeightForProposedWidth).reduce(0, +) + totalSpacing
186196
}
187197

188198
if !dryRun {
@@ -233,6 +243,8 @@ public enum LayoutSystem {
233243
return ViewSize(
234244
size: size,
235245
idealSize: idealSize,
246+
idealWidthForProposedHeight: idealWidthForProposedHeight,
247+
idealHeightForProposedWidth: idealHeightForProposedWidth,
236248
minimumWidth: minimumWidth,
237249
minimumHeight: minimumHeight,
238250
maximumWidth: maximumWidth,

Sources/SwiftCrossUI/Modifiers/Frame.swift

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,40 @@ struct StrictFrameView<Child: View>: TypeSafeView {
109109
backend.setPosition(ofChildAt: 0, in: widget, to: childPosition)
110110
}
111111

112+
let idealWidth: Int
113+
let idealHeight: Int
114+
if let width, let height {
115+
idealWidth = width
116+
idealHeight = height
117+
} else if let width, height == nil {
118+
idealWidth = width
119+
idealHeight = childSize.idealHeightForProposedWidth
120+
} else if let height, width == nil {
121+
idealHeight = height
122+
idealWidth = childSize.idealWidthForProposedHeight
123+
} else {
124+
idealWidth = childSize.idealSize.x
125+
idealHeight = childSize.idealSize.y
126+
}
127+
128+
let idealWidthForProposedHeight: Int
129+
let idealHeightForProposedWidth: Int
130+
if width == nil && height == nil {
131+
idealWidthForProposedHeight = childSize.idealWidthForProposedHeight
132+
idealHeightForProposedWidth = childSize.idealHeightForProposedWidth
133+
} else {
134+
idealWidthForProposedHeight = idealWidth
135+
idealHeightForProposedWidth = idealHeight
136+
}
137+
112138
return ViewSize(
113139
size: frameSize,
114140
idealSize: SIMD2(
115-
width ?? childSize.idealSize.x,
116-
height ?? childSize.idealSize.y
141+
idealWidth,
142+
idealHeight
117143
),
144+
idealWidthForProposedHeight: idealWidthForProposedHeight,
145+
idealHeightForProposedWidth: idealHeightForProposedWidth,
118146
minimumWidth: width ?? childSize.minimumWidth,
119147
minimumHeight: height ?? childSize.minimumHeight,
120148
maximumWidth: width.map(Double.init) ?? childSize.maximumWidth,
@@ -183,9 +211,6 @@ struct FlexibleFrameView<Child: View>: TypeSafeView {
183211
dryRun: Bool
184212
) -> ViewSize {
185213
var proposedFrameSize = proposedSize
186-
if let idealWidth {
187-
proposedFrameSize.x = min(proposedFrameSize.x, idealWidth)
188-
}
189214
if let minWidth {
190215
proposedFrameSize.x = max(proposedFrameSize.x, minWidth)
191216
}
@@ -198,9 +223,6 @@ struct FlexibleFrameView<Child: View>: TypeSafeView {
198223
if let maxHeight {
199224
proposedFrameSize.y = min(proposedFrameSize.y, maxHeight)
200225
}
201-
if let idealHeight {
202-
proposedFrameSize.y = min(proposedFrameSize.y, idealHeight)
203-
}
204226

205227
let childSize = children.child0.update(
206228
with: body.view0,
@@ -209,27 +231,50 @@ struct FlexibleFrameView<Child: View>: TypeSafeView {
209231
dryRun: dryRun
210232
)
211233

234+
// TODO: Fix idealSize propagation. When idealSize isn't possible, we
235+
// have to use idealWidthForProposedHeight and
236+
// idealHeightForProposedWidth, and sometimes we may also have to
237+
// perform an additional dryRun update to probe the child view.
238+
212239
var frameSize = childSize
213240
if let minWidth {
214241
frameSize.size.x = max(frameSize.size.x, minWidth)
215242
frameSize.minimumWidth = minWidth
216243
frameSize.idealSize.x = max(frameSize.idealSize.x, minWidth)
244+
frameSize.idealWidthForProposedHeight = max(
245+
frameSize.idealWidthForProposedHeight,
246+
minWidth
247+
)
217248
}
218249
if let maxWidth {
219250
frameSize.size.x = min(frameSize.size.x, maxWidth)
220251
frameSize.idealSize.x = min(frameSize.idealSize.x, maxWidth)
221252
frameSize.maximumWidth = min(childSize.maximumWidth, Double(maxWidth))
253+
frameSize.idealWidthForProposedHeight = min(
254+
frameSize.idealWidthForProposedHeight,
255+
maxWidth
256+
)
222257
}
258+
223259
if let minHeight {
224260
frameSize.size.y = max(frameSize.size.y, minHeight)
225261
frameSize.minimumHeight = minHeight
226262
frameSize.idealSize.y = max(frameSize.idealSize.y, minHeight)
263+
frameSize.idealHeightForProposedWidth = max(
264+
frameSize.idealHeightForProposedWidth,
265+
minHeight
266+
)
227267
}
228268
if let maxHeight {
229269
frameSize.size.y = min(frameSize.size.y, maxHeight)
230270
frameSize.idealSize.y = min(frameSize.idealSize.y, maxHeight)
231271
frameSize.maximumHeight = min(childSize.maximumHeight, Double(maxHeight))
272+
frameSize.idealHeightForProposedWidth = min(
273+
frameSize.idealHeightForProposedWidth,
274+
maxHeight
275+
)
232276
}
277+
233278
if let idealWidth {
234279
frameSize.idealSize.x = idealWidth
235280
}

Sources/SwiftCrossUI/Modifiers/Padding.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ struct PaddingModifierView<Child: View>: TypeSafeView {
7777
return ViewSize(
7878
size: size,
7979
idealSize: childSize.idealSize &+ paddingSize,
80+
idealWidthForProposedHeight: childSize.idealWidthForProposedHeight + paddingSize.x,
81+
idealHeightForProposedWidth: childSize.idealHeightForProposedWidth + paddingSize.y,
8082
minimumWidth: childSize.minimumWidth + paddingSize.x,
8183
minimumHeight: childSize.minimumHeight + paddingSize.y,
8284
maximumWidth: childSize.maximumWidth + Double(paddingSize.x),

Sources/SwiftCrossUI/Scenes/WindowGroupNode.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ public final class WindowGroupNode<Content: View>: SceneGraphNode {
4040
parentEnvironment = environment
4141

4242
backend.setResizeHandler(ofWindow: window) { [weak self] newSize in
43-
guard let self else { return }
43+
guard let self else {
44+
return
45+
}
4446
_ = self.update(
4547
scene,
4648
proposedWindowSize: newSize,
@@ -61,7 +63,9 @@ public final class WindowGroupNode<Content: View>: SceneGraphNode {
6163

6264
_ = update(
6365
newScene,
64-
proposedWindowSize: backend.size(ofWindow: window),
66+
proposedWindowSize: isFirstUpdate
67+
? (newScene ?? scene).defaultSize
68+
: backend.size(ofWindow: window),
6569
backend: backend,
6670
environment: environment
6771
)
@@ -238,8 +242,8 @@ public final class WindowGroupNode<Content: View>: SceneGraphNode {
238242
} else {
239243
return nil
240244
}
241-
} else if contentSize.size != currentProposedSize {
242-
return contentSize.size
245+
} else if contentSize.idealSize != currentProposedSize {
246+
return contentSize.idealSize
243247
} else {
244248
return nil
245249
}

Sources/SwiftCrossUI/ViewGraph/ViewSize.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ public struct ViewSize: Equatable {
3333
public var size: SIMD2<Int>
3434
/// The size that the view ideally wants to take up.
3535
public var idealSize: SIMD2<Int>
36+
/// The width that the view ideally wants to take up assuming that the
37+
/// proposed height doesn't change. Only really differs from `idealSize` for
38+
/// views that have a trade-off between width and height (such as `Text`).
39+
public var idealWidthForProposedHeight: Int
40+
/// The height that the view ideally wants to take up assuming that the
41+
/// proposed width doesn't change. Only really differs from `idealSize` for
42+
/// views that have a trade-off between width and height (such as `Text`).
43+
public var idealHeightForProposedWidth: Int
3644
/// The minimum width that the view can take (if its height remains the same).
3745
public var minimumWidth: Int
3846
/// The minimum height that the view can take (if its width remains the same).
@@ -59,6 +67,8 @@ public struct ViewSize: Equatable {
5967
public init(
6068
size: SIMD2<Int>,
6169
idealSize: SIMD2<Int>,
70+
idealWidthForProposedHeight: Int? = nil,
71+
idealHeightForProposedWidth: Int? = nil,
6272
minimumWidth: Int,
6373
minimumHeight: Int,
6474
maximumWidth: Double?,
@@ -67,6 +77,8 @@ public struct ViewSize: Equatable {
6777
) {
6878
self.size = size
6979
self.idealSize = idealSize
80+
self.idealWidthForProposedHeight = idealWidthForProposedHeight ?? idealSize.x
81+
self.idealHeightForProposedWidth = idealHeightForProposedWidth ?? idealSize.y
7082
self.minimumWidth = minimumWidth
7183
self.minimumHeight = minimumHeight
7284
// Using `Double(1 << 53)` as the default allows us to differentiate between views
@@ -87,6 +99,8 @@ public struct ViewSize: Equatable {
8799
public init(fixedSize: SIMD2<Int>) {
88100
size = fixedSize
89101
idealSize = fixedSize
102+
idealWidthForProposedHeight = fixedSize.x
103+
idealHeightForProposedWidth = fixedSize.y
90104
minimumWidth = fixedSize.x
91105
minimumHeight = fixedSize.y
92106
maximumWidth = Double(fixedSize.x)

Sources/SwiftCrossUI/Views/Group.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public struct Group<Content: View>: View {
3131
backend: Backend,
3232
dryRun: Bool
3333
) -> ViewSize {
34-
let size = LayoutSystem.updateStackLayout(
34+
LayoutSystem.updateStackLayout(
3535
container: widget,
3636
children: layoutableChildren(backend: backend, children: children),
3737
proposedSize: proposedSize,
@@ -40,6 +40,5 @@ public struct Group<Content: View>: View {
4040
dryRun: dryRun,
4141
inheritStackLayoutParticipation: true
4242
)
43-
return size
4443
}
4544
}

0 commit comments

Comments
 (0)