Skip to main content

RenderTree

Struct RenderTree 

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

Arena-allocated persistent render tree. Node 0 is always the root.

Implementations§

Source§

impl RenderTree

Source

pub const ROOT: NodeId = 0

Source

pub fn new() -> Self

Source

pub fn start_frame(&mut self)

Start a new frame and begin the root. Must be called before painting.

Source

pub fn reset(&mut self, node: NodeId)

Reset a node for a fresh paint: clears its declarations (the picture cache fields persist — the walker manages those explicitly).

Source

pub fn slot(&mut self, parent: NodeId, reset: bool) -> NodeId

Consume the next child slot of parent.

reset == true (normal paint descent): the child is begun — its declared data is cleared for re-declaration. reset == false (cache-hit replay): the slot is consumed so siblings stay positionally aligned, but the child subtree keeps all its state.

Source

pub fn keyed_slot(&mut self, parent: NodeId, key: u64) -> NodeId

Like Self::slot, but the returned NodeId is resolved by an explicit stable key instead of “whatever was previously at this position” — see the module doc’s “Identity” section. Reusing an existing key’s node preserves ALL its sticky state (scroll_ctrl, anim_channels, hover/press, and everything underneath it in the subtree, however deep) exactly like an ordinary same-position repaint does; a new key gets a brand-new node with empty children/keyed_children, so nothing nested under it — however many ScrollViews/Tabs/TextAreas it contains — can possibly alias whatever a DIFFERENT key’s subtree left behind.

The resolved node is ALSO written into parent’s ordinary children/cursor slot, same as slot() — the key only changes which NodeId ends up at that position, not how it’s found afterward. This matters: hit-testing, hover, semantics/accessibility, and the picture-cache walk all traverse children, not keyed_children — a node reachable ONLY through the keyed map would be invisible to all of them (found via a real test failure — semantic_labels came back empty for a screen reached this way).

Source

pub fn prune_keyed_children(&mut self, parent: NodeId, valid_keys: &[u64])

Drop any of parent’s keyed children whose key is no longer in valid_keys — called once per frame by ScreenTransitionView with the navigation stack’s current keys, so a screen’s cached subtree (scroll position, animation state, everything) is released once it’s actually been popped, not retained forever. The dropped node’s arena slot itself isn’t reclaimed (this arena never frees — same tradeoff slot()’s positional children already have for any widget that stops being painted), only the reference to it.

Source

pub fn finalize(&mut self)

End of frame: drop unused child slots of every node repainted this frame, so removed widgets cannot leave ghost hit regions behind.

Source

pub fn node_mut(&mut self, id: NodeId) -> &mut TreeNode

Source

pub fn node(&self, id: NodeId) -> &TreeNode

Source

pub fn nodes_iter(&self) -> impl Iterator<Item = &TreeNode>

Every node in the arena, for callers that need to scan rather than look up a specific id (e.g. tests asserting some node reached a given interaction state without knowing its id in advance).

Source

pub fn nodes_indexed(&self) -> impl Iterator<Item = (NodeId, &TreeNode)>

Same as Self::nodes_iter, paired with each node’s NodeId — needed by callers that must look the node back up for a second, mutable pass (D116’s EditController draining: the engine collects (NodeId, controller, ops) immutably first, since it can’t mutate the tree while iterating it).

Source

pub fn hit_test( &self, x: f32, y: f32, ) -> (Option<(HitHandler, bool)>, Vec<ScrollHandler>)

Hit-test walk: children before own regions, later siblings first — paint order is z-order, so the topmost match wins structurally (D092). Returns the topmost hit callback, whether it is POSITIONAL — positional hits become the active drag grab (streamed MouseMove positions until release); plain hits fire once — and, when the winner is a plain hit, so a touch/mouse gesture that starts on a plain-hit child (Button, ListTile, …) sitting inside e.g. a ScrollView can still fall back to dragging that ancestor once movement shows it’s a scroll, not a tap (2026-08-02, real Android touch testing — without this a plain-hit child sitting anywhere in a scrollable page permanently shadowed the ScrollView’s own drag region, so touch-drag scrolling silently did nothing on any page with interactive content — desktop was unaffected since wheel/trackpad scroll is a wholly separate InputEvent::Scroll path).

The chain is the SECOND return value, always present — collected independently of what the leaf hit resolves to (None, a plain tap, or even a positional widget like a Slider), so touching blank scrollable space directly (no leaf hit at all) still yields a usable chain even though the first value is None.

Source

pub fn hover_test(&self, x: f32, y: f32) -> Option<NodeId>

Topmost node under the cursor that owns any interactive or hover region — drives hover state (buttons, tiles, tooltips).

