import Gtk /// Type-erased `View` that stores a mount thunk and its parent-node shape. /// /// Uses runtime casts to dispatch: `Mountable` primitives/containers are /// called directly; user structs evaluate `body` once and recurse. /// ``AnyView`` deliberately does NOT conform to `Mountable` - the `as? AnyView` /// branch handles nesting without name clashes. public struct AnyView: View { /// The mount thunk: builds this view's `Gtk.Widget` exactly once. @_spi(Portico) public let makeWidget: (MountContext) -> Gtk.Widget /// The structured node this view contributes to a parent container. @_spi(Portico) public let kind: ViewNodeKind public var body: Never { fatalError() } /// Wraps a pre-built mount thunk directly. @_spi(Portico) public init( makeWidget: @escaping (MountContext) -> Gtk.Widget, kind: ViewNodeKind = .widget ) { self.makeWidget = makeWidget self.kind = kind } /// Creates a type-erased view wrapping the given view. /// /// Dispatch order: `AnyView` passthrough, ``Mountable`` direct mount, then /// user-struct body evaluation once at mount. public init(_ view: V) { if let any = view as? AnyView { self.makeWidget = any.makeWidget self.kind = any.kind } else if let m = view as? Mountable { self.makeWidget = { ctx in m.mount(ctx) } self.kind = (view as? any DynamicViewGroup).map(ViewNodeKind.group) ?? .widget } else { self.makeWidget = { ctx in _resolveDynamicProperties(view, in: ctx.environment) return AnyView(view.body).makeWidget(ctx) } self.kind = (view as? any DynamicViewGroup).map(ViewNodeKind.group) ?? .widget } } /// Creates a conditional node with a vertical-box fallback mount. @_spi(Portico) public static func conditional(_ node: ConditionalNode) -> AnyView { AnyView( makeWidget: { ctx in mountConditionalFallback(node, ctx: ctx) }, kind: .conditional(node) ) } /// Creates a positional list node with a vertical-box fallback mount. @_spi(Portico) public static func list(_ rows: [[AnyView]]) -> AnyView { AnyView( makeWidget: { ctx in mountListFallback(rows, ctx: ctx) }, kind: .list(rows) ) } /// Applies an environment derivation to this node and every descendant. @_spi(Portico) public func deriving( _ derive: @escaping (MountContext) -> MountContext ) -> AnyView { AnyView( makeWidget: { ctx in makeWidget(derive(ctx)) }, kind: derivingKind(kind, derive) ) } } @MainActor private func derivingKind( _ kind: ViewNodeKind, _ derive: @escaping (MountContext) -> MountContext ) -> ViewNodeKind { switch kind { case .widget: return .widget case .group(let group): return .group(EnvironmentGroup(base: group, derive: derive)) case .conditional(.taken(let index, let content)): return .conditional(.taken(index: index, content: content.map { $0.deriving(derive) })) case .conditional(.complete(let selector, let arms)): return .conditional(.complete( selector: selector, arms: arms.map { arm in ConditionalArm(kind: arm.kind, build: { arm.build()?.map { $0.deriving(derive) } }, track: arm.track) } )) case .list(let rows): return .list(rows.map { $0.map { $0.deriving(derive) } }) } }