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
impl ChildPod
Sourcepub const INSPECT_ID_BASE: u64
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.
Sourcepub fn new(widget: Box<dyn Widget>) -> Self
pub fn new(widget: Box<dyn Widget>) -> Self
Wrap a freshly built child widget at the origin, with zero size until its first layout.
Sourcepub fn type_name(&self) -> &'static str
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.
Sourcepub fn debug_label(&self) -> Option<&str>
pub fn debug_label(&self) -> Option<&str>
The human name attached for tooling, if any. None by default.
Sourcepub fn set_debug_label(&mut self, label: impl Into<Cow<'static, str>>)
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.
Sourcepub fn clear_debug_label(&mut self)
pub fn clear_debug_label(&mut self)
Drop any attached debug label.
Sourcepub fn inspect_id(&self) -> WidgetId
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.
Sourcepub fn widget_mut(&mut self) -> &mut dyn Widget
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).
Sourcepub fn set_widget(&mut self, widget: Box<dyn Widget>)
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).
Sourcepub fn size(&self) -> Size
pub fn size(&self) -> Size
The child’s resolved size (valid after ChildPod::layout_child).
Sourcepub fn set_origin(&mut self, origin: Point)
pub fn set_origin(&mut self, origin: Point)
Place the child at origin within the container’s coordinate space.
Sourcepub fn transform(&self) -> Option<Affine>
pub fn transform(&self) -> Option<Affine>
The child’s transform, if any (see ChildPod::set_transform).
Sourcepub fn set_transform(&mut self, transform: Option<Affine>)
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:
ChildPod::paint_childwraps the child’s paint inPaintScene::push_transform/PaintScene::pop_transform, and maps an ancestor’s visible rect back into the child’s frame (the bounding box of its inverse image), so a culling descendant still culls against what is really on screen;ChildPod::containsmaps the point through the inverse before the bounds test, so it hits exactly what paint drew — a rotated child hits along its rotated edges, not its axis-aligned bounding box (the same test ascrate::hit::point_in_transformed_rect);ChildPod::event_childmaps pointer, scroll and scale positions through the inverse (InputEvent::transformed), so the child sees local coordinates exactly as an untransformed child does;ChildPod::semantics_childreports the subtree at the axis-aligned bounding box of the transformed child rect. This is an approximation (v1): the pod’s frame becomes that box, and descendants are offset from its corner unscaled and unrotated.
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.
Sourcepub fn is_active(&self) -> bool
pub fn is_active(&self) -> bool
Whether this child currently holds the recorded active (captured) path.
Sourcepub fn set_active(&mut self, active: bool)
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.
Sourcepub fn is_focused(&self) -> bool
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.
Sourcepub fn set_focused(&mut self, focused: bool)
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.
Sourcepub fn focus_epoch(&self) -> u64
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.
Sourcepub fn holds_live_focus(&self) -> bool
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.
Sourcepub fn retire_stale_focus_link(&mut self) -> bool
pub fn retire_stale_focus_link(&mut self) -> bool
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.
Sourcepub fn hover_epoch(&self) -> u64
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.
Sourcepub fn layout_child(
&mut self,
ctx: &mut LayoutCtx<'_>,
bc: &BoxConstraints,
) -> Size
pub fn layout_child( &mut self, ctx: &mut LayoutCtx<'_>, bc: &BoxConstraints, ) -> Size
Lay the child out under bc, recording and returning its chosen size.
Sourcepub fn paint_child(
&mut self,
ctx: &mut PaintCtx<'_>,
scene: &mut dyn PaintScene,
)
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.
Sourcepub fn semantics_child(&self, ctx: &mut SemanticsCtx)
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.
Sourcepub fn event_child(
&mut self,
ctx: &mut EventCtx<'_>,
event: &InputEvent,
) -> EventResult
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.
Sourcepub fn contains(&self, point: Point) -> bool
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
impl Drop for ChildPod
Source§fn drop(&mut self)
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.