Add support for menus
This commit is contained in:
parent
71cd433a8f
commit
f77cf5bd34
@ -56,7 +56,7 @@ public struct MenuCollection: MenuWidget, Wrapper {
|
||||
/// - data: The widget data.
|
||||
/// - menu: The menu.
|
||||
/// - Returns: The view storage with the GMenu as the pointer.
|
||||
public func getMenu(data: WidgetData, menu: NSMenu?) -> ViewStorage {
|
||||
public func getMenu(data: WidgetData, menu: NSMenu? = nil) -> ViewStorage {
|
||||
let item = NSMenuItem()
|
||||
let menu = menu ?? .init()
|
||||
let storage = container(data: data.noModifiers, type: MenuContext.self)
|
||||
|
||||
77
Sources/Core/View/MenuWrapper.swift
Normal file
77
Sources/Core/View/MenuWrapper.swift
Normal file
@ -0,0 +1,77 @@
|
||||
//
|
||||
// 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 isPresented: Bool
|
||||
/// The content.
|
||||
var content: Body
|
||||
/// The menu.
|
||||
var menu: Body
|
||||
|
||||
/// Initialize a menu wrapper.
|
||||
/// - Parameters:
|
||||
/// - content: The view content.
|
||||
/// - isPresented: Whether the menu is visible.
|
||||
/// - menu: The menu.
|
||||
public init(@ViewBuilder content: () -> Body, isPresented: Binding<Bool>, @ViewBuilder menu: () -> Body) {
|
||||
self._isPresented = isPresented
|
||||
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 isPresented,
|
||||
let menu = storage.fields["menu"] as? NSMenu,
|
||||
let content = storage.content[.mainContent]?.first?.pointer as? NSView,
|
||||
let currentEvent = NSApp.currentEvent {
|
||||
NSMenu.popUpContextMenu(menu, with: currentEvent, for: content)
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -24,6 +24,7 @@ struct Demo: App {
|
||||
@State private var elements: [Element] = [.init()]
|
||||
@State private var selectedElement: String?
|
||||
@State private var alert = false
|
||||
@State private var menuPresented = false
|
||||
|
||||
var scene: Scene {
|
||||
Window("Main", id: "main") {
|
||||
@ -39,7 +40,12 @@ struct Demo: App {
|
||||
selectedElement = element.id
|
||||
}
|
||||
Button(alert.description) {
|
||||
alert = true
|
||||
menuPresented = true
|
||||
}
|
||||
.menu(isPresented: $menuPresented) {
|
||||
MenuButton(alert.description) {
|
||||
print("Hi")
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert("Hello", isPresented: $alert)
|
||||
|
||||
@ -30,4 +30,13 @@ extension AnyView {
|
||||
PaddingView(padding: padding, edges: edges, child: self)
|
||||
}
|
||||
|
||||
/// A menu over the view.
|
||||
/// - Parameters:
|
||||
/// - isPresented: Whether the menu is currently visible.
|
||||
/// - menu: The menu.
|
||||
/// - Returns: The view.
|
||||
public func menu(isPresented: Binding<Bool>, @ViewBuilder menu: @escaping () -> Body) -> Meta.AnyView {
|
||||
MenuWrapper(content: { self }, isPresented: isPresented, menu: menu)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user