macbackend/Sources/Core/View/MenuWrapper.swift
david-swift 3c2cc8cb48
All checks were successful
Deploy Docs / publish (push) Successful in 3m33s
SwiftLint / SwiftLint (push) Successful in 3s
Fix menu not working properly
2024-12-15 22:20:59 +01:00

80 lines
2.6 KiB
Swift

//
// MenuWrapper.swift
// MacBackend
//
// Created by david-swift on 06.12.2024.
//
import AppKit
/// Wrap a view to add a menu.
public struct MenuWrapper: MacWidget {
/// Whether the menu is visible.
@Binding var present: Signal
/// The content.
var content: Body
/// The menu.
var menu: Body
/// Initialize a menu wrapper.
/// - Parameters:
/// - content: The view content.
/// - present: The signal for presenting the menu.
/// - menu: The menu.
public init(@ViewBuilder content: () -> Body, present: Binding<Signal>, @ViewBuilder menu: () -> Body) {
self._present = present
self.content = content()
self.menu = menu()
}
/// The view storage.
/// - Parameters:
/// - data: The widget data.
/// - type: The type of the views.
/// - Returns: The view storage.
public func container<Data>(
data: WidgetData,
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
let content = content.storage(data: data, type: type)
let menuPointer = NSMenu()
let menu = MenuCollection { self.menu }.getMenu(data: data, menu: menuPointer)
let storage = ViewStorage(content.pointer, content: [.mainContent: [content], "menu": [menu]])
storage.fields["menu"] = menuPointer
update(storage, data: data, updateProperties: true, type: type)
return storage
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - data: The widget data.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the views.
public func update<Data>(
_ storage: ViewStorage,
data: WidgetData,
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
if let content = storage.content[.mainContent]?.first {
self.content.updateStorage(content, data: data, updateProperties: updateProperties, type: type)
}
if let menu = storage.content["menu"]?.first {
MenuCollection { self.menu }
.updateStorage(menu, data: data, updateProperties: updateProperties, type: MenuContext.self)
}
if present.update,
let menu = storage.fields["menu"] as? NSMenu,
let content = storage.content[.mainContent]?.first?.pointer as? NSView,
let currentEvent = NSApp.currentEvent {
StateManager.blockUpdates = true
present.signal()
StateManager.blockUpdates = false
NSMenu.popUpContextMenu(menu, with: currentEvent, for: content)
}
}
}