pub struct WidgetArena { /* private fields */ }Expand description
Flat arena storage for all widgets, using SlotMap for O(1) access.
Implementations§
Source§impl WidgetArena
impl WidgetArena
pub fn new() -> Self
Sourcepub fn insert(&mut self, widget: Box<dyn Widget>) -> WidgetId
pub fn insert(&mut self, widget: Box<dyn Widget>) -> WidgetId
Insert a widget into the arena as a root-level widget.
Sourcepub fn insert_child(
&mut self,
parent: WidgetId,
widget: Box<dyn Widget>,
) -> WidgetId
pub fn insert_child( &mut self, parent: WidgetId, widget: Box<dyn Widget>, ) -> WidgetId
Insert a widget as a child of the given parent.
pub fn get(&self, id: WidgetId) -> Option<&WidgetNode>
pub fn get_mut(&mut self, id: WidgetId) -> Option<&mut WidgetNode>
pub fn children(&self, id: WidgetId) -> &[WidgetId]
pub fn parent(&self, id: WidgetId) -> Option<WidgetId>
pub fn bounds(&self, id: WidgetId) -> Rect
Sourcepub fn effective_transform(&self, id: WidgetId) -> Transform2D
pub fn effective_transform(&self, id: WidgetId) -> Transform2D
The accumulated 2D affine transform that maps id’s pre-transform
local-space points to screen space — equivalent to the renderer’s
transform_stack top by the time it begins painting id. Used by
hit-testing and any consumer that needs to project a node’s
pre-transform bounds into screen space (e.g. teksilo-scene’s a11y
bounds projection of view-transformed scene items).
Composition order. Mirrors crates/teksilo-render/src/renderer.rs’s
PushTransform handling: each push composes as
new_top = device_t.then(prev_top), so the deepest (innermost)
transform is applied first to a local point and outer ancestors
compose afterward. Walking root→leaf, each ancestor’s
transform_prop is folded in via t.then(effective) (NOT
effective.then(t)).
Returns Transform2D::IDENTITY if no ancestor sets a non-identity
transform, which is the common case (90%+ of widgets).
Sourcepub fn local_pointer_position(&self, id: WidgetId, window_point: Point) -> Point
pub fn local_pointer_position(&self, id: WidgetId, window_point: Point) -> Point
Convert a window-space pointer position into the widget-local
coordinate space of id’s event handlers — i.e. relative to id’s
top-left, after undoing any transform scopes between the window and
id. This is the single conversion the dispatcher applies before
handing a position to on_tap / on_drag / on_pointer_event, so
every handler sees positions in its own local space.
The transform handling mirrors Self::hit_test_recursive so the
position a handler receives is in the same space the hit-test used
to pick it:
- A content transform node (
content_transform, e.g.SceneView) owns its transform and maps its content itself. The framework feeds such a node positions in its parent-effective space (the same spacehit_test_recursivepasses throughinv(transform)), with no bounds-origin subtraction — the node’sview_transformalready accounts for its placement. - Any other node (the 90%+ identity case, plus
Scale/Rotateself-transforms) receives widget-local coordinates: undo the full transform chain including its own, then subtract its bounds origin so the result is relative to its top-left.
In the common no-transform case this collapses to
window_point - bounds.origin.
Sourcepub fn refresh_roots(&mut self)
pub fn refresh_roots(&mut self)
Refresh the cached roots list. Call once per frame from layout().
Sourcepub fn hit_test_at(
&self,
point: Point,
exclude: Option<WidgetId>,
) -> Option<WidgetId>
pub fn hit_test_at( &self, point: Point, exclude: Option<WidgetId>, ) -> Option<WidgetId>
Walk the active widget tree at point and return the deepest
widget under it (the front-most hit, last child wins). Honors
event_pass_through (such nodes pass through to whatever sits
behind them but their descendants are still hit-testable). Does
not consider overlays — for the full pointer-routing hit-test
see WidgetTree::hit_test.
exclude: if Some(id), that widget (and any descendants
within its subtree) are skipped during the walk. Used by the
debug inspector’s picker tool to ignore the picker overlay
itself, and by drag-and-drop to ignore the drag preview.
Sourcepub fn hit_test_in_subtree(
&self,
start: WidgetId,
point: Point,
) -> Option<WidgetId>
pub fn hit_test_in_subtree( &self, start: WidgetId, point: Point, ) -> Option<WidgetId>
Hit-test starting from a specific subtree root rather than the
arena’s top-level roots. Same semantics as
hit_test_at but scoped — useful when
callers want to ignore everything outside a known subtree
(e.g. the inspector’s picker hit-tests inside the user-root
subtree so it never resolves to its own chrome).
Sourcepub fn hit_test_in_subtree_excluding(
&self,
start: WidgetId,
point: Point,
exclude: Option<WidgetId>,
) -> Option<WidgetId>
pub fn hit_test_in_subtree_excluding( &self, start: WidgetId, point: Point, exclude: Option<WidgetId>, ) -> Option<WidgetId>
Like hit_test_in_subtree but also
excludes a widget (and its descendants) from the walk. Lets the
overlay / drag-and-drop hit-test reuse the single canonical recursion
in hit_test_recursive instead of duplicating it.
Sourcepub fn active_ids(&self) -> Vec<WidgetId>
pub fn active_ids(&self) -> Vec<WidgetId>
Iterate over all active widget IDs.
Allocating wrapper around Self::active_ids_iter. Hot-path
callers that hold &self for the whole iteration should call
the iterator directly to avoid the per-call Vec allocation;
callers that need an owned snapshot (because they mutate
arena state inside the loop) should use
Self::fill_active_ids with a reusable buffer.
Sourcepub fn active_ids_iter(&self) -> impl Iterator<Item = WidgetId> + '_
pub fn active_ids_iter(&self) -> impl Iterator<Item = WidgetId> + '_
Stream all active widget IDs without allocating. The iterator
borrows the arena, so the caller cannot mutate it while
iterating — for that case use Self::fill_active_ids.
Sourcepub fn fill_active_ids(&self, out: &mut Vec<WidgetId>)
pub fn fill_active_ids(&self, out: &mut Vec<WidgetId>)
Fill out with every active widget ID. Clears out first so
callers can reuse a long-lived buffer across calls. Use this
when the iteration site needs an owned snapshot independent
of the arena borrow (typically because it mutates per-widget
state with arena.get_mut(id) inside the loop).
Sourcepub fn set_dormant(&mut self, id: WidgetId)
pub fn set_dormant(&mut self, id: WidgetId)
Set a widget subtree to dormant state (state preserved, not rendered). Recursively dormants all children.
The node named here is marked self-parked (WidgetNode::self_dormant);
the descendants swept along by the recursion are not, since their
dormancy belongs to this ancestor rather than to them. That distinction
is what lets activate put the subtree back exactly as
it found it instead of waking content that was already closed.
Sourcepub fn activate(&mut self, id: WidgetId)
pub fn activate(&mut self, id: WidgetId)
Activate a dormant widget subtree (triggers relayout and repaint).
Recursively activates all children, except those a descendant
widget has independently gated off via visible_when(false).
The directly-targeted id is always activated (the caller asked for
it). When recursing, a child whose own visible_state currently
evaluates to false is left dormant along with its subtree: it is
hidden by its own gate, not by the ancestor’s dormancy, so a parent
reactivation must not wake it. This is what keeps a ComboBox’s
closed dropdown panel, a collapsed overlay, or any visible_when-
gated child from leaking back to the screen when an ancestor (e.g. a
Toolbar item reappearing from overflow) is re-activated. The
per-pass visibility reconciliation
(visibility_checks_iter) still owns
the eventual activate/dormant transitions when the gate flips.
Sourcepub fn destroy(&mut self, id: WidgetId)
pub fn destroy(&mut self, id: WidgetId)
Destroy a widget and remove it from the arena entirely. Recursively destroys all children. State is gone.
Sourcepub fn remove_node(&mut self, id: WidgetId)
pub fn remove_node(&mut self, id: WidgetId)
Remove a single node: unlink it from its parent’s child list and drop it from the arena. Does not recurse into its children.
The caller owns the recursion. This exists for
WidgetTree::destroy_subtree /
the reconciling rebuild path, which walks the subtree itself so it can
honour re-parenting — a child re-homed into the surviving tree must NOT
be torn down via this node’s now-stale children list. Using
destroy there would re-recurse that stale list and
destroy the re-homed survivor.
pub fn is_active(&self, id: WidgetId) -> bool
pub fn len(&self) -> usize
pub fn is_empty(&self) -> bool
pub fn mark_all_clean(&mut self)
pub fn any_needs_layout(&self) -> bool
pub fn any_needs_paint(&self) -> bool
pub fn mark_needs_paint(&mut self, id: WidgetId)
Sourcepub fn mark_subtree_needs_paint(&mut self, id: WidgetId)
pub fn mark_subtree_needs_paint(&mut self, id: WidgetId)
Recursively mark a widget and all its descendants needs_paint. Used by callers that want a fresh paint of an entire subtree — e.g. a rich tooltip whose dwell indicator child would otherwise reuse its cached_paint while the parent re-runs some per-frame logic.
pub fn mark_needs_layout(&mut self, id: WidgetId)
Sourcepub fn mark_needs_rebuild(&mut self, id: WidgetId)
pub fn mark_needs_rebuild(&mut self, id: WidgetId)
Mark a widget as needing its build() re-run.
Also marks for layout and paint since rebuilt children need both.
Sourcepub fn collect_needs_rebuild(&self) -> Vec<WidgetId>
pub fn collect_needs_rebuild(&self) -> Vec<WidgetId>
Collect widgets that need their build() re-run (data-driven rebuild).
Only returns active widgets with needs_rebuild == true.
Allocating wrapper around Self::needs_rebuild_iter. Prefer
the iterator on hot paths.
Sourcepub fn needs_rebuild_iter(&self) -> impl Iterator<Item = WidgetId> + '_
pub fn needs_rebuild_iter(&self) -> impl Iterator<Item = WidgetId> + '_
Stream widgets that need build() re-run without allocating.
needs_rebuild is set only by BindingLevel::Rebuild bindings —
i.e. on composing widgets that explicitly want build() re-run
when their data model changes. It is intentionally NOT gated on
the widget currently having children: a data-driven widget that
builds its children directly and starts EMPTY (e.g. the toast
host with no toasts yet, an empty list that renders rows without
a persistent container) must still rebuild to materialise its
FIRST child. rebuild_single_widget handles a childless widget
correctly (nothing to tear down, then it adopts build()’s
output).
Sourcepub fn visibility_checks(&self) -> Vec<(WidgetId, bool, bool)>
pub fn visibility_checks(&self) -> Vec<(WidgetId, bool, bool)>
Check all widgets with visible_state bindings and return (id, is_currently_active, should_be_visible) tuples.
Allocating wrapper around Self::visibility_checks_iter.
Sourcepub fn visibility_checks_iter(
&self,
) -> impl Iterator<Item = (WidgetId, bool, bool)> + '_
pub fn visibility_checks_iter( &self, ) -> impl Iterator<Item = (WidgetId, bool, bool)> + '_
Stream widgets with visible_state bindings without
allocating. Each entry is (id, is_currently_active, should_be_visible).
Sourcepub fn is_enabled(&self, id: WidgetId) -> bool
pub fn is_enabled(&self, id: WidgetId) -> bool
Check if a widget is effectively enabled, walking up the parent chain.
Returns false if the widget itself or any ancestor has enabled_state
bound to false. This lets containers like GroupBox disable a whole
subtree by binding a single signal on their content wrapper.
Sourcepub fn set_alignment_override(&mut self, id: WidgetId, alignment: Alignment)
pub fn set_alignment_override(&mut self, id: WidgetId, alignment: Alignment)
Set a per-child alignment override on a widget.
Sourcepub fn set_clips_children(&mut self, id: WidgetId, clips: bool)
pub fn set_clips_children(&mut self, id: WidgetId, clips: bool)
Mark a widget as clipping its children (scroll area, overflow hidden).
Sourcepub fn ime_context(&self, id: WidgetId) -> Option<ImeContext>
pub fn ime_context(&self, id: WidgetId) -> Option<ImeContext>
The OS-IME descriptor for the widget at id, or None if the node
is not a text-input surface (the default) or the id is unknown. The
platform IME layer queries this for the focused widget to decide
whether to enable the OS input method and with which purpose.
Sourcepub fn set_ime_context(&mut self, id: WidgetId, ime: Option<ImeContext>)
pub fn set_ime_context(&mut self, id: WidgetId, ime: Option<ImeContext>)
Set (or clear, with None) the OS-IME descriptor for the widget at
id.
Sourcepub fn alignment_override(&self, id: WidgetId) -> Option<Alignment>
pub fn alignment_override(&self, id: WidgetId) -> Option<Alignment>
Get a widget’s alignment override, if any.
Sourcepub fn take_widget(&mut self, id: WidgetId) -> Option<Box<dyn Widget>>
pub fn take_widget(&mut self, id: WidgetId) -> Option<Box<dyn Widget>>
Temporarily take the widget box out of a node (for rebuild). The node remains in the arena with a placeholder.
Sourcepub fn restore_widget(&mut self, id: WidgetId, widget: Box<dyn Widget>)
pub fn restore_widget(&mut self, id: WidgetId, widget: Box<dyn Widget>)
Restore a widget box that was previously taken out.
Sourcepub fn mark_ancestors_need_layout(&mut self, id: WidgetId)
pub fn mark_ancestors_need_layout(&mut self, id: WidgetId)
Walk up the parent chain from id and mark each ancestor as needing layout.
Called when a relayout-level binding changes, since a child’s size change
may affect its parent’s size, and so on up to the root.
Sourcepub fn mark_all_dirty(&mut self)
pub fn mark_all_dirty(&mut self)
Mark all widgets as needing layout and paint (e.g. after a theme change). Also clears per-widget paint caches since the visual output is stale.
Sourcepub fn mark_all_needs_paint_only(&mut self)
pub fn mark_all_needs_paint_only(&mut self)
Mark every active node for repaint without touching layout, rebuild,
or the per-widget paint caches. Used for a global visual change that
leaves geometry untouched — the window’s active-state flip (caret
hiding, selection desaturation, DimWhenInactive). Lighter than
Self::mark_all_dirty: the paint walker re-runs paint() for any
node whose needs_paint is set and overwrites its cache, so there is no
need to clear cached_paint; and skipping needs_layout avoids a
pointless relayout pass. Dormant nodes are skipped — they don’t paint,
and they’re re-marked on reactivation.