Skip to main content

ItemChange

Enum ItemChange 

Source
#[non_exhaustive]
pub enum ItemChange {
Show 18 variants LocalPosChanged { id: ItemId, old: Point, new: Point, }, LocalBoundsChanged { id: ItemId, old: Rect, new: Rect, }, MeasuredSizeChanged { id: ItemId, old: Rect, new: Rect, }, SizePolicyChanged { id: ItemId, old: SizePolicy, new: SizePolicy, }, TransformChanged { id: ItemId, old: Transform2D, new: Transform2D, }, VisibilityChanged { id: ItemId, visible: bool, }, FlagsChanged { id: ItemId, old: ItemFlags, new: ItemFlags, }, OpacityChanged { id: ItemId, old: f32, new: f32, }, ZChanged { id: ItemId, old: f32, new: f32, }, LayerChanged { id: ItemId, old: SceneLayer, new: SceneLayer, }, ParentChanged { id: ItemId, old: Option<ItemId>, new: Option<ItemId>, }, Removed { id: ItemId, }, Added { id: ItemId, }, PayloadChanged { id: ItemId, old: ItemPayload, new: ItemPayload, }, AppearanceChanged { id: ItemId, change: AppearanceChange, }, ItemReplaced { id: ItemId, old_bounds: Rect, new_bounds: Rect, }, PlacementChanged { id: ItemId, old: Placement, new: Placement, }, HandlersChanged { id: ItemId, replaced: Option<Box<HandlerReplacement>>, },
}
Expand description

A change to an item’s state, fired through Scene::item_change_signal for every mutation. Apps observe to wire validation, persistence, telemetry, mirroring to a data layer, and other side effects. The model is “fire after the change has been applied” — by the time the observer sees the event, the Scene already reflects it, and (when the mutation came through a SceneModel) the observer may freely read and write the scene back.

§Edits and derived notifications

Most variants are edits: one mutation, one variant, both sides of the value it replaced, and SceneTransactionRecord::edits carries them so a data layer can invert the transaction by walking them in reverse.

VisibilityChanged is not one. It is a derived notification — a convenience beside the FlagsChanged that actually describes the mutation, emitted by both flag doors whenever IS_VISIBLE flips so a consumer need not diff two bitsets. It rides the signal and stays out of the record, so hiding a card is one edit whichever door hid it. is_edit is the test, for a consumer that counts changes off the signal and wants the same number the record has.

#[non_exhaustive]: this is the crate’s outbound event vocabulary, matched by every observer, and it grows whenever the scene learns to report something new — MeasuredSizeChanged and SizePolicyChanged are the most recent. Without the attribute each such addition would stop a downstream match from compiling; with it, a consumer’s wildcard arm keeps meaning “a change I do not act on”.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

LocalPosChanged

set_local_pos: position in parent coords moved.

Fields

§id: ItemId

The item that moved.

§old: Point

Where it was, in its parent’s frame.

§new: Point

Where it is now.

§

LocalBoundsChanged

set_local_bounds: AABB in local coords changed.

Fields

§id: ItemId

The item that resized.

§old: Rect

Its AABB in local coordinates before the write.

§new: Rect

Its AABB now.

§

MeasuredSizeChanged

set_measured_size: a derived geometry write — the size an entry under a non-Fixed SizePolicy measured from its widget, or one an app computed from content it already owns.

Separate from LocalBoundsChanged because it means something different to every consumer of the channel:

  • It is not an edit. is_edit is false and the change is stamped ephemeral, so a history above the scene does not gain an undo step because a paragraph re-wrapped. A reflow is a function of content the document already holds; undoing it would mean undoing the width or the words.
  • It is not structural. It is counted out of Scene::structural_version, the way refresh_dynamic_bounds’s per-frame churn is, so a line wrap does not buy an AccessKit re-walk.
  • The observing SceneView answers it with a relayout, not a rebuild: the geometry moved, nothing was materialised or reaped, and the delegate does not need re-running.

