ItemA11yDecorations
The owning salvage door: everything Scene::remove
destroys, moved out instead of dropped.
Why a second channel exists at all
ItemChange travels through a Signal, and
Signal<T> requires T: Clone (it snapshots the value before fanning out).
A SceneItem is a Box<dyn SceneItem> with no clone_item and no
downcast, and a heavyweight entry holds a Box<dyn Widget>. Neither can be
cloned, so the removed entry can never ride the notification channel —
not as a design preference but as a type fact. It has to be moved, which
means a door that hands ownership over.
That door is Scene::take (the caller keeps the
salvage) and the SceneTransactionRecord
delivered to the edit sink (the framework hands it over). Both produce
RemovedItems; Scene::restore puts one back.
What a removal used to destroy
Scene::remove drops, in this order: the entry (its item or widget box, its
handlers, its geometry, its flags), then the item's slice of the logical
accessibility tree — AT parent, AT relations, live-region status, landmark
role, rotor categories — then its magnets. Only after all of that does it
announce ItemChange::Removed. So an app that reconstructed the item from
the event alone would restore the pixels and silently lose every one of
those. On a crate whose differentiator is per-item accessibility, that is
the single strongest reason this door exists.
The edges a naive salvage misses
The logical AT tree is a graph, and a removal cuts edges on both sides:
- the removed item's own AT parent (
removed → parent), and - every surviving node that was AT-parented under the removed item
(
survivor → removed), whichremovealso drops — re-rooting those survivors at the view root.
Recording only the first would make restore silently fail to re-adopt the
survivors, i.e. fail at exactly the edge case the salvage is sold on. So
ItemA11yDecorations carries both directions, and the same applies to
relations, which remove retains on either endpoint.
Builder methods at a glance
is_empty
API reference
📖 Full rustdoc API for this module
pub struct ItemA11yDecorations
The per-item slice of the logical accessibility tree, harvested by
Scene::take and re-attached by
Scene::restore.
Both directions of every edge, because a removal cuts both — see the module docs. A restore re-attaches only the edges whose other endpoint is still alive; an edge to something that has since been removed is dropped, because re-inserting it would name a node the AT walker cannot resolve.
#![allow(unused)] fn main() { pub struct ItemA11yDecorations { /* fields */ } }
Methods
pub fn is_empty(&self) -> bool
Whether this item carried any logical-AT decoration at all. A restore of an undecorated item touches none of the scene's AT maps.
pub struct RemovedItem
One item lifted whole out of a Scene: its entry, its
magnets and its logical-AT decorations, still owned and still carrying its
original ItemId.
Opaque on purpose. It wraps the crate-private SceneEntry whole rather
than copying its fields out, so a future field added to the entry cannot be
missed by Scene::restore — the same argument the
single-construction-site rule makes for insertion.
Ordering
Scene::take returns a subtree deepest-first, the
order remove already announces in.
Scene::restore_all reverses it for you;
restoring by hand means roots first, or a child hits
RestoreError::MissingParent.
#![allow(unused)] fn main() { pub struct RemovedItem { /* fields */ } }
Methods
pub fn id(&self) -> ItemId
The id this item had, and the id
Scene::restore puts it back at.
pub fn local_pos(&self) -> Point
Position in the parent's coordinate frame.
pub fn local_bounds(&self) -> Rect
AABB in local coordinates.
pub fn transform(&self) -> Transform2D
Local→parent transform.
pub fn z(&self) -> f32
Paint z-order.
pub fn layer(&self) -> SceneLayer
Lightweight paint band.
pub fn parent(&self) -> Option<ItemId>
Logical parent at the moment of removal. A restore needs this item
present, or it fails with RestoreError::MissingParent.
pub fn detach(&mut self)
Forget the recorded parent, so this salvage restores at root level.
The door RestoreError::MissingParent points at, and the one a
move between scenes needs: the parent a salvage names is still in the
scene it came from, so restoring a parented item into a second scene is
refused unless its parent went first — or unless the caller says, here,
that it should arrive unparented.
Nothing else changes: geometry is untouched, so an item that was placed
in its parent's frame keeps those numbers and now reads them as scene
coordinates. Use
Scene::reparent_keeping_scene_pos
after the restore when the item should not visibly move.
pub fn children(&self) -> &[ItemId]
Direct children at the moment of removal — all of them removed with it,
and all of them present in the same Scene::take
result.
pub fn flags(&self) -> ItemFlags
Behaviour flags.
pub fn opacity(&self) -> f32
Local opacity multiplier.
pub fn is_widget(&self) -> bool
Whether this was a heavyweight Widget entry rather than a lightweight
SceneItem one.
pub fn item(&self) -> Option<&dyn SceneItem>
The lightweight item, if this was one. None for widget entries.
pub fn into_item(self) -> Option<Box<dyn SceneItem>>
Consume the salvage for its lightweight item box — cut-to-clipboard.
None for widget entries (and the salvage is dropped either way).
pub fn payload(&self) -> Option<std::rc::Rc<dyn std::any::Any>>
The type-erased payload of a multi-view (Delegated) heavyweight
entry, which is what lets a restored card be rebuilt by every view's
delegate. None for a lightweight item and for a single-view
(Scene::add_widget) entry.
pub fn widget_instance_present(&self) -> bool
Whether a single-view (Scene::add_widget) entry still carries its
one Box<dyn Widget>.
true for every lightweight item and for every multi-view
(add_widget_item) entry, because neither depends on a one-shot box.
This is a fact about the salvage, not a verdict on restorability,
and the distinction matters: a Once widget already drained by a
mounted view restores perfectly well when the take and the restore
happen inside one build cycle (the view's orphan reap keys on the
scene's live heavyweight set, which the restore has already put the id
back into, so the arena instance is never destroyed). Refusing such a
restore would refuse one that works — and would refuse the whole entry,
geometry and accessibility included, over a widget instance.
So Scene::restore always accepts, and this
reports what an app needs to decide for itself. When false and the
view has already reaped the instance, the restored entry is a
heavyweight slot with nothing to materialise — visible to no view. The
rule that avoids it entirely is the same one multi-view content already
follows: content that must survive an undo goes in through
SceneModel::add_widget_item,
whose payload every view can rebuild from.
pub fn a11y(&self) -> &ItemA11yDecorations
The logical-AT decorations this item carried — both directions of every
edge. See ItemA11yDecorations.
pub fn magnet_count(&self) -> usize
How many magnets were attached to this item. Their ids are preserved by
a restore, so a consumer keying connections on
MagnetId keeps them.
pub enum RestoreError
Why Scene::restore could not put a salvage back.
#[non_exhaustive]: this crate has out-of-tree consumers and the restore
path may learn to refuse something new.
#![allow(unused)] fn main() { pub enum RestoreError { /* variants */ } }
Variants
IdAlreadyLive— An entry with this id is already in the scene. Restoring over it would alias two items onto one identity. Defensive.Scene::takeretires the id, so a second salvage for it cannot exist while the first is held, and the restore that succeeds consumes the one that does — which makes this unreachable through the public API today. It stays because it is the only thing standing between a future door that breaks that invariant and a corruptedentry_index, and refusing is better than aliasing.MissingParent— The parent the item was removed from is not in the scene. Restore roots-first —Scene::restore_allorders a wholetakeresult for you — or clear the recorded parent withRemovedItem::detachbefore restoring, which is what a move into a different scene normally wants. The salvage is consumed by the refused call, so a caller that may hit this checksparent()(or callsdetach()) before handing it over.
pub struct ReplaceRejected
A refused Scene::replace_item: why, and the
item it did not take.
The item comes back rather than being dropped, because a refused write must
not eat the caller's value. A Box<dyn SceneItem> can be expensive to build
and cannot be cloned, so a caller recovering from a precondition violation
would otherwise have nothing left to insert instead — and the row it was
reconciling would silently vanish.
#[non_exhaustive]: see RestoreError. The crate only ever hands this
out, so there is nothing to construct — recover the item with
let ReplaceRejected { item, .. } = rejected;.
#![allow(unused)] fn main() { pub struct ReplaceRejected { /* fields */ } }
pub enum ReplaceItemError
Why Scene::replace_item could not swap an
item box. Travels inside a ReplaceRejected, which also carries the item.
#[non_exhaustive]: see RestoreError.
#![allow(unused)] fn main() { pub enum ReplaceItemError { /* variants */ } }
Variants
UnknownItem— No entry with this id.NotLightweight— The entry is a heavyweightWidget, which holds noSceneItembox. Replace its data withSceneModel::set_payloadinstead.