MirrorState

class MirrorState<V> @RememberInComposition constructor(initial: V) : State<V>

Mirrors the value a widget property currently holds - a property the widget can change on its own, independently of the composition's declaration - and carries a change the composition has not answered for to the scope that declares it.

The mirror is that value as a State, so value answers with what the widget holds now, and reading it while composing subscribes - as subscribe does for a component that needs the news without the value. A widget property is not versioned, so what value answers with is the live value rather than any snapshot's.

A component subscribed to the mirror is invalidated when the widget's value changes under its declaration - whether the user changed it, or a write to some other property of the same widget did. A change a settle made and recorded the widget's answer to is the one kind that invalidates nothing: it is where the declaration was already heading, and the pass that made it has already been told where it landed. Settling - reconciling a declaration against what the widget holds - runs during a composition pass, not at the moment of the change, because the declaration to settle against only exists while a pass is running.

A change is reported as it happens, and the caller either adopts it into its declared state or does not. The next pass acts on that answer: an adopted change leaves the widget alone, an unadopted one writes the declaration back, so the widget snaps away from what the user left it holding.

Swing asks for the repaint a change provokes while the widget is still handling it, ahead of anything the report of that change can schedule. A change carried to the caller through report settles inside the event that made it wherever a frame can run there, so the declaration is back on the widget before that repaint is served and the rejected value is never shown. A change only observed leaves the pass a later event, following within a few event-dispatch cycles, inside a single display refresh interval: the widget can be painted once holding a value the caller rejected, and what is bounded is how long that value survives. A reported change takes that same later pass where a frame is already running, or where something else is waiting for one.

Runs on the event dispatch thread.

Parameters

initial

the value the widget holds before any declaration has been settled onto it.

Constructors

Link copied to clipboard
@RememberInComposition
constructor(initial: V)

Types

Link copied to clipboard
sealed interface SettlementScope<in V>

What a settlement says the widget was left holding. See the MirrorState.settle a block runs in.

Properties

Link copied to clipboard

Whether a write of this wrapper's own to its widget is currently in flight. It is true only for the length of a write, which runs to completion on the event dispatch thread.

Link copied to clipboard
open override val value: V

The widget's current value. Reading it while composing subscribes to the widget's value changing under its declaration, as subscribe does - a change a settle answered for is the one kind that is not such news.

Functions

Link copied to clipboard
fun observed(published: V): Boolean

Mirrors published as what the widget now holds, and returns whether it is a change by the user: a value that differs from what the mirror held before, and that did not happen inside a write of this wrapper's own.

Link copied to clipboard
fun report(published: V, onChanged: (V) -> Unit)

Carries a value the widget published to the caller: mirrors published through observed and, where that is a change of the user's, hands it to onChanged and settles the composition on the answer - inside the event that made the change wherever a frame can run there, so the declaration is back on the widget before the repaint that change asked for is served. Where one cannot, the pass follows a later event, as it does for a change only observed.

Link copied to clipboard
fun MirrorState<*>.report(onChanged: () -> Unit)

Carries to the caller a change the widget published on one channel and reports on another: onChanged runs and the settling pass follows it, as in MirrorState.report, but the value itself was mirrored through MirrorState.observed when the earlier channel carried it.

Link copied to clipboard
fun <R> settle(block: MirrorState.SettlementScope<V>.() -> R): R

Runs block as a settlement of this mirror's own: the value the widget is left holding when it returns is one this pass asked for and read back itself, so it is recorded as an answer rather than as news.

fun settle(declared: V, read: () -> V, write: (V) -> Unit, onSettled: (V) -> Unit = {})

Settles the widget on declared: writes it through write unless read already answers with it. The value the widget ends up holding becomes the baseline later changes are measured against, and the one declared has now been answered for, so a widget that answered with a value of its own is not written again on every later pass.

Link copied to clipboard
fun subscribe()

Subscribes the composing scope to the widget's value changing under its declaration, so that a change the caller does not adopt brings the pass that puts the declaration back. Answers nothing: what a subscribed scope does about a change is read the widget on the pass after it.

Link copied to clipboard
fun write(block: () -> Unit)

Runs block as the wrapper's own write to its widget, so the events it raises are recognizable as such rather than as something the user did.