Skip to content

Commit baf48b3

Browse files
committed
Impl WinUIBackend ScrollView, fix ScrollView layout calculations
ScrollView had some layout bugs affecting all backends.
1 parent 9961828 commit baf48b3

File tree

5 files changed

+57
-110
lines changed

5 files changed

+57
-110
lines changed

Examples/Sources/NotesExample/ContentView.swift

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -28,79 +28,6 @@ class NotesState: Observable, Codable {
2828
var error: String?
2929
}
3030

31-
struct OnChangeOfView<Value: Equatable, Child: View>: View {
32-
var state = OnChangeOfViewState()
33-
34-
var currentValue: Value
35-
var onChange: (Value) -> Void
36-
var child: Child
37-
var notifyInitial: Bool
38-
39-
class OnChangeOfViewState: Observable {
40-
var value: Value?
41-
}
42-
43-
init(
44-
_ value: Value,
45-
_ onChange: @escaping (Value) -> Void,
46-
_ notifyInitial: Bool,
47-
_ child: Child
48-
) {
49-
self.currentValue = value
50-
self.onChange = onChange
51-
self.notifyInitial = notifyInitial
52-
self.child = child
53-
}
54-
55-
var body: some View {
56-
if state.value != currentValue {
57-
let isInitial = state.value != nil
58-
state.value = currentValue
59-
if !isInitial || notifyInitial {
60-
onChange(currentValue)
61-
}
62-
}
63-
return child
64-
}
65-
}
66-
67-
struct OnAppearView<Child: View>: View {
68-
var state = OnAppearViewState()
69-
var onAppear: () -> Void
70-
var child: Child
71-
72-
class OnAppearViewState: Observable {
73-
var hasAppeared = false
74-
}
75-
76-
init(_ onAppear: @escaping () -> Void, _ child: Child) {
77-
self.onAppear = onAppear
78-
self.child = child
79-
}
80-
81-
var body: some View {
82-
if !state.hasAppeared {
83-
state.hasAppeared = true
84-
onAppear()
85-
}
86-
return child
87-
}
88-
}
89-
90-
extension View {
91-
func onChange<Value>(
92-
of value: Value,
93-
initial: Bool = false,
94-
_ action: @escaping (Value) -> Void
95-
) -> OnChangeOfView<Value, Self> {
96-
OnChangeOfView(value, action, initial, self)
97-
}
98-
99-
func onAppear(perform action: @escaping () -> Void) -> OnAppearView<Self> {
100-
OnAppearView(action, self)
101-
}
102-
}
103-
10431
struct ContentView: View {
10532
let notesFile = URL(fileURLWithPath: "notes.json")
10633

@@ -149,9 +76,9 @@ struct ContentView: View {
14976
state.selectedNoteId = note.id
15077
}
15178
}
152-
.onChange(of: state.notes) { notes in
79+
.onChange(of: state.notes) {
15380
do {
154-
let data = try JSONEncoder().encode(notes)
81+
let data = try JSONEncoder().encode(state.notes)
15582
try data.write(to: notesFile)
15683
} catch {
15784
print("Error: \(error)")

Examples/Sources/NotesExample/NotesApp.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import DefaultBackend
2-
import SwiftBundlerRuntime
32
import SwiftCrossUI
43

4+
#if canImport(SwiftBundlerRuntime)
5+
import SwiftBundlerRuntime
6+
#endif
7+
58
@main
69
@HotReloadable
710
struct NotesApp: App {

Examples/notes.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"content":"Welcome SwiftCrossNotes!","id":"D70F96BB-2153-4FC6-A79F-FD231B4F3523","title":"Hello, world!"},{"content":"- Carrots","id":"04864C37-38E3-4FC1-8BAF-C2BA41AAF8D9","title":"Shopping list"},{"title":"My note","id":"EAA92A96-E443-4374-AB35-41CD4BD99EBD","content":"I hope for world piss"}]

Sources/SwiftCrossUI/Views/ScrollView.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,14 @@ public struct ScrollView<Content: View>: TypeSafeView, View {
7676
scrollViewWidth = max(proposedSize.x, verticalScrollBarWidth)
7777
minimumWidth = verticalScrollBarWidth
7878
} else {
79-
scrollViewWidth = max(
80-
contentSize.size.x,
81-
contentSize.minimumWidth + verticalScrollBarWidth
82-
)
79+
scrollViewWidth = contentSize.size.x + verticalScrollBarWidth
8380
minimumWidth = contentSize.minimumWidth + verticalScrollBarWidth
8481
}
8582
if axes.contains(.vertical) {
8683
scrollViewHeight = max(proposedSize.y, horizontalScrollBarHeight)
8784
minimumHeight = horizontalScrollBarHeight
8885
} else {
89-
scrollViewHeight = max(
90-
contentSize.size.y,
91-
contentSize.minimumHeight + horizontalScrollBarHeight
92-
)
86+
scrollViewHeight = contentSize.size.y + horizontalScrollBarHeight
9387
minimumHeight = contentSize.minimumHeight + horizontalScrollBarHeight
9488
}
9589

@@ -102,9 +96,11 @@ public struct ScrollView<Content: View>: TypeSafeView, View {
10296
if !dryRun {
10397
let proposedContentSize = SIMD2(
10498
hasHorizontalScrollBar
105-
? contentSize.idealSize.x : (contentSize.size.x - verticalScrollBarWidth),
99+
? contentSize.idealSize.x
100+
: min(contentSize.size.x, proposedSize.x - verticalScrollBarWidth),
106101
hasVerticalScrollBar
107-
? contentSize.idealSize.y : (contentSize.size.y - horizontalScrollBarHeight)
102+
? contentSize.idealSize.y
103+
: min(contentSize.size.y, proposedSize.y - horizontalScrollBarHeight)
108104
)
109105

110106
finalResult = children.child.update(

Sources/WinUIBackend/WinUIBackend.swift

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public struct WinUIBackend: AppBackend {
3737
public let defaultPaddingAmount = 10
3838

3939
public var scrollBarWidth: Int {
40-
fatalError("TODO")
40+
12
4141
}
4242

4343
private class InternalState {
@@ -61,8 +61,9 @@ public struct WinUIBackend: AppBackend {
6161
// Toggle Switch has annoying default 'internal margins' (not Control
6262
// margins that we can set directly) that we can luckily get rid of by
6363
// overriding the relevant resource values.
64-
application.resources.insert("ToggleSwitchPreContentMargin", 0.0 as Double)
65-
application.resources.insert("ToggleSwitchPostContentMargin", 0.0 as Double)
64+
_ = application.resources.insert("ToggleSwitchPreContentMargin", 0.0 as Double)
65+
_ = application.resources.insert("ToggleSwitchPostContentMargin", 0.0 as Double)
66+
6667
callback()
6768
}
6869
WinUIApplication.main()
@@ -219,7 +220,6 @@ public struct WinUIBackend: AppBackend {
219220
public func addChild(_ child: Widget, to container: Widget) {
220221
let container = container as! Canvas
221222
container.children.append(child)
222-
try! container.updateLayout()
223223
}
224224

225225
public func setPosition(ofChildAt index: Int, in container: Widget, to position: SIMD2<Int>) {
@@ -394,12 +394,10 @@ public struct WinUIBackend: AppBackend {
394394
let block = createTextView()
395395
updateTextView(block, content: text, environment: environment)
396396

397-
let allocation =
398-
proposedFrame.map(WindowsFoundation.Size.init(_:))
399-
?? WindowsFoundation.Size(
400-
width: .infinity,
401-
height: .infinity
402-
)
397+
let allocation = WindowsFoundation.Size(
398+
width: (proposedFrame?.x).map(Float.init(_:)) ?? .infinity,
399+
height: .infinity
400+
)
403401
try! block.measure(allocation)
404402

405403
let computedSize = block.desiredSize
@@ -451,11 +449,42 @@ public struct WinUIBackend: AppBackend {
451449
internalState.buttonClickActions[ObjectIdentifier(button)] = action
452450
}
453451

454-
// public func createScrollContainer(for child: Widget) -> Widget {
455-
// let scrollViewer = ScrollViewer()
456-
// scrollViewer.content = child
457-
// return scrollViewer
458-
// }
452+
public func createScrollContainer(for child: Widget) -> Widget {
453+
let scrollViewer = WinUI.ScrollViewer()
454+
scrollViewer.content = child
455+
child.horizontalAlignment =
456+
__x_ABI_CMicrosoft_CUI_CXaml_CHorizontalAlignment_Left
457+
child.verticalAlignment = __x_ABI_CMicrosoft_CUI_CXaml_CVerticalAlignment_Top
458+
return scrollViewer
459+
}
460+
461+
public func setScrollBarPresence(
462+
ofScrollContainer scrollView: Widget,
463+
hasVerticalScrollBar: Bool,
464+
hasHorizontalScrollBar: Bool
465+
) {
466+
let scrollViewer = scrollView as! WinUI.ScrollViewer
467+
468+
scrollViewer.isHorizontalRailEnabled = hasHorizontalScrollBar
469+
scrollViewer.horizontalScrollMode =
470+
hasHorizontalScrollBar
471+
? __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollMode_Enabled
472+
: __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollMode_Disabled
473+
scrollViewer.horizontalScrollBarVisibility =
474+
hasHorizontalScrollBar
475+
? __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollBarVisibility_Visible
476+
: __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollBarVisibility_Hidden
477+
478+
scrollViewer.isVerticalRailEnabled = hasVerticalScrollBar
479+
scrollViewer.verticalScrollMode =
480+
hasVerticalScrollBar
481+
? __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollMode_Enabled
482+
: __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollMode_Disabled
483+
scrollViewer.verticalScrollBarVisibility =
484+
hasVerticalScrollBar
485+
? __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollBarVisibility_Visible
486+
: __x_ABI_CMicrosoft_CUI_CXaml_CControls_CScrollBarVisibility_Hidden
487+
}
459488

460489
public func createSlider() -> Widget {
461490
let slider = Slider()
@@ -847,12 +876,3 @@ final class CustomComboBox: ComboBox {
847876
final class CustomSplitView: SplitView {
848877
var sidebarResizeHandler: (() -> Void)?
849878
}
850-
851-
extension WindowsFoundation.Size {
852-
init(_ other: SIMD2<Int>) {
853-
self.init(
854-
width: Float(other.x),
855-
height: Float(other.y)
856-
)
857-
}
858-
}

0 commit comments

Comments
 (0)