Skip to main content

ChildPod

Struct ChildPod 

Source
pub struct ChildPod { /* private fields */ }
Expand description

A container’s owned child: a boxed widget plus the layout geometry and capture bookkeeping the container maintains for it.

Containers own their children directly as ChildPods (a Vec for Flex/Stack, named fields for Padding/Align) rather than as arena nodes — the WidgetTree arena stays single-root. This is a deliberate divergence from the masonry “everything in the arena” model: it needs zero global-id plumbing and no disjoint-borrow gymnastics for the container features this crate ships. Arena-backed children (for damage tracking / a11y global access) are deferred to a later phase.

origin/size are in the container’s local coordinate space; ChildPod::event_child translates events into the child’s local space and ChildPod::paint_child offsets the child’s paint origin accordingly.

Because the arena cannot see into a container, the pod also carries what read-only tooling needs to describe the element it wraps — type_name, debug_label, inspect_id, plus the geometry above — and Widget::visit_children is how a walk reaches it.

Implementations§

Source§

impl ChildPod

Source

pub const INSPECT_ID_BASE: u64

Where ChildPod::inspect_id’s allocator starts.

Pod ids and arena WidgetIds share one namespace in an inspect snapshot, and the arena’s are allocated from zero upward by BuildCtx::alloc_id. Starting the pod allocator at 2^48 keeps the two apart for any tree an app could plausibly build (the arena would have to allocate 281 trillion ids to reach it) without threading a shared counter through a read-only walk.

Source

pub fn new(widget: Box<dyn Widget>) -> Self

Wrap a freshly built child widget at the origin, with zero size until its first layout.

Source

pub fn type_name(&self) -> &'static str

The wrapped widget’s concrete type name, asked of the live widget (Widget::type_name) rather than recorded at build time — so a rebuild that swapped the child’s type can never leave a stale name here, and the double box build_child stores resolves through both layers.

Diagnostic only: type_name’s output is not a stable contract across compiler versions, so never parse or match on it.

Source

pub fn debug_label(&self) -> Option<&str>

The human name attached for tooling, if any. None by default.

Source

