60 lines
1.7 KiB
Swift
60 lines
1.7 KiB
Swift
import Gtk
|
|
|
|
// MARK: - Label
|
|
|
|
/// A text label backed by `Gtk.Label` with three source modes:
|
|
/// constant text, explicit ``Binding``, and a tracked closure.
|
|
///
|
|
/// Reactive forms (`Binding` and closure) update the label in place
|
|
/// — the widget is never recreated on state change.
|
|
@MainActor public struct Label: View {
|
|
private enum Source {
|
|
case constant(String)
|
|
case binding(Binding<String>)
|
|
case dynamic(() -> String)
|
|
}
|
|
|
|
private let source: Source
|
|
|
|
public var body: Never { fatalError() }
|
|
|
|
/// Creates a static label that never changes.
|
|
public init(_ text: String) {
|
|
source = .constant(text)
|
|
}
|
|
|
|
/// Creates a label that updates when the binding changes.
|
|
public init(_ text: Binding<String>) {
|
|
source = .binding(text)
|
|
}
|
|
|
|
/// Creates a label whose text is recomputed via a tracked closure
|
|
/// whenever any state read inside it changes.
|
|
public init(_ make: @escaping () -> String) {
|
|
source = .dynamic(make)
|
|
}
|
|
}
|
|
|
|
// MARK: - Mountable
|
|
|
|
@_spi(Portico) extension Label: Mountable {
|
|
@_spi(Portico) public func mount(_ ctx: MountContext) -> Gtk.Widget {
|
|
let label = Gtk.Label(str: "")
|
|
switch source {
|
|
case .constant(let s):
|
|
label.setText(str: s)
|
|
case .binding(let b):
|
|
label.setText(str: b.wrappedValue)
|
|
ctx.registry.add(b.subscribe { [label] v in
|
|
label.setText(str: v)
|
|
})
|
|
case .dynamic(let make):
|
|
let tracker = DependencyTracker { [label] in
|
|
label.setText(str: make())
|
|
}
|
|
tracker.run()
|
|
ctx.registry.add(tracker)
|
|
}
|
|
return label
|
|
}
|
|
}
|