An app mirroring scene geometry into its document should match LocalBoundsChanged and ignore this one. An app that wants the measured height persisted anyway (so a cold start opens at the right size without waiting for a measurement) can read it and store it as a hint.

Fields

§id: ItemId

The entry whose derived size changed.

§old: Rect

Its AABB in local coordinates before the write.

§new: Rect

Its AABB now. Same origin; the size is what moved.

§

SizePolicyChanged

set_size_policy: who decides this entry’s box changed.

An edit, unlike the MeasuredSizeChanged that follows it: “this note’s height follows its words” is a decision someone made about the document, the way a flag change is, and a history above the scene should be able to put it back.

It carries no geometry — the policy decides how the next layout pass computes one. It exists at all because nothing else would tell a view that the answer to a question it asks every pass has changed: a policy written silently would take effect whenever something unrelated happened to dirty the view, which in a test is never and in an app is worse — unpredictable.

Fields

§id: ItemId

The heavyweight entry whose policy changed.

§old: SizePolicy

Who decided its box before.

§new: SizePolicy

Who decides it now.

§

TransformChanged

set_transform: local→parent transform changed.

Fields

§id: ItemId

The item whose basis changed.

§old: Transform2D

Its local→parent transform before the write.

§new: Transform2D

Its local→parent transform now.

§

VisibilityChanged

IS_VISIBLE flipped, by whichever door flipped it — set_visible, set_flag or a wholesale set_flags.

A derived notification, always emitted immediately before the FlagsChanged that describes the same mutation. It exists so a consumer that only cares about visibility need not diff two ItemFlags bitsets, and it is deliberately not an edit: is_edit is false for it and it never reaches a transaction record, so one mutation is one recorded edit no matter which door made it. (It used to be emitted by set_flag and not by set_flags, which made hiding a card two recorded changes through one door and one through the other.)

Fields

§id: ItemId

The item whose IS_VISIBLE bit flipped.

§visible: bool

The bit’s new value. Its own value, not the inherited one — Scene::is_effectively_visible chains the parents.

§

FlagsChanged

set_flags / set_flag changed the bitset. The edit that describes a flag change, visibility included.

Fields

§id: ItemId

The item whose flags changed.

§old: ItemFlags

The whole bitset before the write.

§new: ItemFlags

The whole bitset now. Diff the two to see which bits moved.

§

OpacityChanged

set_opacity: local opacity multiplier changed.

Fields

§id: ItemId

The item whose opacity changed.

§old: f32

Its local multiplier before the write.

§new: f32

Its local multiplier now.

§

ZChanged

set_z: paint z-order changed.

Fields

§id: ItemId

The item that restacked.

§old: f32

Its paint z before the write.

§new: f32

Its paint z now.

§

LayerChanged

set_layer: the Under/Over paint band changed.

Fields

§id: ItemId

The item that changed band.

§old: SceneLayer

The band it was in.

§new: SceneLayer

The band it is in now.

§

ParentChanged

set_item_parent: logical parent changed.

Fields

§id: ItemId

The child that was reparented.

§old: Option<ItemId>

Its logical parent before the write; None when it was a root.

§new: Option<ItemId>

Its logical parent now; None when it is now a root.

§

Removed

remove: item is gone.

Fields

§id: ItemId

The item that is gone. Its contents travel the owning channel: Scene::take hands the caller a RemovedItem, and Scene::remove routes one to the edit sink.

§

Added

add_item / add_widget: item was inserted.

Fields

§id: ItemId

The item that was inserted.

§

PayloadChanged

set_payload: the type-erased payload of a Delegated heavyweight entry was replaced. A SceneView rebuilds that entry’s widget (re-invokes its delegate) on the next build. Routed through emit_item_change, so mutation_seq advances and the AT-walk gate notices.

Fields

§id: ItemId

The Delegated heavyweight entry whose data was replaced.

§old: ItemPayload

The payload every view built its widget from until now.

§new: ItemPayload