pub fn set_debug_label(&mut self, label: impl Into<Cow<'static, str>>)

Attach a human name for tooling (an inspector shows it beside the type name). Purely descriptive — nothing in the build/layout/paint/event path reads it.

Source

pub fn clear_debug_label(&mut self)

Drop any attached debug label.

Source

pub fn inspect_id(&self) -> WidgetId

This pod’s tooling id, assigning one on the first call and reusing it thereafter — so the id a devtools client holds keeps naming the same pod across frames, and across a keyed reorder that relocates the pod.

Behind &self (interior mutability) because the whole introspection seam is read-only; ids come from INSPECT_ID_BASE upward and never collide with an arena WidgetId.

Source

pub fn widget(&self) -> &dyn Widget

Shared access to the boxed child widget.

Source

pub fn widget_mut(&mut self) -> &mut dyn Widget

Mutable access to the boxed child widget (e.g. to downcast during a container’s own rebuild).

Source

pub fn set_widget(&mut self, widget: Box<dyn Widget>)

Replace the boxed child widget (used when a type-changing rebuild swaps the underlying widget).

Source

pub fn origin(&self) -> Point

The child’s origin in the container’s coordinate space.

Source

pub fn size(&self) -> Size

The child’s resolved size (valid after ChildPod::layout_child).

Source

pub fn set_origin(&mut self, origin: Point)

Place the child at origin within the container’s coordinate space.

Source

pub fn transform(&self) -> Option<Affine>

The child’s transform, if any (see ChildPod::set_transform).

Source

pub fn set_transform(&mut self, transform: Option<Affine>)

Place the child under an arbitrary transform, or clear it with None.

The transform is applied in the child’s own local space, before the origin offset: a child-local point p lands at origin + transform * p in the container’s space. So Affine::scale_about(2.0, center) zooms the child about its own local center, and a pan/zoom container can leave origin at zero and drive the whole placement through the transform.

While one is set:

A transform with no inverse (a zero scale, a collapsed axis, a non-finite coefficient — see crate::hit::checked_inverse) draws nothing and hits nothing: contains is false and paint skips the subtree. An event that still reaches the child through a recorded capture or focus path is delivered translated by -origin only, so a capture can always release.

Out of v1’s reach: rects a descendant reports in window space from paint (platform-view frames, input shields, hero rects, overlay anchors) are not mapped through the transform.

Source

pub fn is_active(&self) -> bool

Whether this child currently holds the recorded active (captured) path.

Source

pub fn set_active(&mut self, active: bool)

Set (or clear) the recorded active path — the container clears this on Up/Cancel when capture auto-releases.

The link is keyed on the gesture’s claimant. While the root is delivering a non-claimant contact down a live capture’s path (rule (c) of InputEvent::PointerContact’s multi-contact contract), a clear is refused: that contact’s Up/Cancel reaches every container on the path, and a container clearing its link on it would strand the claimant’s own follow-ups. Outside such a pass — every single-pointer dispatch, a rebuild, a container’s own teardown — a clear takes effect as always.

A container that clears the link to take the gesture over from its child (rather than because the gesture ended) should release it through EventCtx::release_captured_child instead, which also ends the gesture’s contact opt-in when the released subtree held it.

Source

pub fn is_focused(&self) -> bool

Whether this child has a recorded focus path at all — not whether that record belongs to the session the root currently holds.

The raw flag, kept for the things that legitimately want it: a paint-time culling exemption, a blur sweep clearing whatever it finds, a container asking “did I ever record a link here”. Deciding where a focus-routed event goes, or whether a widget may speak for the focus session, needs ChildPod::holds_live_focus instead — a link this flag reports can be one a moved session left behind, and there is no pass that visits an abandoned branch to clear it.

Source

pub fn set_focused(&mut self, focused: bool)

Record (or drop) this child’s focus path against the live session.

Setting it stamps the session standing on this thread (set_live_focus_session) beside the flag, so the link says which session it belongs to rather than merely that one existed; clearing it leaves the stamp alone, which costs nothing because the flag gates every read. Containers clear it on blur-on-outside-tap and set it when a child requests focus; the flag is maintained automatically by ChildPod::event_child on a focus_requested/focus_released bubble.

Source

pub fn focus_epoch(&self) -> u64

The focus epoch this pod’s recorded link was stamped with — the focus counterpart of ChildPod::hover_epoch, and just as much an identity rather than an ordering or a boolean.

Diagnostic only, for the same reason the hover stamp’s accessor is: a stamp is never cleared, only stranded by the next session, so a non-zero value means “a claim passed through here once”, never “focused”. Ask ChildPod::holds_live_focus, which is the comparison this exists for.

Source

pub fn holds_live_focus(&self) -> bool

Whether this child holds a focus link on the session the root currently has — the read every routing and provenance decision wants.

true only while the flag is set and the stamp names the live session (set_live_focus_session). Two branches can both carry a set flag — an overlay pod’s claim reaches no container’s blur sweep, so the branch it superseded keeps its own record — and this is what tells them apart without either branch having to be visited.

A dispatch driven with no root at all reads (0, 0) on both sides, so a pod that claimed focus during such a dispatch answers true: with no session to be stale relative to, the flag is all there is.

Drop a recorded focus link that the live session has already stranded, reporting whether one was dropped.

The retirement seam a RenderRoot needs and cannot otherwise have. A pod floated by the overlay portal lives off the tree, behind its owner’s Rc, and the root borrows it for exactly the length of the paint pass that floats it — so the one moment the root can act on such a link is that pass, and the one thing it can honestly say about it is what the stamp already decides. Calling this keeps the raw flag and the stamp telling the same story, which is what the consumers of ChildPod::is_focused that cannot consult an epoch depend on.

Deliberately not a bare set_focused(false) at the call site: the condition is the whole contract, and a pod whose link is live must never be retired by a pass that merely walked past it.

Source

pub fn hover_epoch(&self) -> u64

The hover epoch this pod’s recorded hover link belongs to — the hover counterpart of ChildPod::is_focused, reported as a stamp rather than a flag because “is it hovered?” is only answerable against the live epoch (0 means no claim has ever passed through this pod).

There is no setter: the stamp is maintained solely by ChildPod::event_child from a claim bubble, so a container cannot record or clear a hover link by hand — which is what keeps at most one path hovered. See the crate::event module docs.

§A bare stamp answers nothing

The returned u64 is an identity, not an ordering and not a boolean. It means something only compared for equality against the live epoch, and that comparison is the pipeline’s own: the live epoch rides the running context (PaintCtx::hover_epoch/EventCtx::hover_epoch), both crate-private, and the comparison is already ANDed with the ancestor chain by paint_child/event_child before any widget sees it. Treating a non-zero stamp as “hovered”, or ordering two pods’ stamps, reads reasonable and is wrong: a stamp is never cleared, only stranded by the next epoch advance, so a pod the pointer left an hour ago still carries a non-zero one, and the counter wraps.

Read PaintCtx::is_hovered instead (authoritative), or EventCtx::is_hovered for the state as of the previous pass; between them they answer “is this widget or its subtree hovered” — which is the question a widget actually has. A container asking the narrower “which of my children” answers it with the same hit test its own claim rides, not from here. This accessor is diagnostic — tooling, tests, and the debug dump — the way ChildPod::type_name is.

Source

pub fn layout_child( &mut self, ctx: &mut LayoutCtx<'_>, bc: &BoxConstraints, ) -> Size

Lay the child out under bc, recording and returning its chosen size.

Source

pub fn paint_child( &mut self, ctx: &mut PaintCtx<'_>, scene: &mut dyn PaintScene, )

Paint the child, offsetting its paint origin by the container’s origin (ctx.origin()) so the child draws at its absolute position.

Bubbles the child’s animation-continuation request (PaintCtx::needs_frame) back into the parent ctx, mirroring ChildPod::event_child’s absorb of the child’s redraw/capture flags — so a nested flinging widget keeps the whole tree’s frames coming.

A pod with a transform additionally wraps that paint in PaintScene::push_transform/PaintScene::pop_transform (and skips it entirely when the transform has no inverse); an untransformed pod pushes nothing.

Source

pub fn semantics_child(&self, ctx: &mut SemanticsCtx)

Collect the child’s semantics, translating the current absolute origin into the child’s space exactly like ChildPod::paint_child offsets its paint origin (child_origin = ctx.origin() + self.origin).

A container’s Widget::semantics calls this for each of its ChildPods so their nodes attach under the container’s node (or, for a transparent container, under whatever encloses it — see crate::semantics).

A pod with a transform reports its subtree at the axis-aligned bounding box of the transformed child rect — an approximation: descendants are offset from that box’s corner, unscaled and unrotated.

Source

pub fn event_child( &mut self, ctx: &mut EventCtx<'_>, event: &InputEvent, ) -> EventResult

Route an event into the child, translating its position into the child’s local space and folding the child’s redraw/capture flags back into ctx.

If the child captured the pointer, this records the active path (ChildPod::is_active); the container clears it on Up/Cancel.

Containers should not call this directly gated on an ad-hoc contains() check — that drops a captured gesture the instant it moves outside the child’s bounds. Route through frust-widgets’ route_event/route_event_single helpers instead, which check ChildPod::is_active first and forward unconditionally to a captured child.

A pod with a transform maps positions through the inverse of its local→container mapping instead (InputEvent::transformed); everything else about the dispatch — capture, contact and focus bookkeeping, hover — is identical.

§Another contact walks the active path forward-only

A non-claimant contact the root delivers down a live capture (rule (c) of InputEvent::PointerContact’s contract) is meant for the widget that opted in with EventCtx::capture_contacts — the captor — and for nothing above it. The containers between the root and the captor must not run their own pointer handling on it: a scroll view that saw a second finger’s Down as its own would re-arm its drag from the wrong finger and take the gesture away from the captor on the claimant’s next move.

A pod cannot reach into its child widget’s own pods, so the walk travels on the one route every container already provides without running its pointer machinery: the broadcast-first rule. While the root walks such a contact, each container on the path is handed an inert carrier (an InputEvent::Overlay addressed to a key no overlay owner holds, which every widget ignores and every container forwards to its children before anything else), and the real event rides beside it, re-based into each pod’s space on the way down. This method then decides, per pod:

  • Off the recorded active path: nothing — the child widget is not called at all.
  • The captor (the child itself opted in on the capture that made this pod active): the child receives the real event, translated as usual, with the walk closed, so it — and whatever it routes below itself — handles the contact the ordinary way. The walk ends here: a widget below the captor that also opted in hears the contact only if the captor forwards it.
  • On the path, above the captor: the child receives the carrier, so its own handler runs but none of its gesture, capture, focus, blur or hit-test logic does; the walk continues into its children. The result reported upward is the captor’s, not the carrier’s Ignored. If the carrier never reaches a pod on the path (a container whose captured child is not one of its broadcast targets — an overlay owner whose captured pod is a floated surface), this child alone is handed the real event the ordinary way instead.

Everything this method folds back into ctx — redraw, capture, focus, IME — still bubbles from the captor through every pod on the way back up. No hover, cursor or blur bookkeeping moves: the root opens no hover pass for a non-claimant contact, and no container above the captor runs the blur sweep it would run on a Down. Every other dispatch, including the claimant’s own events, takes exactly the path described above this section.

Source

pub fn contains(&self, point: Point) -> bool

Whether point (in the container’s coordinate space) lies within this child’s bounds — the container’s hit test.

This is only the initial hit test (deciding which child a fresh Down/first contact goes to). Once a child has captured the pointer (ChildPod::is_active), subsequent events must bypass this check and go straight to the captured child regardless of where the point now falls — see frust-widgets’ route_event/route_event_single.

A pod with a transform maps point back through the transform first, so the test agrees with what paint drew; a transform with no inverse hits nothing.

Trait Implementations§

Source§

impl Drop for ChildPod

Source§

fn drop(&mut self)

Report a live hover link severed by the pod’s own removal, so RenderRoot::rebuild ends the hover before the frame ends.

The epoch mechanism strands a stale stamp on every hover pass, but a pass is exactly what a removed widget no longer gets: a rebuild that drops the claimant leaves the root’s mirror standing (is_hover_active() keeps reporting a link nothing holds) and leaves every surviving ancestor of the dead claimant reading hovered off its own still-matching stamp, until some later Move happens to re-derive — which never arrives on a pointer the user has stopped moving. This destructor is the hover analog of the focus-orphan mark, and lives here rather than in the reconcilers because the stamp has no setter for a container to cooperate through; see crate::event::mark_hover_orphaned for the full rationale and the “only when the link was live” invariant this comparison enforces.

The comparison is against the published (root, epoch) pair, not the epoch alone: per-root counters collide, so an unqualified match would let a pod of one root end another root’s live hover (see hover_root).

Costs one predictable branch on a u64 field per pod dropped; the thread-local read happens only for the pod chain that has actually held a claim at some point.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. 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
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> StorageAccess<T> for T

Source§

fn as_borrowed(&self) -> &T

Borrows the value.
Source§

fn into_taken(self) -> T

Takes the value.
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.