Skip to content

Commit 9e58521

Browse files
committed
Implement WinUIBackend SplitView and text wrapping support
1 parent 4b82aa2 commit 9e58521

File tree

7 files changed

+76
-93
lines changed

7 files changed

+76
-93
lines changed

Examples/Sources/SplitExample/SplitApp.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct ContentView: View {
9494
}
9595
}
9696
.padding(10)
97-
.frame(minWidth: 150)
97+
.frame(minWidth: 190)
9898
} detail: {
9999
VStack {
100100
switch state.selectedDetail {

Sources/AppKitBackend/AppKitBackend.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -645,11 +645,11 @@ public final class AppKitBackend: AppBackend {
645645

646646
public func setResizeHandler(
647647
ofSplitView splitView: Widget,
648-
to action: @escaping (_ leadingWidth: Int, _ trailingWidth: Int) -> Void
648+
to action: @escaping () -> Void
649649
) {
650650
let splitView = splitView as! NSCustomSplitView
651-
splitView.resizingDelegate?.setResizeHandler { paneWidths in
652-
action(paneWidths[0], paneWidths[1])
651+
splitView.resizingDelegate?.setResizeHandler {
652+
action()
653653
}
654654
}
655655

@@ -1264,15 +1264,15 @@ class NSCustomSplitView: NSSplitView {
12641264
}
12651265

12661266
class NSSplitViewResizingDelegate: NSObject, NSSplitViewDelegate {
1267-
var resizeHandler: ((_ paneWidths: [Int]) -> Void)?
1267+
var resizeHandler: (() -> Void)?
12681268
var leadingWidth = 0
12691269
var minimumLeadingWidth = 0
12701270
var maximumLeadingWidth = 0
12711271
var isFirstUpdate = true
12721272
/// Tracks whether AppKit is resizing the side bar (as opposed to the user resizing it).
12731273
var appKitIsResizing = false
12741274

1275-
func setResizeHandler(_ handler: @escaping (_ paneWidths: [Int]) -> Void) {
1275+
func setResizeHandler(_ handler: @escaping () -> Void) {
12761276
resizeHandler = handler
12771277
}
12781278

@@ -1292,7 +1292,7 @@ class NSSplitViewResizingDelegate: NSObject, NSSplitViewDelegate {
12921292

12931293
// Only call the handler if the side bar has actually changed size.
12941294
if leadingWidth != previousWidth {
1295-
resizeHandler?(paneWidths)
1295+
resizeHandler?()
12961296
}
12971297
}
12981298

Sources/Gtk3Backend/Gtk3Backend.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,11 @@ public final class Gtk3Backend: AppBackend {
337337

338338
// public func setResizeHandler(
339339
// ofSplitView splitView: Widget,
340-
// to action: @escaping (_ leadingWidth: Int, _ trailingWidth: Int) -> Void
340+
// to action: @escaping () -> Void
341341
// ) {
342342
// let splitView = splitView as! Paned
343343
// splitView.notifyPosition = { splitView in
344-
// action(splitView.position, splitView.getNaturalSize().width - splitView.position)
344+
// action()
345345
// }
346346
// }
347347

Sources/GtkBackend/GtkBackend.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,11 @@ public final class GtkBackend: AppBackend {
332332

333333
public func setResizeHandler(
334334
ofSplitView splitView: Widget,
335-
to action: @escaping (_ leadingWidth: Int, _ trailingWidth: Int) -> Void
335+
to action: @escaping () -> Void
336336
) {
337337
let splitView = splitView as! Paned
338338
splitView.notifyPosition = { splitView in
339-
action(splitView.position, splitView.getNaturalSize().width - splitView.position)
339+
action()
340340
}
341341
}
342342

Sources/SwiftCrossUI/Backend/AppBackend.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public protocol AppBackend {
212212
/// Sets the function to be called when the split view's panes get resized.
213213
func setResizeHandler(
214214
ofSplitView splitView: Widget,
215-
to action: @escaping (_ leadingWidth: Int, _ trailingWidth: Int) -> Void
215+
to action: @escaping () -> Void
216216
)
217217
/// Gets the width of a split view's sidebar.
218218
func sidebarWidth(ofSplitView splitView: Widget) -> Int
@@ -531,7 +531,7 @@ extension AppBackend {
531531

532532
public func setResizeHandler(
533533
ofSplitView splitView: Widget,
534-
to action: @escaping (_ leadingWidth: Int, _ trailingWidth: Int) -> Void
534+
to action: @escaping () -> Void
535535
) {
536536
todo()
537537
}

Sources/SwiftCrossUI/Views/SplitView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct SplitView<Sidebar: View, Detail: View>: TypeSafeView, View {
4545
) -> ViewUpdateResult {
4646
let leadingWidth = backend.sidebarWidth(ofSplitView: widget)
4747
if !dryRun {
48-
backend.setResizeHandler(ofSplitView: widget) { _, _ in
48+
backend.setResizeHandler(ofSplitView: widget) {
4949
environment.onResize(.empty)
5050
}
5151
}
@@ -63,7 +63,7 @@ struct SplitView<Sidebar: View, Detail: View>: TypeSafeView, View {
6363
let trailingResult = children.trailingChild.update(
6464
with: body.view1,
6565
proposedSize: SIMD2(
66-
proposedSize.x - leadingWidth,
66+
proposedSize.x - max(leadingWidth, leadingResult.size.minimumWidth),
6767
proposedSize.y
6868
),
6969
environment: environment,

Sources/WinUIBackend/WinUIBackend.swift

Lines changed: 61 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -367,16 +367,15 @@ public struct WinUIBackend: AppBackend {
367367
proposedFrame: SIMD2<Int>?,
368368
environment: EnvironmentValues
369369
) -> SIMD2<Int> {
370-
let block = TextBlock()
371-
block.text = text
372-
373-
missing("font design handling (monospace vs normal)")
374-
environment.apply(to: block)
375-
376-
let allocation = WindowsFoundation.Size(
377-
width: .infinity,
378-
height: .infinity
379-
)
370+
let block = createTextView()
371+
updateTextView(block, content: text, environment: environment)
372+
373+
let allocation =
374+
proposedFrame.map(WindowsFoundation.Size.init(_:))
375+
?? WindowsFoundation.Size(
376+
width: .infinity,
377+
height: .infinity
378+
)
380379
try! block.measure(allocation)
381380

382381
let computedSize = block.desiredSize
@@ -387,7 +386,9 @@ public struct WinUIBackend: AppBackend {
387386
}
388387

389388
public func createTextView() -> Widget {
390-
return TextBlock()
389+
let textBlock = TextBlock()
390+
textBlock.textWrapping = __x_ABI_CMicrosoft_CUI_CXaml_CTextWrapping_Wrap
391+
return textBlock
391392
}
392393

393394
public func updateTextView(
@@ -397,6 +398,7 @@ public struct WinUIBackend: AppBackend {
397398
) {
398399
let block = textView as! TextBlock
399400
block.text = content
401+
missing("font design handling (monospace vs normal)")
400402
environment.apply(to: block)
401403
}
402404

@@ -614,76 +616,44 @@ public struct WinUIBackend: AppBackend {
614616
imageView.source = bitmap
615617
}
616618

617-
// public func createOneOfContainer() -> Widget {
618-
// let frame = Frame()
619-
// frame.contentTransitions = TransitionCollection()
620-
// frame.contentTransitions.append(NavigationThemeTransition())
621-
// return frame
622-
// }
623-
624-
// public func addChild(_ child: Widget, toOneOfContainer container: Widget) {
625-
// let frame = container as! Frame
626-
// frame.content = child
627-
// // frame.contentTransitions.append(Transition(composing: child, createCallback: {})
628-
// }
629-
630-
// public func setVisibleChild(ofOneOfContainer container: Widget, to child: Widget) {
631-
// // TODO: the frame.navigate method should allow to change the content of the frame
632-
// // with the specified animation (NavigationThemeTransition) but I fail to understant
633-
// // how to pass the child widget to it, so for now it just set the new content
634-
// let frame = container as! Frame
635-
// frame.content = child
636-
// // let _ = try! frame.navigate(TypeName(name: child.accessKey, kind: .custom))
637-
// }
638-
639-
// public func removeChild(_: Widget, fromOneOfContainer _: Widget) {}
640-
641-
// public func createSpacer() -> Widget {
642-
// StackPanel()
643-
// }
644-
645-
// public func updateSpacer(
646-
// _ spacer: Widget, expandHorizontally: Bool, expandVertically: Bool, minSize: Int
647-
// ) {
648-
// let stackPanel = spacer as! StackPanel
649-
// if expandHorizontally {
650-
// stackPanel.minWidth = Double(minSize)
651-
// }
652-
// if expandVertically {
653-
// stackPanel.minHeight = Double(minSize)
654-
// }
655-
// }
656-
657-
// public func createSplitView(leadingChild: Widget, trailingChild: Widget) -> Widget {
658-
// let grid = Grid()
659-
// let leadingColumn = ColumnDefinition()
660-
// let trailingColumn = ColumnDefinition()
661-
// leadingColumn.width = GridLength(value: 1, gridUnitType: .star)
662-
// trailingColumn.width = GridLength(value: 1, gridUnitType: .star)
663-
// grid.columnDefinitions.append(leadingColumn)
664-
// grid.columnDefinitions.append(trailingColumn)
665-
// Grid.setColumn(leadingChild, 0)
666-
// Grid.setColumn(trailingChild, 1)
667-
// grid.children.append(leadingChild)
668-
// grid.children.append(trailingChild)
669-
// return grid
670-
// }
619+
public func createSplitView(leadingChild: Widget, trailingChild: Widget) -> Widget {
620+
let splitView = CustomSplitView()
621+
splitView.pane = leadingChild
622+
splitView.content = trailingChild
623+
splitView.isPaneOpen = true
624+
splitView.displayMode = __x_ABI_CMicrosoft_CUI_CXaml_CControls_CSplitViewDisplayMode_Inline
625+
return splitView
626+
}
671627

672-
// public func getInheritedOrientation(of _: Widget) -> InheritedOrientation? {
673-
// InheritedOrientation.vertical
674-
// }
628+
public func setResizeHandler(
629+
ofSplitView splitView: Widget,
630+
to action: @escaping () -> Void
631+
) {
632+
// WinUI's SplitView currently doesn't support resizing, but we still
633+
// store the sidebar resize handler because we programmatically resize
634+
// the sidebar and call the handler whenever the minimum sidebar width
635+
// changes.
636+
let splitView = splitView as! CustomSplitView
637+
splitView.sidebarResizeHandler = action
638+
}
675639

676-
// public func createFrameContainer(for child: Widget) -> Widget {
677-
// let frame = Frame()
678-
// frame.content = child
679-
// return frame
680-
// }
640+
public func sidebarWidth(ofSplitView splitView: Widget) -> Int {
641+
let splitView = splitView as! CustomSplitView
642+
return Int(splitView.openPaneLength.rounded(.towardZero))
643+
}
681644

682-
// public func updateFrameContainer(_ container: Widget, minWidth: Int, minHeight: Int) {
683-
// let frame = container as! Frame
684-
// frame.minWidth = Double(minWidth)
685-
// frame.minHeight = Double(minHeight)
686-
// }
645+
public func setSidebarWidthBounds(
646+
ofSplitView splitView: Widget,
647+
minimum minimumWidth: Int,
648+
maximum maximumWidth: Int
649+
) {
650+
let splitView = splitView as! CustomSplitView
651+
let newWidth = Double(max(minimumWidth, 10))
652+
if newWidth != splitView.openPaneLength {
653+
splitView.openPaneLength = newWidth
654+
splitView.sidebarResizeHandler?()
655+
}
656+
}
687657

688658
// public func createTable(rows: Int, columns: Int) -> Widget {
689659
// let grid = Grid()
@@ -842,3 +812,16 @@ final class CustomComboBox: ComboBox {
842812
var onChangeSelection: ((Int?) -> Void)?
843813
var actualForegroundColor: UWP.Color = UWP.Color(a: 255, r: 0, g: 0, b: 0)
844814
}
815+
816+
final class CustomSplitView: SplitView {
817+
var sidebarResizeHandler: (() -> Void)?
818+
}
819+
820+
extension WindowsFoundation.Size {
821+
init(_ other: SIMD2<Int>) {
822+
self.init(
823+
width: Float(other.x),
824+
height: Float(other.y)
825+
)
826+
}
827+
}

0 commit comments

Comments
 (0)