Skip to content

Commit fc6be77

Browse files
committed
WinUIBackend: Implement Scene commands (menu bar) support
1 parent 4de7709 commit fc6be77

File tree

1 file changed

+120
-7
lines changed

1 file changed

+120
-7
lines changed

Sources/WinUIBackend/WinUIBackend.swift

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class WinUIApplication: SwiftApplication {
2727
}
2828

2929
public final class WinUIBackend: AppBackend {
30-
public typealias Window = WinUI.Window
30+
public typealias Window = CustomWindow
3131
public typealias Widget = WinUI.FrameworkElement
3232
public typealias Menu = Void
3333
public typealias Alert = WinUI.ContentDialog
@@ -92,7 +92,7 @@ public final class WinUIBackend: AppBackend {
9292
}
9393

9494
public func createWindow(withDefaultSize size: SIMD2<Int>?) -> Window {
95-
let window = Window()
95+
let window = CustomWindow()
9696
windows.append(window)
9797
window.closed.addHandler { _, _ in
9898
self.windows.removeAll { other in
@@ -145,7 +145,7 @@ public final class WinUIBackend: AppBackend {
145145
let size = window.appWindow.clientSize
146146
let out = SIMD2(
147147
Int(size.width),
148-
Int(size.height)
148+
Int(size.height) - CustomWindow.menuBarHeight
149149
)
150150
return out
151151
}
@@ -158,7 +158,7 @@ public final class WinUIBackend: AppBackend {
158158
public func setSize(ofWindow window: Window, to newSize: SIMD2<Int>) {
159159
let size = UWP.SizeInt32(
160160
width: Int32(newSize.x),
161-
height: Int32(newSize.y)
161+
height: Int32(newSize.y + CustomWindow.menuBarHeight)
162162
)
163163
try! window.appWindow.resizeClient(size)
164164
}
@@ -174,7 +174,7 @@ public final class WinUIBackend: AppBackend {
174174
window.sizeChanged.addHandler { _, args in
175175
let size = SIMD2(
176176
Int(args!.size.width.rounded(.awayFromZero)),
177-
Int(args!.size.height.rounded(.awayFromZero))
177+
Int(args!.size.height.rounded(.awayFromZero)) - CustomWindow.menuBarHeight
178178
)
179179
action(size)
180180
}
@@ -189,7 +189,7 @@ public final class WinUIBackend: AppBackend {
189189
}
190190

191191
public func setChild(ofWindow window: Window, to widget: Widget) {
192-
window.content = widget
192+
window.setChild(widget)
193193
try! widget.updateLayout()
194194
widget.actualThemeChanged.addHandler { _, _ in
195195
self.internalState.themeChangeAction?()
@@ -220,8 +220,43 @@ public final class WinUIBackend: AppBackend {
220220
// print("missing: \(message)")
221221
}
222222

223+
private func renderItems(_ items: [ResolvedMenu.Item]) -> [MenuFlyoutItemBase] {
224+
items.map { item in
225+
switch item {
226+
case .button(let label, let action):
227+
let widget = MenuFlyoutItem()
228+
widget.text = label
229+
widget.click.addHandler { _, _ in
230+
action?()
231+
}
232+
return widget
233+
case .submenu(let submenu):
234+
let widget = MenuFlyoutSubItem()
235+
widget.text = submenu.label
236+
for subitem in renderItems(submenu.content.items) {
237+
widget.items.append(subitem)
238+
}
239+
return widget
240+
}
241+
}
242+
}
243+
223244
public func setApplicationMenu(_ submenus: [ResolvedMenu.Submenu]) {
224-
missing("setApplicationMenu(_:) implementation")
245+
let items = submenus.map { submenu in
246+
let item = MenuBarItem()
247+
item.title = submenu.label
248+
for subitem in renderItems(submenu.content.items) {
249+
item.items.append(subitem)
250+
}
251+
return item
252+
}
253+
254+
for window in windows {
255+
window.menuBar.items.clear()
256+
for item in items {
257+
window.menuBar.items.append(item)
258+
}
259+
}
225260
}
226261

227262
public func computeRootEnvironment(
@@ -919,6 +954,50 @@ public final class WinUIBackend: AppBackend {
919954
}
920955
}
921956

957+
// public func showOpenDialog(
958+
// fileDialogOptions: FileDialogOptions,
959+
// openDialogOptions: OpenDialogOptions,
960+
// window: Window?,
961+
// resultHandler handleResult: @escaping (DialogResult<[URL]>) -> Void
962+
// ) {
963+
// let picker = FileOpenPicker()
964+
// // TODO: Associate the picker with a window. Requires some janky WinUI
965+
// // Win32 interop kinda stuff I believe.
966+
// if openDialogOptions.allowMultipleSelections {
967+
// let promise = try! picker.pickMultipleFilesAsync()!
968+
// promise.completed = { operation, status in
969+
// guard
970+
// status == .completed,
971+
// let operation,
972+
// let result = try? operation.getResults()
973+
// else {
974+
// return
975+
// }
976+
// print(result)
977+
// }
978+
// } else {
979+
// let promise = try! picker.pickSingleFileAsync()!
980+
// promise.completed = { operation, status in
981+
// guard
982+
// status == .completed,
983+
// let operation,
984+
// let result = try? operation.getResults()
985+
// else {
986+
// return
987+
// }
988+
// print(result)
989+
// }
990+
// }
991+
// }
992+
993+
// public func showSaveDialog(
994+
// fileDialogOptions: FileDialogOptions,
995+
// saveDialogOptions: SaveDialogOptions,
996+
// window: Window?,
997+
// resultHandler handleResult: @escaping (DialogResult<URL>) -> Void
998+
// ) {
999+
// }
1000+
9221001
public func createClickTarget(wrapping child: Widget) -> Widget {
9231002
let clickTarget = ClickTarget()
9241003
addChild(child, to: clickTarget)
@@ -1084,3 +1163,37 @@ final class ClickTarget: WinUI.Canvas {
10841163
var clickHandler: (() -> Void)?
10851164
var child: WinUI.FrameworkElement?
10861165
}
1166+
1167+
public class CustomWindow: WinUI.Window {
1168+
/// Hardcoded menu bar height from MenuBar_themeresources.xaml in the
1169+
/// microsoft-ui-xaml repository.
1170+
static let menuBarHeight = 40
1171+
1172+
var menuBar = WinUI.MenuBar()
1173+
var child: WinUIBackend.Widget?
1174+
var grid: WinUI.Grid
1175+
1176+
public override init() {
1177+
grid = WinUI.Grid()
1178+
1179+
super.init()
1180+
1181+
let menuBarRowDefinition = WinUI.RowDefinition()
1182+
menuBarRowDefinition.height = WinUI.GridLength(
1183+
value: Double(Self.menuBarHeight),
1184+
gridUnitType: .pixel
1185+
)
1186+
let contentRowDefinition = WinUI.RowDefinition()
1187+
grid.rowDefinitions.append(menuBarRowDefinition)
1188+
grid.rowDefinitions.append(contentRowDefinition)
1189+
grid.children.append(menuBar)
1190+
WinUI.Grid.setRow(menuBar, 0)
1191+
self.content = grid
1192+
}
1193+
1194+
public func setChild(_ child: WinUIBackend.Widget) {
1195+
self.child = child
1196+
grid.children.append(child)
1197+
WinUI.Grid.setRow(child, 1)
1198+
}
1199+
}

0 commit comments

Comments
 (0)