import Adw import Gtk extension View { @MainActor private func mountDialog(_ view: Dialog, _ ctx: MountContext) -> Adw.Dialog { let widget = AnyView(view).makeWidget(ctx) guard let dialog = widget as? Adw.Dialog else { preconditionFailure("Dialog mounted a \(type(of: widget)); expected Adw.Dialog.") } return dialog } /// Presents a configurable `Adw.Dialog` over this view while `isPresented` is true. /// /// Each property accepts a fixed value or a live `Binding`. Width and height use `Int32`; /// integer literals are accepted. Use `DialogPresentationMode.bottomSheet` explicitly for /// `presentationMode`. Setting `canClose` to false vetoes user dismissal. /// /// - Parameters: /// - isPresented: Two-way control over the dialog visibility. /// - title: Optional dialog title. /// - contentWidth: Optional content width in pixels. /// - contentHeight: Optional content height in pixels. /// - presentationMode: Optional dialog presentation mode. /// - canClose: Whether user dismissal is allowed. /// - followsContentSize: Whether the dialog follows its content size. /// - content: Builder whose first view becomes the dialog child. /// - Returns: This view, unchanged, with the dialog presentation attached. public func dialog( isPresented: Binding, title: (any DialogPropertySource)? = nil, contentWidth: (any DialogPropertySource)? = nil, contentHeight: (any DialogPropertySource)? = nil, presentationMode: (any DialogPropertySource)? = nil, canClose: (any DialogPropertySource)? = nil, followsContentSize: (any DialogPropertySource)? = nil, @ViewBuilder content: () -> [AnyView] ) -> AnyView { let contentViews = content() var configured = Dialog() configured = appliedDialogProperty(title, to: configured, constant: { $0.title($1) }, binding: { $0.title($1) }) configured = appliedDialogProperty(contentWidth, to: configured, constant: { $0.contentWidth($1) }, binding: { $0.contentWidth($1) }) configured = appliedDialogProperty(contentHeight, to: configured, constant: { $0.contentHeight($1) }, binding: { $0.contentHeight($1) }) configured = appliedDialogProperty(presentationMode, to: configured, constant: { $0.presentationMode($1) }, binding: { $0.presentationMode($1) }) configured = appliedDialogProperty(canClose, to: configured, constant: { $0.canClose($1) }, binding: { $0.canClose($1) }) configured = appliedDialogProperty(followsContentSize, to: configured, constant: { $0.followsContentSize($1) }, binding: { $0.followsContentSize($1) }) return AnyView(makeWidget: { ctx in let host = AnyView(self).makeWidget(ctx) let dialog = mountDialog(configured, ctx) if let first = contentViews.first { dialog.setChild(child: first.makeWidget(ctx)) } bindDialogPresentation(dialog, isPresented: isPresented, host: host, ctx: ctx) return host }) } /// Presents a pre-configured `Dialog` over this view while `isPresented` is true. /// /// Use this overload for widget-slot properties such as `defaultWidget` and `focusWidget`. /// - Parameters: /// - isPresented: Two-way control over the dialog visibility. /// - dialog: The configured dialog view to mount. /// - Returns: This view, unchanged, with the dialog presentation attached. public func dialog(isPresented: Binding, _ dialog: Dialog) -> AnyView { AnyView(makeWidget: { ctx in let host = AnyView(self).makeWidget(ctx) let mounted = mountDialog(dialog, ctx) bindDialogPresentation(mounted, isPresented: isPresented, host: host, ctx: ctx) return host }) } }