43 lines
2 KiB
Swift
43 lines
2 KiB
Swift
import Gtk
|
|
|
|
/// A live, order-independent reference to a widget produced elsewhere in the view tree.
|
|
///
|
|
/// Declare a reference with `@WidgetRef`, publish a producing view with ``View/ref(_:)``,
|
|
/// and pass the projected binding to any modifier that accepts the referenced widget.
|
|
/// The reference is initially `nil`; publishing another widget replaces the current value.
|
|
/// When the publishing subtree unmounts, the reference is cleared only if it still points
|
|
/// at that subtree's widget.
|
|
@propertyWrapper @MainActor public struct WidgetRef<W: Gtk.Widget> {
|
|
private let box = StateBox<W?>(nil)
|
|
|
|
/// Creates an unset widget reference.
|
|
public init() {}
|
|
|
|
/// The referenced widget, or `nil` until the view carrying ``View/ref(_:)`` mounts.
|
|
/// Reads track, so a tracked closure that reads this re-runs when the reference changes.
|
|
public var wrappedValue: W? { box.get() }
|
|
|
|
/// The read-only binding consumed by reference-taking widget modifiers.
|
|
/// Writes are ignored; publishing views own the reference value.
|
|
public var projectedValue: Binding<W?> { Binding(readOnly: box) }
|
|
|
|
/// Publishes a mounted widget and clears it when that publishing subtree tears down.
|
|
///
|
|
/// The widget is checked dynamically because Swift cannot express the relationship
|
|
/// between the publisher's target type and this reference's generic type. Multiple
|
|
/// publishers are allowed; the latest publisher wins, and an older publisher cannot
|
|
/// clear a newer value during teardown.
|
|
@_spi(Portico) public func _publish(_ widget: Gtk.Widget, registry: NodeRegistry) {
|
|
guard let typed = widget as? W else {
|
|
preconditionFailure(
|
|
"WidgetRef<\(W.self)>: .ref() applied to a view whose widget is \(type(of: widget)). Declare the ref at that type, or at a superclass of it."
|
|
)
|
|
}
|
|
box.set(typed)
|
|
registry.add(SubscriptionToken { [box] in
|
|
if box.peek() === typed {
|
|
box.set(nil)
|
|
}
|
|
})
|
|
}
|
|
}
|