The payload every view will rebuild from.

§

AppearanceChanged

set_item_fill / set_item_stroke / clear_item_*: a lightweight item’s paint-only appearance (fill / stroke colour or style) changed. Never moves geometry, so the observing SceneView evicts the item’s cached frame and repaints without relayout or rebuild.

It can move the item’s hit shape, though: a stroked PathItem derives its hit band from the stroke it draws, so a view caching hit geometry must re-read this item’s shape even while skipping relayout.

Fields

§id: ItemId

The lightweight item that was recoloured.

§change: AppearanceChange

Which of fill or stroke moved, and to what.

§

ItemReplaced

replace_item: the lightweight item box at this id was swapped for a different one, keeping the entry — position, transform, z, layer, parent, flags, opacity, handlers, magnets and logical-AT decorations all survive, and so does the ItemId.

One change, not Removed + Added, because nothing about the item’s identity changed. Consumers must treat it as a geometry change: the new item carries its own local_bounds and its own hit shape.

old_bounds / new_bounds are the entry’s AABB either side of the swap; the replaced box itself is returned to whoever called Scene::replace_item.

Fields

§id: ItemId

The entry whose item box was swapped. Its ItemId is unchanged.

§old_bounds: Rect

The entry’s AABB before the swap.

§new_bounds: Rect

The entry’s AABB after it, carried by the new box.

§

PlacementChanged

set_placement: parent, z, local position and transform written together as one property.

The atomic form of the four separate mutators. A visually-stable reparent (“drag this card into that group”) is one edit here, where set_item_parent + set_local_pos + set_transform is three edits, three undo steps, and two intermediate states in which the item is visibly in the wrong place.

Fields

§id: ItemId

The item that was placed.

§old: Placement

Parent, z, local position and transform before the write.

§new: Placement

All four now.

§

HandlersChanged

set_item_handlers / handlers_mut: the item’s handler set was replaced or handed out for mutation.

Always means at least “this item’s handlers are no longer what you last read”, which is what a consumer caching them — the SceneView’s dispatch snapshot — needs. Without it, the two handler mutators were the only doors in the model that changed observable state silently.

Whether it also describes the change is replaced; see HandlerReplacement.

Fields

§id: ItemId

The item whose handlers changed.

§replaced: Option<Box<HandlerReplacement>>

Both sides, when the door that fired this knew them.

Some from Scene::set_item_handlers, which is handed the new set and can clone the old one out — so that door produces a reversible edit like every other mutator.

None from Scene::handlers_mut, which fires on the way in: a &mut borrow cannot report what the caller will do with it, and there is no later moment the scene is told about. That call is an invalidation notice and nothing finer, so it is not recorded as an edit — a record claiming to carry both sides must not carry an entry that carries neither. An app that wants its handler edits in the history makes them through set_item_handlers.

Boxed because a SceneItemHandlerSet is a wide struct and this is the rarest variant: inline, two of them would set the size of every ItemChange, every SceneChange and every queued notification — a per-pointer-sample cost for a setup-time call.

Implementations§

Source§

impl ItemChange

Source

pub fn id(&self) -> ItemId

The item this change is about.

Every variant names exactly one item, so an observer that only needs which item moved need not match the whole enum. The fan-out’s runaway detector reads it too: it charges each delivery to the subject it is about, so it needs that subject without caring what kind of change it is. (Those per-subject counts name the culprit in the panic; the bound that trips is a flat total — see CascadeBudget.)

Source

pub fn is_edit(&self) -> bool

Whether this change is an edit — a mutation a transaction record carries — rather than a derived notification the scene emits beside one for a consumer’s convenience.

Three variants are not edits:

Filtering the change signal by this gives the same count the transaction record has, which is what an app showing “N changes in this edit” needs: hiding a card is one change through Scene::set_visible and one through Scene::set_flags.

Trait Implementations§

Source§

impl Clone for ItemChange

Source§

fn clone(&self) -> ItemChange

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ItemChange

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more