Source

pub fn long_press_test( &self, x: f32, y: f32, ) -> Option<Arc<dyn Fn() + Send + Sync>>

Topmost long-press callback under the cursor.

Source

pub fn set_hover(&mut self, target: Option<NodeId>) -> bool

Set the hovered node, clearing the previous one. Marks both the old and new node dirty so the next walk repaints exactly them (localized damage). Returns true when the hover target changed.

Source

pub fn set_pressed(&mut self, target: Option<NodeId>) -> bool

Set the pressed node, clearing the previous one — same shape as Self::set_hover, driven by MouseDown/MouseUp instead of MouseMove. Returns true when the pressed target changed.

Source

pub fn scroll_test( &self, x: f32, y: f32, dx: f32, dy: f32, ) -> Option<HitHandler>

Axis-aware scroll routing: among the viewports under the cursor (innermost first), pick the first that handles the DOMINANT axis of the delta; fall back to the innermost that handles the other axis. A horizontal carousel no longer intercepts a vertical page scroll.

Source

pub fn zoom_test( &self, x: f32, y: f32, ) -> Option<Arc<dyn Fn(f32) + Send + Sync>>

Innermost registered zoom region under (x, y) (trackpad pinch, InteractiveViewer) — same innermost-first, later-sibling-first priority as scroll_test, but with no axis-selection step (a pinch gesture has no “axis”, just one delta).

Source

pub fn collect_hits(&self) -> Vec<HitRegion>

All hit regions in tree (paint) order — used by the overlay pass to flatten a per-entry subtree into a dispatch list.

Source

pub fn collect_scrolls(&self) -> Vec<ScrollRegion>

All scroll regions in tree (paint) order.

Source

pub fn collect_focus(&self) -> Vec<FocusNode>

All focus nodes in tree (paint) order — feeds the Tab cycle each frame, including cache-hit frames where no widget was repainted.

Source

pub fn focus_owner(&self, focus_id: u64) -> Option<NodeId>

The render-tree node that declared the rosace_a11y::FocusNode with id focus_id (D112/Phase 28 Step 1) — bridges FocusManager::focused (a FocusNode’s own global id) back to a NodeId, so the engine’s key dispatch can find and mutate that node’s persistent text_edit/editable state.

Source

pub fn editable_test(&self, x: f32, y: f32) -> Option<NodeId>

Topmost editable node whose declared rect contains (x, y) — used by the engine to focus (and, Step 1: place the caret at the end of) an editable widget on click (D112/Phase 28). Same z-order traversal as Self::hover_test; editable rects live in TreeNode::editable, declared by super::PaintCtx::register_editable.

Source

pub fn collect_semantics(&self) -> SemanticNode

Derive the accessibility tree (D099): semantics entries in paint order, nested by render-tree structure. Branches with no semantic content anywhere below them are pruned.

Source

pub fn content_to_screen(&self, target: NodeId, p: Point) -> Point

All overlay entries in tree order (insertion order = z-order, D058). Map a point expressed in target’s CONTENT space to window/screen space, applying the inverse of every transform-host remap on the path from the root (each is a pure translation: + viewport origin − scroll offset). Phase 32 bug fix (user-reported): an overlay anchored by a widget inside a GPU scroll layer (e.g. a Tooltip’s Absolute position) carried content coords into the window-space overlay pass and rendered far from its anchor.

Source

pub fn overlay_ids(&self) -> Vec<(NodeId, usize)>

Source

pub fn transform_ids(&self) -> Vec<(NodeId, usize)>

All transform-layer entries in tree order.

Source

pub fn inspect(&self) -> Vec<InspectNode>

Read-only snapshot of the live tree (D123/O2) — plain data, safe to hand to a DevTools overlay: no callbacks, no Arc<dyn Fn>, nothing that could be invoked or mutated through it. “Live” means reachable from the root through children as of the last finalize() — an arena slot orphaned by a removed widget is not included, even though its TreeNode still physically exists until the slot is reused.

Additive and non-invasive: reads fields every node already carries, touches nothing about how painting/hit-testing/layout work.

Source

pub fn pick(&self, x: f32, y: f32) -> Option<NodeId>

The node whose rect contains (x, y) and is deepest (most specific) in the tree — the element-picker hit target (D123/O2). Unlike Self::hover_test/Self::hit_test, this considers EVERY node’s paint rect, not just ones that declared an interactive region — a plain Container/Text is pickable too. Ties (same depth) go to the one painted later (topmost in z-order), mirroring every other hit-order convention in this file.

Trait Implementations§

Source§

impl Default for RenderTree

Source§

fn default() -> Self

Returns the “default value” for a type. 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, 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.