Skip to main content

WidgetTree

Struct WidgetTree 

Source
pub struct WidgetTree { /* private fields */ }

Implementations§

Source§

impl WidgetTree

Source

pub fn sync_accessibility(&mut self) -> TreeUpdate

Build an AccessKit TreeUpdate from the current state of all active widgets. Call this once per frame, between layout and paint, and push the result to the accesskit_winit::Adapter. Caches the result and rebuilds only when something that actually changes the AT tree has happened: a focus move, an overlay change, a widget rebuild, an active↔dormant transition, an AccessibilityOnly binding flip, a shortcut rebind, a locale switch, a queued announcement, or an explicit request_accessibility_update. A plain relayout does not invalidate the cache.

Source

pub fn a11y_walk_generation(&self) -> u64

How many accessibility walks have happened.

A delivery that has not seen the latest walk is holding a tree whose shape may be stale, not merely its geometry — so it must push the full tree rather than rely on the geometry patch.

Source

pub fn accessibility_tree_snapshot(&self) -> TreeUpdate

Build a TreeUpdate describing the tree right now, without touching any state.

For a caller that wants to look at the accessibility tree rather than deliver it: an automation query, a screenshot’s blind-spot check, a test assertion. Unlike sync_accessibility this neither caches, nor bumps the AT version, nor records announcements, nor advances the framework’s live regions — which matters, because a caller that consumed an announcer step and then dropped the update would have silently eaten a message the user was meant to hear.

It is a full walk every time; sync_accessibility is the one with the cache.

Source

pub fn dispatch_access_action( &mut self, node_id: NodeId, action: Action, data: Option<ActionData>, ops: &mut dyn WindowOps, ) -> bool

Dispatch a synthetic AccessKit action to the node identified by node_id (which may be a synthetic, widget-emitted child node — e.g. a rich-text TextRun). Resolves the owning widget exactly the way the platform AT adapter does (node_id_to_widget_id_maybe then widget_for_synthetic), builds a crate::event::WidgetEvent::AccessAction, and dispatches it through ops so actions that open windows / dialogs work.

Returns true when the action was consumed — a handler claimed it, focus moved, or the context-menu fallback opened a menu — and false when nothing acted on it, including when the target node resolves to no live widget. Callers are expected to surface that: an action a node never handles is a caller error, and reporting it as success (which is what “a widget existed at the target” amounted to) leaves an automation client chasing timing and coordinates for a UI that was never going to move.

This is the in-process equivalent of an OS screen reader invoking an action — the channel an automation harness uses to drive the UI without the OS AT layer.

Source

pub fn widget_for_synthetic(&self, node_id: NodeId) -> Option<WidgetId>

Look up the owning widget for a synthetic AccessKit NodeId emitted by push_text_run_child / push_paragraph_child. Used by handle_accessibility_actions to route an ActionRequest targeting a TextRun child back to the editor that owns it.

Source

pub fn accessibility_node(&self, id: WidgetId) -> AccessibilityInfo

Source

pub fn find_by_role(&self, role: Role) -> Option<WidgetId>

Source

pub fn find_by_label(&self, label: &str) -> Option<WidgetId>

Source

pub fn find_by_action(&self, action: Action) -> Option<WidgetId>

Source

pub fn text_content(&self, id: WidgetId) -> Option<String>

Get the text content of a widget from its accessibility name. Equivalent to the label set via AccessNodeBuilder::set_name, after override application.

Source

pub fn text_value(&self, id: WidgetId) -> Option<String>

Get the text value of a widget from its accessibility value. Equivalent to the value set via AccessNodeBuilder::set_value, after override application.

Source§

impl WidgetTree

Source

pub fn begin_external_drag( &mut self, position: Point, data: ExternalDropData, ops: &mut dyn WindowOps, )

Begin an external drag session at position carrying OS-delivered data. Establishes the initial hover target and feedback immediately.

§Which device is dragging

A drag from another application does not say: none of wl_data_device, XDND, OLE IDropTarget or NSDraggingDestination carries the source’s device to the destination, so the session reports PointerKind::Unknown — which resolves as precise everywhere a kind is read, i.e. exactly the behaviour every OS drop had before pointers were distinguishable.

Our OWN escalated drag re-entering a window is the case that is knowable, and it does not go through this door blind: the pointer is recovered from the outbound stash alongside the typed payload.

Source

pub fn update_external_drag(&mut self, position: Point, ops: &mut dyn WindowOps)

Update an in-flight external drag as the OS reports pointer motion. No-op unless an external session is active.

Source

pub fn end_external_drag( &mut self, position: Point, data: ExternalDropData, ops: &mut dyn WindowOps, )

Complete an external drag with a drop at position, firing on_drop on the target. data is the authoritative payload read at drop time; if non-empty it replaces the session payload (some backends only have the full data at drop, not at enter). No-op unless an external session is active.

Source

pub fn abort_external_drag(&mut self, ops: &mut dyn WindowOps)

End an external drag over this window for good: the OS aborted the operation, or the app-originated drag this window was holding as a re-entered session has finished elsewhere. No drop will follow.

The difference from cancel_external_drag is the re-entered case, and it is the whole reason both exist: a leave re-stashes the typed payload so the next window the drag enters can pick it up, because the OS drag is still in flight. An abort must not — re-stashing a dead drag leaves a payload that the next genuine external drag from another application could misclaim.

on_drag_leave fires on the current target so no highlight is stranded. on_drag_ended fires only for a session with an in-app source, so a re-entered session is silent here: the window that started the drag owns that notification and fires it once from handle_os_drag_ended.

Source

pub fn cancel_external_drag(&mut self, ops: &mut dyn WindowOps)

Cancel an in-flight external drag (the pointer left the window or the OS aborted the operation) without dropping. No-op unless an external session is active.

Source

pub fn handle_os_drag_ended( &mut self, outcome: DropOutcome, ops: &mut dyn WindowOps, )

Resolve an OS (outbound) drag at its terminal event. Clears the global typed-payload stash and fires on_drag_ended(outcome) once on the source widget (set only on the window that started the drag). Routed here by teksilo-app when the platform backend reports DragEnded.

Source

pub fn abort_outbound_drag(&mut self)

Abort any outbound OS drag this tree participates in, used when the window is closing. If this tree is the drag source, the whole drag is ending (the source object dies with the window) — end the stash so a later genuine external drag can’t be mistaken for ours. If instead this is a non-source window currently holding the re-entered payload, hand it back to the stash so another window can still recover it. No on_drag_ended fires (the window and its handlers are being torn down).

Source§

impl WidgetTree

Source

pub fn focus_with_origin_ops( &mut self, id: WidgetId, origin: FocusOrigin, ops: &mut dyn WindowOps, )

Set focus to a specific widget with the given origin, invoking on_focus_lost / on_focus_gained handlers through the caller-supplied WindowOps sink.

teksilo-app drives in-dispatch focus changes through this method so that focus-triggered handlers can synchronously call ctx.open_window(...). Standalone callers (programmatic focus from framework code paths, tests) use focus_with_origin which wraps with NoopWindowOps.

WCAG 3.2.1 (On Focus). The capability above is a footgun: an on_focus handler that opens a window, navigates, or otherwise changes context merely because a control received focus is a Success Criterion 3.2.1 failure — keyboard users tabbing through the UI would trigger it unexpectedly. on_focus should only update local visual/reactive state. A debug-only guard (EventContext::open_window) warns if a synchronous context change is attempted from inside focus dispatch.

Source

pub fn focus_with_origin(&mut self, id: WidgetId, origin: FocusOrigin)

Set focus using NoopWindowOps. Programmatic / framework-internal callers. Handlers triggered from this path cannot ctx.open_window(...).

Source

pub fn focus(&mut self, id: WidgetId)

Set focus to a specific widget (programmatic origin, no ops).

Source

pub fn focus_ops(&mut self, id: WidgetId, ops: &mut dyn WindowOps)

Set focus — the dispatch-path variant that threads ops through to any on_focus_lost / on_focus_gained handlers.

Source

pub fn focused(&self) -> Option<WidgetId>

Get the currently focused widget.

Source

pub fn ime_context_for_focused(&self) -> Option<ImeContext>

The OS-IME descriptor of the currently focused widget, if it is a text-input surface. None when nothing is focused or the focused node is not text-editing. The platform layer reads this at focus-change time to enable/disable the OS input method and pick its purpose. See crate::ime.

Source

pub fn first_focusable_descendant(&self, root: WidgetId) -> Option<WidgetId>

Find the first focusable widget within a subtree, in traversal order — the widget Tab would land on first. Respects nested FocusScopes and scoped tab_index (not merely raw DFS order), so a modal’s initial focus matches its Tab order.

Source

pub fn is_active(&self, id: WidgetId) -> bool

Whether the given widget id currently exists and is active in the tree (not dormant, not destroyed). Callers that need to validate a user-supplied WidgetId before acting on it — e.g. the modal presentation path validating ModalRequest::focus_target — use this.

Source

pub fn widget_initial_focus_hint(&self, id: WidgetId) -> Option<WidgetId>

Walk the subtree rooted at id in depth-first order, returning the first widget-reported initial_focus_hint that resolves to an active descendant of id.

Used by the modal presentation pipeline to let a deferred-built content widget (e.g. MessageBox) direct focus to a specific descendant after build — even when wrapped in a surface widget like ModalContainer that doesn’t itself know the default button’s id. The framework walks in to find the first hint under the content root, which is tighter than falling all the way back to first_focusable_descendant.

Hints pointing at inactive or out-of-subtree ids are ignored; the walk continues so a shallow wrapper’s stale hint doesn’t hide a deeper child’s valid one.

Source

pub fn focus_origin(&self) -> Option<FocusOrigin>

How the currently focused widget gained focus.

Source

pub fn focus_visible_signal(&self) -> Signal<bool>

Input-modality “focus-visible” signal: true after keyboard input, false after pointer input. Focus rings observe this so they show only during keyboard navigation. See BuildContext::focus_visible.

Source

pub fn view_focus_active_for(&mut self, node_id: WidgetId) -> Signal<bool>

Reactive signal that is true when the nearest focusable ancestor of node_id (its “focus scope” — e.g. the enclosing data view) holds keyboard focus. With no focusable ancestor, returns a constant-true signal so selection renders active (the legacy behaviour for items outside any focus scope). Drives focus-aware selection in StandardItem.

Source

pub fn begin_view_focus(&mut self, node_id: WidgetId) -> Signal<bool>

Push node_id’s focus scope onto the build-time scope stack (creating its view_focus_signal if absent) so descendants built before arena parenting is wired (docked / virtualized rows) still read the correct view focus. Pair with end_view_focus.

Source

pub fn end_view_focus(&mut self)

Pop the innermost focus scope pushed by begin_view_focus.

Source

pub fn current_view_focus(&self) -> Option<Signal<bool>>

The innermost active build-time focus scope, if any.

Source§

impl WidgetTree

Source

pub fn layout(&mut self, proposal: SizeProposal)

Run the layout pass with the given size proposal, using NoopWindowOps. Handlers triggered from drag_tick / tooltip activation / etc cannot call ctx.open_window(...) from this path.

teksilo-app calls layout_with_ops with a real sink so those handlers can open windows.

Source

pub fn measure_root_intrinsic(&self, proposal: SizeProposal) -> Option<Size>

Measure the intrinsic size of the primary (non-overlay) content root(s) at proposal — e.g. { width: Some(w), height: None } for the natural height at a fixed width. Mirrors the overlay intrinsic pass below: it calls the root’s layout_response directly — NOT the activation-ignoring WidgetArena::measure_intrinsic — so a visible_when(false) / parked-Switcher descendant is excluded exactly as the real layout excludes it. A size-to-content window is therefore sized to what is actually shown. Computes sizes only (never writes bounds), so it is safe to call right after a layout pass.

Drives size-to-content windows (see WindowConfig::size_to_content): the native-window path has no in-tree overlay to size to content, so teksilo-app measures the root here and resizes the OS window to fit. Returns None if there is no active primary root; with more than one active primary root the per-axis maximum is returned (size-to-content is intended for single-primary-root windows).

Source

pub fn layout_with_ops( &mut self, proposal: SizeProposal, ops: &mut dyn WindowOps, )

Run the layout pass with the given size proposal, threading the app’s WindowOps sink through to drag_tick / tooltip / delayed-overlay handlers.

Source§

impl WidgetTree

Source

pub fn attach_tooltip( &mut self, anchor_id: WidgetId, content_id: WidgetId, delay: Duration, )

Attach a tooltip to a widget. The tooltip content widget must already be in the tree (typically added as a dormant widget during build).

Source

pub fn attach_tooltip_with_placement( &mut self, anchor_id: WidgetId, content_id: WidgetId, delay: Duration, placement: TooltipPlacement, )

Variant of attach_tooltip that opens the tooltip at the given TooltipPlacementSide for anchors stacked vertically (menu items, a vertical tab strip, list/tree rows) where Below would cover the next sibling.

Source

pub fn attach_tooltip_with_sticky( &mut self, anchor_id: WidgetId, content_id: WidgetId, delay: Duration, sticky_after: Option<Duration>, )

Attach a tooltip that auto-promotes to “sticky” after sticky_after elapses post-show. Used by rich tooltips implementing the sticky-on-dwell UX (typically 2 seconds).

The tooltip is shown normally after delay, then each subsequent layout pass checks whether sticky_after has elapsed since the overlay was shown. When it has, the tree calls promote_tooltip_to_sticky — the entry is flagged sticky (so pointer-leave no longer auto-dismisses) and the overlay’s dismiss behavior is swapped to EscapeOrClickOutside.

Source

pub fn attach_tooltip_with_sticky_sink( &mut self, anchor_id: WidgetId, content_id: WidgetId, delay: Duration, sticky_after: Option<Duration>, shown_at_sink: Rc<Cell<Option<Instant>>>, )

Variant of attach_tooltip_with_sticky that also takes a shared Rc<Cell<Option<Instant>>> “sink” the tree updates whenever the tooltip is shown or dismissed. The rich tooltip widget reads from this sink to drive its dwell indicator without needing a paint-gap heuristic.

Source

pub fn attach_tooltip_with_sticky_sink_placement( &mut self, anchor_id: WidgetId, content_id: WidgetId, delay: Duration, sticky_after: Option<Duration>, shown_at_sink: Rc<Cell<Option<Instant>>>, placement: TooltipPlacement, )

Variant of attach_tooltip_with_sticky_sink that also carries a TooltipPlacement — the full-featured path used by MenuItem / TabHeader / StandardItem rich + composite tooltips that want Side placement.

Source

pub fn is_descendant_of(&self, widget_id: WidgetId, ancestor: WidgetId) -> bool

Source

pub fn promote_tooltip_to_sticky(&mut self, content_id: WidgetId)

Promote a shown tooltip from “ephemeral hover” to “sticky”.

  • Flags the tooltip entry as sticky so tooltip_pointer_leave no longer auto-dismisses it,
  • Swaps the overlay’s dismiss behavior to EscapeOrClickOutside so clicking anywhere off the tooltip (or pressing Escape) closes it.

The entry is not removed: when the user later dismisses the sticky overlay, dormant_dismissed_content resets the entry back to its initial state so a future hover re-shows the tooltip from scratch.

Called from RichTooltipWidget (or by the auto-promote sweep) once the dwell timer reaches its threshold.

Source

pub fn next_timer_deadline(&self) -> Option<Instant>

Returns the earliest deadline for a pending tooltip or delayed overlay (if any).

Source

pub fn overlay_manager(&self) -> &OverlayManager

Source

pub fn overlay_manager_mut(&mut self) -> &mut OverlayManager

Mutable access to the overlay manager. Used by the modal-presentation pipeline to wire up cascade-dismissal between paired overlays (e.g. the dialog scrim and the modal panel) via OverlayManager::set_parent_overlay.

Source

pub fn active_overlays(&self) -> Vec<OverlayId>

Source

pub fn overlay_content_bounds(&self, id: OverlayId) -> Option<Rect>

Laid-out bounds of an open overlay’s content surface.

This is the size the overlay pass actually measured — taken with an unbounded proposal, independent of the host tree’s own proposal — so it is the right thing to assert against for content that must cap or wrap itself (tooltips against TOOLTIP_MAX_WIDTH, popovers against their max height). Reading bounds(content_id) instead would report whatever the surrounding layout handed the widget.

Source

pub fn show_overlay(&mut self, request: OverlayRequest) -> OverlayId

Source

pub fn show_overlay_in_band( &mut self, request: OverlayRequest, band: OverlayBand, ) -> OverlayId

Show an overlay in an explicit z-band.

show_overlay is this with OverlayBand::Standard. The other band is for the touch text affordances — selection handles, the magnifier, the selection toolbar — which must render above the editor’s clips_children ancestor, below every menu, and outside the outside-press dismissal that every caret-moving tap would otherwise trigger. See crate::overlay::text_affordance.

Source

pub fn show_overlay_from_source( &mut self, source_widget: WidgetId, request: OverlayRequest, ) -> OverlayId

Show an overlay relative to a source widget, inheriting the source overlay ancestry and focus-restore behavior used during event dispatch.

Source

pub fn show_overlay_for( &mut self, request: OverlayRequest, duration: Duration, ) -> OverlayId

Source

pub fn dismiss_overlay(&mut self, id: OverlayId)

Dismiss an overlay programmatically. Uses NoopWindowOps for any focus-loss handlers it triggers — user code fires these from outside a dispatch.

Source

pub fn dismiss_overlay_with_ops( &mut self, id: OverlayId, ops: &mut dyn WindowOps, )

Dispatch-path variant that threads ops through to the focus-loss handler fired during dismissal.

Source

pub fn is_visible(&self, id: WidgetId) -> bool

Source§

impl WidgetTree

Source

pub fn start_fling( &mut self, target: WidgetId, velocity: Vec2, chain: Vec<(WidgetId, PanClaim)>, )

Begin coasting target at velocity (in scroll-offset space), chaining along chain when it runs out.

Public so a surface that drives its own release — a SceneView, a custom canvas — can hand the tree a coast instead of integrating one. prefers_reduced_motion collapses it to nothing: a re-dispatched fling has no settle to fall back to, because the target already has the content where the finger left it.

Source

pub fn stop_fling(&mut self, target: WidgetId)

Stop target’s coast, if it has one. Idempotent.

Source

pub fn is_flinging(&self, target: WidgetId) -> bool

Whether target is coasting.

Source

pub fn tick_flings(&mut self, now: Instant)

Advance every coast to now and dispatch what it produced.

Each delta goes through the same door and along the same frozen chain a pan does, so a flick that runs out of inner list scrolls the outer one. A coast the whole chain declines is stopped: it has nothing left to move, and spinning a simulation against a wall is a frame budget spent on nothing.

Source

pub fn tick_flings_with_ops(&mut self, now: Instant, ops: &mut dyn WindowOps)

tick_flings with the caller’s WindowOps sink.

Source

pub fn dispatch_os_gesture( &mut self, gesture: GestureEvent, at: Option<Point>, ops: &mut dyn WindowOps, )

Route a pre-recognized gesture that carries no position of its own.

The single ingress for pinch. The OS trackpad stream (PinchGesture / RotationGesture, which winit reports without a position) and the two-contact TouchPinchRecognizer both arrive here, so on_pinch cannot be reachable on one input and dead on the other.

at is the gesture’s own position when it has one — the touch recognizer supplies the contact midpoint. With None the route is the hover owner’s last position, then the hovered widget, then the focused one, then the root: the OS says only that a pinch happened, and the pointer that could have said where is a trackpad, whose cursor is the hover owner.

Source

pub fn touch_pinch_active(&self) -> bool

Whether a two-contact pinch is in progress.

Source

pub fn set_backend_reports_palm(&mut self, reports: bool)

Declare whether the backend classifies palms itself.

false — the default, and what every BackendCaps row Teksilo ships today reports — turns on the conservative fallback in PalmWatch. Set it true from a backend that advertises reports_palm, where the digitiser’s own answer is better than any heuristic and has already been applied at PointerTable::would_admit.

Source

pub fn palm_fallback_active(&self) -> bool

Whether the palm fallback is running.

Source

pub fn next_input_deadline(&self) -> Option<Instant>

The earliest wall-clock instant at which the input layer wants the event loop back: a pending gesture deadline (a long press), a press whose feedback delay has not elapsed, a standing hold about to reach max_hold, a tree-owned long-press route waiting out its hold (super::touch_route), or a live fling simulation.

Folded into next_timer_deadline beside the tooltip, overlay and animation terms, so there is one ControlFlow::WaitUntil over the one clock rather than a second timer path for input.

Source§

impl WidgetTree

Source

pub fn cancel_pointer( &mut self, pointer: PointerId, reason: CancelReason, ops: &mut dyn WindowOps, )

Revoke pointer’s interaction, for reason.

Always queued behind the sample currently being dispatched, and a no-op if that interaction has already finished by the time the queue drains — a cancel raised from a handler must not fire against a press the very same sample completed. “Finished” means the pointer is no longer live, or holds no capture and has no sequence, or its sequence is already inside its own terminal dispatch; all three say there is nothing left to revoke.

The teardown runs in one order, and the order is load-bearing: every competitor’s recognizer state goes first (so nothing can recognize on the way out), then the arbitration, then the capture, then the drag session, then the table entry, and the event is delivered last — to a tree that has already forgotten the interaction, so a handler that reacts by capturing or dragging starts from a clean slate rather than racing the teardown.

Two teardown steps named in the design are absent because their subject does not exist yet: the framework press signal (P11) and the fling driver (P13/P21) each clear at the marked point below.

Source

pub fn cancel_pointer_to( &mut self, pointer: PointerId, reason: CancelReason, recipient: Option<WidgetId>, ops: &mut dyn WindowOps, )

cancel_pointer, addressed to a widget the caller names rather than to whoever the table says holds the pointer.

For a producer whose own teardown has already given the capture back before it raises the cancel — the OS-drag escalation hands the pointer to the platform first — so the funnel would otherwise have nobody left to tell. The named widget is used only while it is still there; a recipient destroyed in the meantime falls back to the ordinary chain.

Source

pub fn cancel_all_pointers( &mut self, reason: CancelReason, ops: &mut dyn WindowOps, )

Revoke every live pointer, for reason. The window went away under them, a modal opened over them, the platform took the seat.

Source

pub fn cancel_pointers_in_subtree( &mut self, root: WidgetId, reason: CancelReason, ops: &mut dyn WindowOps, )

Revoke every pointer whose interaction is anchored inside root.

“Anchored inside” means the pointer’s captor is root or a descendant of it: that widget is the one about to stop existing, and the pointer it holds would otherwise be stranded on it. A pointer merely passing over the subtree is not anchored in it and is left alone.

A pointer whose press is no longer revocable is skipped, which is what makes the named exemption work: tapping a menu item whose own handler closes its menu must complete the tap, not have it cancelled out from under itself by the teardown it asked for.

Source§

impl WidgetTree

Source

pub fn dispatch_event_with_ops( &mut self, event: WidgetEvent, ops: &mut dyn WindowOps, )

Dispatch an event into the widget tree.

Routing rules:

  • Pointer events -> hit testing against layout tree
  • Keyboard/IME events -> focused widget
  • AccessKit actions -> target widget directly
  • Scroll events -> hit testing (scroll target under pointer)

Dispatch an event with the caller-supplied app-level WindowOps sink. teksilo-app calls this variant; handlers can reach the multi-window API synchronously (open_window creates the winit window inside the same call before returning).

Source

pub fn dispatch_event(&mut self, event: WidgetEvent)

Dispatch an event on a standalone tree (tests, headless scenarios). Handler code that calls ctx.open_window(...) from within this dispatch will panic — by design. See dispatch_event_with_ops for the app-facing variant.

Source

pub fn dispatch_pointer(&mut self, sample: PointerSample)

Deliver one pointer sample.

This and dispatch_scroll are the real input doors: a backend produces PointerSamples and ScrollSamples, and everything Teksilo knows about who is pointing — identity, kind, pressure, timestamp, coalesced history — reaches the tree through them.

For now a sample is lowered onto the legacy WidgetEvent it describes and takes the existing route, so a mouse behaves bit for bit as it did before the doors existed. What changes here is only that the door exists and that the sample’s PointerInfo is visible to handlers through EventContext::pointer.

Source

pub fn dispatch_pointer_with_ops( &mut self, sample: PointerSample, ops: &mut dyn WindowOps, )

dispatch_pointer with the caller’s app-level WindowOps sink, so handlers can reach the multi-window API synchronously.

Source

pub fn dispatch_scroll(&mut self, sample: ScrollSample)

Deliver one scroll sample.

Routing follows ScrollSample::position: Some hit-tests it, None falls back to the hovered (else focused) widget, which is what every scroll did before. A mouse wheel carries no position, so this is a no-op for a mouse; a pan synthesised from a direct pointer must carry one, because a contact never writes hover.

Source

pub fn dispatch_scroll_with_ops( &mut self, sample: ScrollSample, ops: &mut dyn WindowOps, )

dispatch_scroll with the caller’s app-level WindowOps sink.

Source

pub fn pointer_left_window(&mut self, ops: &mut dyn WindowOps)

The pointer left the window.

The third ingress door, and the only one that carries no sample: the OS says the cursor crossed the window boundary and nothing else. It exists because hover is otherwise cleared only by a move that lands elsewhere — so a mouse that leaves through an edge would leave the last widget hovered for as long as it stays away, with its hover chrome painted, its hover_within signal true and its tooltip still counting down.

Clears hover the way a move to an empty spot does: a PointerLeave to the hovered widget, the tooltip dwell cancelled, the hover_within chain updated. It touches nothing else — no pointer is cancelled, no capture released, no table entry ended. A mouse that leaves the window is still a mouse, and a captured pointer is deliberately exempt: a drag whose pointer wanders off the window keeps its target, which is what makes a drag past the edge (and the OS-drag escalation built on it) work at all.

There is no matching pointer_entered_window, and that is not an omission: the enter carries no position either, and a position only ever arrives with a CursorMoved — which re-arms hover through the ordinary path. A door that could only say “somewhere” would have nothing to hit-test.

Source

pub fn hit_test(&self, point: Point) -> Option<WidgetId>

Hit-test at a point for the mouse, exactly — the meaning this door has always had, and keeps.

A mouse cursor’s hot-spot is exact, so neither hit-targeting mechanism applies to it: the outset pre-pass sees zero insets and the miss-only slop pass short-circuits on a zero radius. A caller that holds a pointer should use hit_test_for instead, which is the same test for a mouse and the widened one for a finger or a stylus.

Source

pub fn hit_test_for( &self, point: Point, pointer: &PointerInfo, ) -> Option<WidgetId>

Hit-test at a point on behalf of a named pointer.

Runs the exact pass with that pointer’s Widget::hit_outset, then — only if the exact pass found nothing eligible — the miss-only slop pass. For PointerKind::Mouse this is exactly hit_test.

Candidates are restricted to the topmost overlay layer the exact pass entered: a press inside an open menu can be re-attributed to a menu row, never to a control on the page behind it.

Source

pub fn hit_test_for_excluding( &self, point: Point, pointer: &PointerInfo, exclude_overlay: Option<OverlayId>, exclude_widget: Option<WidgetId>, ) -> Option<WidgetId>

hit_test_for with the drag-and-drop exclusions of hit_test_excluding_overlay_and_widget.

Source

pub fn hit_test_excluding_overlay_and_widget( &self, point: Point, exclude_overlay: Option<OverlayId>, exclude_widget: Option<WidgetId>, ) -> Option<WidgetId>

Hit-test at a point, excluding a specific overlay and widget from consideration. Used during drag-and-drop to exclude the preview overlay and its content widget, so they don’t block hit-testing of the actual drop targets underneath.

Mouse, exact — the pointer-aware twin is hit_test_for_excluding.

Source§

impl WidgetTree

Source

pub fn input_clock(&self) -> Rc<dyn InputClock>

This tree’s input clock — the one source of EventTimes for everything the pointer path does.

A MonotonicClock anchored at the tree epoch by default. The epoch is the same Instant simulated_now starts at, so the input timeline and the simulated animation timeline are one axis rather than two.

Source

pub fn set_input_clock(&mut self, clock: Rc<dyn InputClock>)

Replace the input clock.

A headless test installs a ManualClock here so gesture deadlines fire exactly when it says, with no sleeping and no dependence on how long the test itself took.

Source

pub fn resume_real_time(&mut self)

Hand time back to the wall clock, carrying forward everything that was advanced while it was simulated.

Who calls this. A host that shares a live tree with a real event loop — the debug automation bridge — after each operation that may have advanced the clock. A headless test does not: a test wants the freeze, and wants it to survive between calls, so that two samples it dispatches without advancing are stamped the same instant rather than however many microseconds apart the machine happened to run them.

The animation axis is handed back by rebasing the scheduler’s stored instants the other way, the exact inverse of what enter_simulated_mode did. An animation half-way through when the operation ends is half-way through on the wall clock too, and the next real layout pass advances it from there — neither snapped to its end (which is what ticking at the wall clock against a start stamped on the simulated one gives) nor stuck (which is what ticking a live tree at a simulated clock nothing is advancing any more gives).

The input axis cannot simply drop its origin. A frozen axis that has been advanced reads ahead of the raw clock; dropping the origin would send input_now backwards, and a monotone EventTime is a platform conformance invariant every velocity tracker, tap streak and hold relies on. So the gap is measured — afresh, against this hand-back’s own readings, never added to what a previous one measured, and floored at zero for the case where the raw clock is already the later of the two — and kept in sim_input_offset: the reading at this instant is the later of the frozen reading and the raw one, and it moves with the wall clock from here.

A no-op on a tree that is not simulating time, so calling it after every operation costs nothing.

Source

pub fn input_now(&self) -> EventTime

The current time on this tree’s input timeline.

While the axis is frozen this is a reading of sim_clock, not of the wall clock, so a deadline can only be reached by advancing the clock. Once resume_real_time has handed it back it is the clock again, plus everything that was advanced.

Source

pub fn sequence_winner(&self, pointer: PointerId) -> Option<WidgetId>

The winner of pointer’s sequence, if one has been decided.

Source

pub fn sequence_members( &self, pointer: PointerId, ) -> Vec<(WidgetId, MemberRole, MemberState)>

Every competitor for pointer’s press, innermost first.

The observable form of the cross-widget arbitration, and the successor to the old armed_drag_observers(): an app can assert that a press on a control inside a draggable container enrols no ancestor at all.

Source

pub fn sequence_touch_action(&self, pointer: PointerId) -> TouchAction

The TouchAction frozen for pointer’s press.

Source

pub fn tick_gestures(&mut self, now: Instant)

Source

pub fn tick_gestures_with_ops(&mut self, now: Instant, ops: &mut dyn WindowOps)

App-facing variant of tick_gestures that accepts a real WindowOps sink so gesture-recognized handlers can call the multi-window API synchronously.

Source

pub fn next_gesture_deadline(&self) -> Option<Instant>

Earliest wall-clock deadline at which any active gesture arena needs WidgetTree::tick_gestures called — typically a pending long-press timeout. Returns None when no recognizer is waiting.

Source§

impl WidgetTree

Source

pub fn bounds(&self, id: WidgetId) -> Rect

Source

pub fn last_pointer_position(&self) -> Option<Point>

Last known pointer position from a PointerMove event. Used by the safe-triangle submenu hover gate to compare the cursor trajectory against the open submenu’s bounds without requiring the gate’s evaluation site to receive a fresh PointerMove itself.

Source

pub fn pointer_position(&self, pointer: PointerId) -> Option<Point>

Where a named pointer is, in window-logical coordinates.

None if that pointer is not live. The per-pointer companion to last_pointer_position, which reports the primary.

Source

pub fn captured_by(&self, pointer: PointerId) -> Option<WidgetId>

The widget holding pointer’s capture.

Capture is per pointer: two contacts hold independent captures, and each is released only by its own Up or Cancel.

Source

pub fn pointer_captured_by(&self) -> Option<WidgetId>

The widget holding the primary pointer’s capture — the singular view of capture, and for a mouse-only machine the whole story.

Source

pub fn live_pointers(&self) -> impl Iterator<Item = PointerInfo> + '_

Every live pointer.

A mouse appears once it has produced a sample and stays for the life of the tree (it never lifts); a contact appears at its press and is gone after its Up or Cancel.

Source

pub fn primary_pointer(&self) -> Option<PointerInfo>

Teksilo’s single pointer — the one backing hovered and last_pointer_position. A mouse wins the role whenever one is live; failing that, the oldest pointer does.

Not the same thing as PointerInfo::primary, which is the W3C per-kind flag and can be true for two pointers at once.

Source

pub fn hover_owner(&self) -> Option<PointerInfo>

The most recent hovering-capable pointer — a mouse, or a pen in proximity. Hover, the cursor and tooltip dwell all follow it, and a touch contact is never it.

Source

pub fn widget_as_any(&self, id: WidgetId) -> Option<&dyn Any>

Borrow the widget at id as &dyn Any for concrete-type introspection. Uses the Widget::as_any hook — widgets that haven’t opted in return None. Primarily for tests that need to inspect a widget’s private Signal state.

Source

pub fn widget_as_any_mut(&mut self, id: WidgetId) -> Option<&mut dyn Any>

Mutable variant of widget_as_any. Widgets opt in by overriding Widget::as_any_mut. Used by tests that need to mutate widget state post-layout (e.g. declaring a logical AT parent on a SceneView after the arena allocated the inner widget’s WidgetId).

Source

pub fn children(&self, id: WidgetId) -> Vec<WidgetId>

Source

pub fn roots(&self) -> Vec<WidgetId>

Root widget ids of the arena (the entry points for a full widget-tree walk). Mirrors what the debug inspector starts its tree view from.

Source

pub fn widget_type_name(&self, id: WidgetId) -> Option<&'static str>

The concrete Rust type name of the widget at id (e.g. "teksilo_widgets::button::Button"), or None if the id isn’t in the arena. The same Widget::type_name() the inspector’s tree view labels rows with.

Source

pub fn widget_debug_string(&self, id: WidgetId) -> Option<String>

The widget at id formatted via its Debug impl — its constructor parameters / fields, the same “debug repr” the inspector’s Properties tab shows. None if the id isn’t in the arena.

Source

pub fn widget_clips_children(&self, id: WidgetId) -> bool

Whether the widget at id clips its children (e.g. ScrollArea, MaxSize). false if the id isn’t in the arena.

Source

pub fn last_proposal(&self) -> SizeProposal

The most recent layout proposal applied to this tree (the size last passed to layout / layout_with_ops). Lets a settle pass re-run layout at the current size without recomputing it from a surface dimension. Returns SizeProposal::exact(800.0, 600.0) on a tree that was never laid out.

Source

pub fn at_version(&self) -> &Signal<u64>

Monotonic accessibility-tree version. Bumped in sync_accessibility only when a rebuild produces a tree whose content actually differs from the cached one (cache hits don’t bump, and a rebuild that reproduces an identical TreeUpdate — e.g. from a shortcut-rebind / locale invalidation — doesn’t either). Saturating, so the monotonic contract holds past u64::MAX. Mirrors ShortcutRegistry::version: poll it to detect AT-tree changes without diffing the whole TreeUpdate.

Source

pub fn announcements_since(&self, seq: u64) -> Vec<Announcement>

Drain the captured live-region announcements with seq strictly greater than seq. See crate::accessibility::Announcement. The buffer is capped at 256 entries, so a caller that lags far behind sees only the retained tail. Read after a sync_accessibility (or a settle that ends in one) to observe announcements raised by the latest rebuild.

Source

pub fn parent(&self, id: WidgetId) -> Option<WidgetId>

Parent widget id in the arena graph, or None for roots.

Source

pub fn needs_layout(&self) -> bool

Source

pub fn needs_paint(&self) -> bool

Source

pub fn active_animation_count(&self) -> usize

Source

pub fn pending_tooltip_count(&self) -> usize

Source

pub fn has_idle_work(&self) -> bool

Whether there are pending idle callbacks to run.

Source

pub fn has_pending_modal_requests(&self) -> bool

Source

pub fn has_pending_modal_dismissal(&self) -> bool

Source

pub fn current_cursor(&self) -> CursorIcon

Source

pub fn hovered(&self) -> Option<WidgetId>

The widget currently under the pointer, if any. The framework updates this on PointerMove / hover routing; widgets that have captured the pointer or that opt out via event_pass_through affect what shows up here. Mirrors the private hovered field for read-only consumers (debug inspector, layout introspection).

Source

pub fn hovered_for(&self, pointer: PointerId) -> Option<WidgetId>

The widget a named pointer is over.

Only ever Some for the hover owner: a contact produces no hover, so asking a finger what it is hovering always answers None.

Source

pub fn has_pending_dispatch(&self) -> bool

Whether any dispatch is waiting to be replayed.

Always false outside a dispatch — the queue is drained before a top-level dispatch_* returns. A test asserts that; nothing else should need to ask.

Source

pub fn last_pointer_kind_signal(&self) -> Signal<PointerKind>

Reactive handle to the kind of the pointer that most recently produced a sample — mouse, finger, stylus.

The one question an adaptive affordance actually needs: whether the user is currently working by hover or by contact. Bind it rather than remembering an on_pointer_event purely to learn the modality.

Source

pub fn hovered_signal(&self) -> Signal<Option<WidgetId>>

Reactive handle to the hovered widget id. Cheap clone — the underlying Signal is shared. Set whenever hovered changes during dispatch, post-layout hover recovery, widget destruction, or overlay subtree dormancy. Intended for debug tooling that wants to react to hover without polling (the inspector’s hover tooltip).

Source

pub fn focused_signal(&self) -> Signal<Option<WidgetId>>

Reactive handle to the focused widget id. Mirror of hovered_signal for the focus chain; drives the inspector’s Focus tab without polling.

Source

pub fn run_idle_callbacks(&mut self, budget: Duration)

Drain and run all pending idle callbacks with the given time budget. Called by the event loop during idle periods between frames.

Source§

impl WidgetTree

Source

pub fn render(&mut self) -> Rc<RenderFrame>

Paint all active widgets and produce a RenderFrame. Uses per-widget paint caching: only widgets with needs_paint are re-painted; clean widgets reuse their cached paint output. Also caches the full assembled frame — if no widget needs painting, the previous frame is returned immediately.

Source

pub fn render_with_ops(&mut self, ops: &mut dyn WindowOps) -> Rc<RenderFrame>

Render a frame, threading the app’s WindowOps sink through any state-change-triggered handlers (data-driven rebuild, binding flush). Called by teksilo-app during its paint pipeline.

Source§

impl WidgetTree

Source

pub const FLING_SAMPLE_INTERVAL: Duration

The cadence fling samples at: one 60 Hz frame, which is under the velocity tracker’s STOP_GAP and therefore never splits a flick into two unrelated runs.

Source

pub fn tooltip_content_within(&self, widget: WidgetId) -> Option<WidgetId>

The content id of the tooltip anchored at widget or anywhere inside it.

The attach helpers keep the content id to themselves, so a test that needs to drive a tooltip’s own surface (promote it, focus into it) has no other way to name it. Matching the whole subtree, not just the id, is what makes this work for composing controls: Button keeps focus on its outer node but attaches its tooltip to an inner body root.

Source

pub fn tooltip_is_sticky_within(&self, widget: WidgetId) -> bool

Whether that tooltip has been promoted.

Promotion is the line between an informational tip and a panel the user asked for: it decides the AT role, the dismiss behaviour, and whether the surface takes a Tab stop.

Source

pub fn click(&mut self, id: WidgetId)

Simulate a click at the center of a widget.

Source

pub fn synthesise_tap(&mut self, id: WidgetId)

Synthesise a primary-button tap at the center of id’s resolved bounds. The OS hands the click off to the widget tree even though the click never went through the normal hit-test path. Used by the Windows custom-title-bar backend when WM_NCHITTEST reported HTMINBUTTON/HTMAXBUTTON/HTCLOSE for an area covering a ControlButton — the OS treated the area as non-client and WM_LBUTTONDOWN/UP never fired in widget land, so we re-issue a synthetic primary-button down

  • up on the right widget.

Equivalent semantics to Self::click; named differently so production call sites read clearly.

The tap runs on a standalone dispatch, so a handler it reaches cannot use the multi-window API. Call synthesise_tap_with_ops from anywhere that already holds a real WindowOps sink.

Source

pub fn synthesise_tap_with_ops(&mut self, id: WidgetId, ops: &mut dyn WindowOps)

synthesise_tap, dispatched over the caller’s app-level WindowOps sink.

A synthetic tap is a nested dispatch, and everything the tapped widget does happens inside it — including the intent it sends and the action that intent resolves to. Dispatching it standalone therefore hands that action a context with no window sink: ctx.open_window panics, and find_window / focus_window / close_window_by_id silently do nothing. That is how keyboard activation in a menu (Enter, Space, a mnemonic, type-ahead — all four route through EventContext::synthetic_click) lost the multi-window API that the same row reached fine by mouse.

Source

pub fn pointer_move(&mut self, position: Point)

Simulate pointer movement to a position.

Source

pub fn press_key(&mut self, key: Key, modifiers: Modifiers)

Simulate a key press (down + up), carrying the text the platform attaches to the key (Key::to_text).

That text is not decoration: Escape arrives as U+001B, and a widget that inspects text behaves differently with it than without. This helper used to send text: None for every key, so a whole class of bug was invisible to every test in the workspace — a field that swallowed Escape passed the suite while failing in the user’s hands.

Source

pub fn type_text(&mut self, _widget: WidgetId, text: &str)

Simulate typing text into the focused widget.

Source

pub fn pointer_down_button(&mut self, position: Point, button: PointerButton)

Simulate a pointer down at a specific position with a specific button.

Source

pub fn pointer_up_button(&mut self, position: Point, button: PointerButton)

Simulate a pointer up at a specific position with a specific button.

Source

pub fn drag(&mut self, from: Point, to: Point)

Simulate a drag from one position to another.

Source

pub fn child_bounds(&self, parent: WidgetId, index: usize) -> Rect

Get bounds of a child by index.

Source

pub fn child_widget(&self, parent: WidgetId, index: usize) -> WidgetId

Get a child widget ID by index.

Source

pub fn advance_time(&mut self, duration: Duration)

Advance this tree’s clock by duration, and run everything that clock drives.

The one door. One call moves, to one virtual now: the simulated clock, the input timeline, the gesture arenas (today: the long-press hold), the press-feedback delays, every live fling, the animation scheduler, the frame tick, the overlay manager’s clock, tooltip dwell, delayed overlays, the pointer-leave grace and overlay auto-dismissal — then drains the signal, rebuild and visibility changes any of that produced. A caller never has to advance a second thing to keep one of those in step with another.

It is not, however, the door to everything that is timed; the list below is the current boundary, and it is the list that has to grow when a subsystem is brought onto this clock.

While this runs, time is taken over: the input timeline and the animation clock both read the simulated clock and nothing else. A long press fires because the caller advanced the hold and never because the caller itself took that long; two samples dispatched without an intervening advance are stamped the same instant rather than however far apart the machine happened to run them; and an animation ages by exactly what was advanced. A headless test wants that to persist, and it does. A host sharing the tree with a real event loop — the debug automation bridge — must give time back when the operation ends, or the window it is attached to never measures another gesture and never advances another animation frame: see resume_real_time.

What it does not move:

  • The shader-driven AnimatedQuadRegistry. It is ticked from render() and has no simulated door at all.
  • A deferred member’s eligible_at on a PointerSequence. Not an oversight: eligibility is never stored, it is re-derived against the timestamp of whatever sample is being arbitrated, so there is no transition to perform at that instant and a press that sat still past its long_press is already eligible on its very next move. See PointerSequence::next_hold_deadline. A hold’s max_hold, by contrast, is a stored transition and is moved — by the gesture pass in (3).
  • Any clock a widget owns itself. A widget that reads the wall clock directly rather than taking its deadline from the tree is outside this door by construction, and there are several in teksilo-widgets.

Dispatched over a no-op window sink; call advance_time_with_ops from anywhere that holds a real one.

Source

pub fn advance_time_with_ops( &mut self, duration: Duration, ops: &mut dyn WindowOps, )

advance_time, over the caller’s WindowOps sink.

A tick is a dispatch: a long press recognized here runs its handler, and that handler may open a window. Standalone, NoopWindowOps panics on open_window — the same trap synthesise_tap_with_ops exists for.

Source

pub fn advance_input_time(&mut self, duration: Duration)

advance_time, under the name the input side reads better by.

An alias, not a second timeline: there is one clock, and moving the input axis is moving it.

Source

pub fn simulated_now(&self) -> Instant

Get the current simulated clock value.

Source

pub fn tooltip_entry_count(&self) -> usize

Total number of live tooltip attachments, dead ones included.

Distinct from pending_tooltip_count, which only counts entries with a running dwell. This is the raw table size — the number that must stay flat across rebuilds, since attach_tooltip* is called from build() and the table is scanned on every pointer move, every layout pass and once per widget in the accessibility walk.

Source

pub fn tab_stops_within(&self, root: WidgetId) -> Vec<WidgetId>

Every widget the arena still holds — active, dormant and orphaned alike.

The number a leak test must assert on. active_widget_count walks the tree from its roots and so cannot see the failure mode that matters here: a node kept alive in the arena with nothing pointing at it. A parentless orphan (tooltip content is ctx.added, hence parentless by construction) is invisible to every other count in this file, and to the accessibility tree, while still paying for itself in the arena’s slotmap forever. Every node inside root (inclusive) that Tab traversal would stop on: focusable, and not suppressed by a tab_stop flag on itself or any ancestor.

Pressing Tab and watching focus cannot answer this for a view that claims the key for its own navigation — TableView moves a cell cursor on Tab, so focus never moves and the traversal graph underneath stays invisible. A data view should expose exactly one stop however many rows are realized; more than one means a control inside a row has leaked into the Tab order, where its presence would track the scroll position.

Membership matches the real collector (collect_scope_entries) exactly: a dormant node and a disabled subtree are both skipped, because Tab traversal returns at each. The two differ only in shape — the real collector groups a traversal_scope subtree so it can order it independently, and this returns one flat list in tree order — which is what a membership assertion wants.

The guards are load-bearing rather than cosmetic. Without them this reports stops the traversal never visits, and a test asserting that a culled or collapsed subtree left the Tab ring passes or fails for a reason unrelated to the mechanism it is pinning.

Source

pub fn widget_count(&self) -> usize

Source

pub fn destroy_subtree_for_testing(&mut self, id: WidgetId)

Tear down a widget and everything it owns — its subtree, its tooltip, and the parentless content it built with add_detached.

The application-facing door is BuildContext::destroy_subtree; this is the same call for tests that hold the tree directly.

Source

pub fn assert_no_leaked_pointer_state(&self)

Panic unless every trace of a pointer interaction is gone.

The one assertion a touch test ends with. A leak here is not a cosmetic untidiness: a surviving capture redelivers every later move to a widget nobody is pointing at, a surviving sequence lets a stale competitor win the next press, and a live recognizer entry starts the next contact mid-gesture. All three are silent until something much later misbehaves, which is why this is checked rather than reasoned about.

A hovering pointer resting in the table is not a leak: a mouse that has been seen once keeps its entry for the life of the tree, and that entry is what every singular accessor reads. What must not survive is a pointer still contacting the surface, a capture, a sequence, or a gesture arena still following a contact.

One thing the design lists is still absent: the touch-motion layer’s own state — live pans, coasts, the window’s pinch and the palm watches. The framework press is checked, at the bottom of this function.

Source

pub fn new_contact(&self) -> PointerId

Mint a fresh contact identity, the way the platform layer does.

A backend reuses its own contact ids the moment a finger lifts, so the allocator mints a PointerId per press; this is that call with a per-process os id, and it ends the mapping immediately so the allocator’s live table does not grow across a test run.

Source

pub fn touch_down(&mut self, pointer: PointerId, at: Point)

A finger lands at at.

Source

pub fn touch_move(&mut self, pointer: PointerId, at: Point)

That finger moves to at, still down.

Source

pub fn touch_up(&mut self, pointer: PointerId, at: Point)

That finger lifts at at.

Source

pub fn touch_cancel(&mut self, pointer: PointerId, at: Point)

The system revokes that finger (a wl_touch.cancel, a compositor grab). Not an touch_up: the end position carries no meaning and no tap is completed.

Source

pub fn pen_down(&mut self, at: Point, pressure: f32, tilt: (f32, f32))

The stylus tip touches down at at.

pressure is normalised 0.0..=1.0; tilt is (tilt_x, tilt_y) in degrees. Both are the axes a real digitizer reports, so a surface that reads PointerInfo::effective_pressure sees what it would see from hardware.

Source

pub fn pen_move(&mut self, at: Point, pressure: f32, tilt: (f32, f32))

The stylus draws to at, still on the surface.

Source

pub fn pen_up(&mut self, at: Point, pressure: f32, tilt: (f32, f32))

The stylus lifts off at at. It stays in proximity — a pen hovers, so its entry survives the lift and the next pen_move continues the same session.

Source

pub fn pen_hover(&mut self, at: Point)

The stylus moves in proximity without touching: no tip pressure, no button. The one direct-pointer hover in the framework.

Source

pub fn tap_with(&mut self, kind: PointerKind, at: Point) -> PointerId

A complete press-and-release at at by the named device, and the identity it used.

The mouse arm is PointerId::MOUSE and the legacy PointerDown/PointerUp pair, so tap_with(PointerKind::Mouse, ..) is the pre-touch-programme click with a position rather than a widget id.

Source

pub fn long_press_at(&mut self, kind: PointerKind, at: Point) -> PointerId

Press at at, hold for exactly the kind’s long_press, release.

The hold comes from the active profile rather than a constant written here, and it is advanced exactly — the recognizer fires at >= hold, so a helper that added a safety margin would stop the threshold itself from ever being asserted.

Source

pub fn touch_drag(&mut self, from: Point, to: Point, steps: usize) -> PointerId

One finger from from to to in steps evenly spaced moves, then a lift. Returns the contact’s identity, so the caller can ask sequence_winner about it.

The clock does not move: this is a drag, and a drag is decided by distance. Use fling when the speed is the point.

Source

pub fn fling(&mut self, from: Point, to: Point, over: Duration) -> PointerId

One finger from from to to over over of simulated time, released while still moving — the shape a coast is handed off from.

Sampled at FLING_SAMPLE_INTERVAL so the velocity tracker sees gaps under its STOP_GAP and at least its MIN_SAMPLE_SIZE of them; a flick described by two far-apart samples yields no velocity at all and would silently never fling.

Source

pub fn pinch( &mut self, a0: Point, b0: Point, a1: Point, b1: Point, steps: usize, ) -> (PointerId, PointerId)

Two fingers, from a0/b0 to a1/b1 in steps moves, then both lift. Returns their identities in the order they landed.

Both contacts are down before either moves, which is what a pinch needs: the recognizer’s reference span is the distance between the two landings.

Source

pub fn set_density(&mut self, density: TargetDensity)

Switch the active TargetDensity.

The name A21 gives set_input_density; an alias, because density is one setting and there is one door to it.

Source

pub fn touch_action_for(&self, id: WidgetId) -> TouchAction

The TouchAction in force at id: the intersection of every declaration from the root down to it.

This is what a press landing on id would freeze. Distinct from sequence_touch_action, which reports what a press already in flight froze — the two differ the moment a widget changes its declaration mid-press, which is the whole reason the value is frozen.

Source

pub fn mark_needs_paint(&mut self, id: WidgetId)

Mark a widget as needing repaint.

Source

pub fn set_dormant(&mut self, id: WidgetId)

Set a widget subtree as dormant.

Goes through the tree’s cancel-aware parking door, so a pointer working inside the subtree is cancelled rather than stranded on a widget the dispatcher will no longer reach.

Source

pub fn activate(&mut self, id: WidgetId)

Activate a dormant widget subtree.

Source

pub fn invalidate_all_paints(&mut self)

Invalidate all per-widget paint caches (paint AND post-paint) and the assembled frame cache. Forces every widget to repaint on the next render() call. Used by the glyph-atlas eviction recovery: after an eviction, any retained frame may hold quads whose atlas UVs now point at recycled slots.

Source§

impl WidgetTree

Source

pub fn new() -> Self

Source

pub fn run_with_event_context<F>(&mut self, ops: &mut dyn WindowOps, f: F)
where F: FnOnce(&mut EventContext<'_>),

Run a closure with a fresh EventContext anchored at this tree, then collect any pending operations queued through the context (intents, modal requests, frame requests, idle callbacks…) so they take effect on the next event-loop tick.

Used by the teksilo-app event-loop dispatcher to deliver async-result callbacks (file dialogs, future background tasks) on the main thread with full handler-equivalent semantics. There is no source widget for app-level events, so intents are anchored at the tree’s first root id (or silently dropped when the tree is empty).

Source

pub fn has_pending_mount_actions(&self) -> bool

Whether any post-mount actions are waiting to run.

Source

pub fn run_mount_actions(&mut self, ops: &mut dyn WindowOps)

Drain and run every queued post-mount action with a fresh EventContext built over ops. The app loop calls this each iteration with a real WindowOps sink (so ctx.parent_window_handle() resolves); headless tests call it with a NoopWindowOps. Actions enqueued by an action (rare) are left for the next drain rather than run re-entrantly.

Source

pub fn set_window_state(&mut self, state: WindowState)

Attach the WindowState for this tree’s hosting window. Called by WindowManager::create_window.

Source

pub fn window_state(&self) -> Option<&WindowState>

Source

pub fn frame_request_handle(&self) -> Rc<Cell<bool>>

Clone the shared “frame requested” flag. Widgets stash this in their state and call .set(true) from inside frame-tick closures to chain-request another frame without needing mutable access to the tree. See RichTextEditor for the canonical use (caret blink, drag-select auto-scroll).

Source

pub fn wake_at_handle(&self) -> Rc<Cell<Option<Instant>>>

Clone the shared wake-at deadline cell. Widgets stash this in their state and call request_wake_at from frame-tick effects to schedule a one-shot deadline without keeping the event loop in Poll mode. On the next layout() at or past the deadline, the tree auto-arms frame_tick_requested so the effect runs on the wake-up pass. Canonical use: the rich text editor’s caret blink schedules a 500 ms wake instead of pumping every frame.

Source

pub fn request_wake_at(&self, at: Instant)

Schedule a one-shot frame wake at at. Merges with any existing deadline — keeps the earlier instant so the most urgent wake wins.

Source

pub fn frame_tick(&self) -> Signal<f32>

The per-frame delta-seconds signal. Observers fire only on frames the tree was asked to pump via request_frame; merely observing the signal does not keep the event loop awake. See BuildContext::frame_tick for widget-side access and BuildContext::request_frame for the opt-in request side.

Source

pub fn request_frame(&self)

Ask the tree to pump exactly one more frame. needs_redraw() returns true until the request is consumed by the next layout() call, which fires the per-frame tick signal and clears the flag. Observers that still need more frames (drag auto-scroll, caret blink, pending document events) must call request_frame() again from inside their tick closure.

Takes &self on purpose: widget handlers and per-frame effects receive a shared reference to the tree via EventContext / BuildContext, and the request flag is a Cell specifically so those shared paths can toggle it without ceremony.

Source

pub fn request_accessibility_update(&self)

Request that the AccessKit tree be re-walked on the next sync_accessibility. Takes &self (the flag is a Cell) so handlers and build() closures reaching the tree through a shared reference can request a re-walk without &mut access. The drain at the top of sync_accessibility flips a11y_dirty.

Source

pub fn announce(&mut self, message: impl Into<String>)

Speak message to the screen reader, politely.

For anything the user needs told that is not the name of a widget: a completed action, a changed count, the result of an undo. The message is delivered on the next two accessibility syncs, which this schedules.

Prefer EventContext::announce inside a handler and BuildContext::announce inside a build; this is the tree-level entry point both of those reach.

Takes impl Into<String>, so tr!(…) works directly. See crate::announcer for why it is a String and not a LocalizedString, and for why an announcement beside a Toast says everything twice.

Source

pub fn announce_with( &mut self, message: impl Into<String>, politeness: Politeness, )

Speak message to the screen reader at the given urgency.

Politeness::Assertive interrupts whatever is being spoken; reserve it for something the user must not miss and cannot recover by re-reading the screen.

Source

pub fn a11y_request_handle(&self) -> Rc<Cell<bool>>

Clone the shared “accessibility re-walk requested” flag, for the same stash-and-toggle pattern as frame_request_handle.

Source

pub fn frame_requested(&self) -> bool

Whether a frame was explicitly requested. Exposed for tests and for the event-loop driver that decides when to schedule the next wake-up.

Source

pub fn frame_tick_deadline(&self) -> Option<Instant>

The next wake-up deadline for the per-frame-effect path, or None when no per-frame effect is armed.

This is the 60 Hz cap for continuous per-frame animations (Pulse, caret blink, drag auto-scroll, --cycle drivers). The per-frame-effect path used to force ControlFlow::Poll, which free-runs at the display’s refresh rate — so on a 300 Hz panel a single Pulse/Cycle rendered at 300 fps (measured ~45 % CPU) for motion that looks identical at 60 fps. Routing it through a fixed 16.667 ms deadline (folded into next_timer_deadline) makes it pace at 60 Hz regardless of refresh rate, matching the signal-tween AnimationScheduler and shader-quad AnimatedQuadRegistry, which already share the same interval.

A throttled subscriber (registered via FrameTickScheduler::subscribe_throttled — e.g. Cycle, whose visible child only changes once per period) stretches the deadline to its own interval: the loop then sleeps to the period instead of rendering identical 60 fps frames in between. The interval used is the minimum across all currently-visible subscribers, so a Cycle next to a Pulse still ticks at 60 Hz while a lone Cycle sleeps to its period. Raw request_frame consumers with no subscription fall back to 60 Hz.

Paces from last_frame_time so the cadence is drift-free; before the first render it fires on the next loop turn.

Source

pub fn subscribe_frame_tick(&self, owner: WidgetId) -> FrameTickSubscription

Subscribe owner to the per-frame-effect scheduler. The returned FrameTickSubscription is an RAII guard — drop it (typically by replacing the field on the owning widget on rebuild, or letting the widget’s Drop run) to remove the subscription. While the guard is alive, the tree will keep arming frame_tick_requested after every render in which owner was painted, and stop on frames where it wasn’t — so a subscribed widget hidden inside a non-selected Switcher branch contributes zero idle frames.

Apps should not call this directly — use BuildContext::subscribe_frame_tick from inside Widget::build.

Source

pub fn subscribe_frame_tick_throttled( &self, owner: WidgetId, interval: Duration, ) -> FrameTickSubscription

Like subscribe_frame_tick, but the owner only needs to wake at most once per interval while visible. Same visibility gate; between wakes the event loop sleeps to the interval deadline instead of rendering identical 60 fps frames. Use for effects whose visible output changes far less often than 60 Hz — e.g. Cycle’s once-per-period index advance.

Apps should not call this directly — use BuildContext::subscribe_frame_tick_throttled from inside Widget::build.

Source

pub fn set_app_context(&mut self, app_context: Rc<TreeAppContext>)

Replace the per-tree app context. Called by teksilo-app when constructing a window so the widget tree can reach the registered event source adapter and post subscription events through the event-loop proxy.

Source

pub fn app_context(&self) -> &Rc<TreeAppContext>

Get the per-tree app context. Used by BuildContext::subscribe_event and by the event-loop handler when dispatching incoming AppEvent::SubscriptionEvent.

Source

pub fn set_locale(&mut self, locale: String)

Switch the tree-level locale at runtime.

Updates locale_signal (a reactive Signal<Option<String>>) and marks all widgets dirty for relayout and repaint. Widgets are not rebuilt: per-string reactivity flows through LocalizedString::to_signal() which observes the teksilo-i18n manager, and anything else that depends on the tree-level locale can bind to locale_signal().

Source

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

Currently active locale identifier, if any.

Source

pub fn locale_signal(&self) -> &Signal<Option<String>>

Reactive handle on the current locale. Mirrors locale() but updates observers when set_locale is called.

Source

pub fn with_theme(self, theme: Theme) -> Self

Source

pub fn with_text_backend(self, backend: Rc<RefCell<dyn TextBackend>>) -> Self

Source

pub fn with_title_bar_host(self, host: Rc<dyn PlatformTitleBarHost>) -> Self

Attach a platform host for custom window chrome. Set by the WindowManager when the application opts in via WindowConfig::custom_chrome(true). Widgets like TitleBar retrieve it from inside the root-builder closure via Self::title_bar_host.

Source

pub fn set_title_bar_host(&mut self, host: Rc<dyn PlatformTitleBarHost>)

Source

pub fn title_bar_host(&self) -> Option<Rc<dyn PlatformTitleBarHost>>

Get the platform title bar host, if one was attached. Returns None when the application did not opt into custom chrome, or when the platform does not support it (X11 without an EWMH-capable window manager, or a headless build).

Source

pub fn theme(&self) -> &Theme

Source

pub fn theme_signal(&self) -> &Signal<Theme>

Reactive handle on the current theme. Updates fire when set_theme is called; widgets that want theme-derived values to stay live should build derived signals via theme_signal.map(...) or combine with other inputs using .zip(...).

Source

pub fn needs_redraw(&self) -> bool

Whether any widget needs layout or paint (i.e., a redraw would be useful).

Uses has_running rather than has_active so that animations parked by the window-inactive gate stop forcing the event loop into ControlFlow::WaitUntil. Without this, an unfocused window would still wake at the animation frame interval and the pause would save nothing. Both the signal scheduler AND the shader-driven animated-quad registry are consulted — a ProgressBar::indeterminate whose widget has no pending paint dirt still needs the loop to keep waking at the animation frame interval so its phase advances.

Source

pub fn needs_render(&self) -> bool

Whether a render pass is needed (any widget needs layout or paint).

Source

pub fn needs_reconcile(&self) -> bool

Whether this tree has reactive work that only a layout() pass can turn into arena dirt — i.e. whether reconciling it right now could change what needs_render reports.

Read-only and cheap: O(unique bound sources) u64 comparisons plus one peek per registered animated signal. No arena walk, no rebuilds, no geometry. Asking does not consume the answer, so it can be asked every dispatch.

§Why this is exactly the right question, and no broader

teksilo_app::WindowManager::request_redraw_needing_render exists for ONE case: a handler in window A wrote a Signal that window B’s widgets also bind, and B — which never saw the event — must be reconciled before anyone can tell it needs repainting. Every OTHER thing layout_with_ops drives already has its own scheduling path and does not need this sweep:

  • tooltip dwell + sticky steps, delayed overlays, auto-dismiss, overlay fades, the animation scheduler, animated quads, gestures, wake_at and the 60 Hz frame tick are all timing driven, and every one of them contributes to next_timer_deadline — which request_redraw_due polls to wake precisely the due windows;
  • drag ticks follow that window’s own pointer stream;
  • a handler that called request_rebuild marked the arena directly, so needs_render() is already true without any reconcile.

So the two terms below are what the sweep uniquely covers: binding-registry staleness (the whole point), and a pending animate_to — which the scheduler has not started yet, so it contributes no deadline, and which only process_pending_animations (inside layout) can promote into one. The second term is belt-and-braces: arming an animation also advances the signal’s generation, so a bound animated signal is already covered by the first — but an animated signal registered without being bound would not be, and this makes that impossible to get wrong.

Source

pub fn register_animated_signal( &mut self, signal: &Signal<f32>, owner: WidgetId, )

Register a Signal<f32> for animation support. The framework checks registered signals each frame for pending animate_to requests. Called automatically by BuildContext::animated_signal()owner is ctx.self_id() of the widget whose build() created the signal. Used by the scheduler to pause/cancel animations when the owning widget is offscreen, dormant, or destroyed.

Source

pub fn has_active_animations(&self) -> bool

Whether any animation is currently running.

Source

pub fn mark_all_needs_paint_only(&mut self)

Mark the owning window as active (focused AND not occluded) or inactive. Propagates to the animation scheduler AND the animated-quad registry so both pause-resume in lockstep — no ticks, no frame wakes, no GPU submits.

On an actual state change it also fires window_active_signal (so build-time binders and DimWhenInactive react) and issues a global paint-only dirty mark, so every widget that reads PaintContext::window_active (caret gates, selection bands) repaints once. This is a repaint, not a relayout — geometry never changes when the window’s active state flips (the caret keeps its space). Window focus changes are rare and user-driven, so the O(n) mark is cheap and Mark every node paint-dirty (no relayout, no rebuild) so the next render re-runs their paint(). This is the paint-cache invalidation an off-thread source needs after posting a RepaintWindowRequest: a bare redraw request re-presents the cached frame, so a widget whose content changed off the UI thread (a terminal’s PTY output) must be marked dirty for its paint() to run again.

Source

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

strictly lighter than set_theme’s mark_all_dirty (layout + paint).

Source

pub fn set_window_active_with_ops( &mut self, active: bool, ops: &mut dyn WindowOps, )

set_window_active with the caller’s app-level WindowOps sink, so the on_pointer_cancel handlers a deactivation fires can reach the multi-window API like any other handler.

Source

pub fn is_window_active(&self) -> bool

Whether the owning window is currently active (focused AND not occluded). The reactive companion is Self::window_active_signal.

Source

pub fn window_active_signal(&self) -> Signal<bool>

Reactive handle on window-active state. Fires when the window gains or loses active status. Bind at BindingLevel::RepaintOnly — an active-state flip never affects geometry. Starts true.

Source

pub fn register_animated_quad( &mut self, owner: WidgetId, kind: AnimatedQuadKind, ) -> AnimatedQuadHandle

Register a new animated quad for the currently-building widget. Called by crate::build_context::BuildContext::animated_quad; returns an opaque handle the widget stashes for its paint() call.

Source

pub fn animated_quad_count(&self) -> usize

Active animated-quad slot count. Test / debug helper.

Source

pub fn tick_animations(&mut self, duration: Duration)

Advance animations by simulated time (for deterministic testing).

An alias of advance_time, not a second door. It was one once, and the two moved disjoint halves of the tree from clocks they each advanced independently: a caller that wanted both had to call both, which advanced simulated time twice, and a caller that wanted one silently froze the other — an animation and the fling it was racing could not be moved to the same instant by any sequence of calls. Kept as a name rather than folded away because it reads correctly at its ~120 call sites, all of which mean “advance the clock”.

Source

pub fn set_theme(&mut self, theme: Theme)

Switch the tree-level theme at runtime.

Updates theme_signal (a reactive Signal<Theme>) and marks all widgets dirty for relayout and repaint. Widgets are not rebuilt: the LayoutContext and PaintContext already resolve the current theme on every pass, and any widget that derives state from theme tokens should do so through a theme_signal() subscription rather than a build-time capture. Preserves focus, scroll offsets, and other interaction state.

Source

pub fn input_density(&self) -> TargetDensity

The TargetDensity the active theme was projected onto.

Source

pub fn set_input_density(&mut self, density: TargetDensity)

Project the active theme onto another density and rebuild the tree.

A rebuild, not Self::set_theme’s mark_all_dirty(): a target size is baked in build() (a MinSize wrapper, a recipe’s Rc<dyn FooStyle>, the number of Toolbar items that fit), and marking layout + paint cannot re-bake it. This reuses the exact path a BindingLevel::Rebuild binding takes — mark_needs_rebuild on each root plus mark_ancestors_need_layout — so the next layout pass drains it through process_rebuilds, which already handles focus restoration, the a11y re-walk and interaction-state revalidation.

A no-op when the density is already the requested one: a density switch throws away every widget id in the tree, so it must not fire on a repeated set.

Source

pub fn set_density_announcement( &mut self, wording: Option<Rc<dyn Fn(TargetDensity) -> String>>, )

Announce density switches to a screen reader, in the application’s own words.

A density switch rebuilds the entire tree, so a screen reader loses its place and the user hears no explanation for it. Registering a wording makes Self::set_input_density speak once — and only once — per real switch, through the same Self::announce path everything else uses.

The wording is the application’s because it cannot be the framework’s: teksilo-i18n depends on this crate, so nothing here can name LocalizedString or reach a translation bundle, and a hardcoded English sentence spoken into a French screen reader is worse than silence. Pass a closure that resolves tr!(…):

tree.set_density_announcement(Some(std::rc::Rc::new(|d| match d {
    TargetDensity::Compact => tr!(layout_compact()).into(),
    TargetDensity::Comfortable => tr!(layout_comfortable()).into(),
    TargetDensity::Spacious => tr!(layout_spacious()).into(),
})));

None — the default — announces nothing.

Source

pub fn set_context_menu_announcement( &mut self, wording: Option<Rc<dyn Fn() -> String>>, )

How to word “a context menu opened” for a screen reader, when the menu was opened by a hold.

The other three routes need nothing: a secondary press, Shift+F10 and the AccessKit ShowContextMenu action are all deliberate, and the menu takes focus, which is announcement enough. A hold is the one route whose user cannot see the menu appear — a finger is on top of where it opens — and which they may not have meant.

The wording is the application’s for the same reason Self::set_density_announcement’s is: teksilo-i18n depends on this crate, so nothing here can name a LocalizedString, and a hardcoded English sentence spoken into a French screen reader is worse than silence.

tree.set_context_menu_announcement(Some(std::rc::Rc::new(|| {
    tr!(context_menu_opened()).into()
})));

None — the default — announces nothing. Where it is set, the announcement is still suppressed if the pressed node’s own subtree already carries a live region — the widget speaking for itself, so the framework does not speak over it — through Self::announce_unless_widget_speaks. The menu’s own subtree is not consulted: it is raised by this very call and has not been walked yet.

Source

pub fn announce_unless_widget_speaks( &mut self, widget: WidgetId, message: impl Into<String>, ) -> bool

Speak message, unless widget already speaks for itself.

A framework announcement that lands beside a widget’s own live region says everything twice — the failure mode crate::announcer warns about for Toast. This is the check that avoids it: if the last accessibility tree carried a live region inside widget’s subtree with text in it, the widget is already talking and this stays quiet. Returns whether the message was queued.

It necessarily reads one tree behind. An announcement is queued during event dispatch; the live-region text it would duplicate is whatever the last built update carried, because the next one has not been built yet. A widget that speaks for the first time in the same dispatch is therefore not yet visible here — which is the right bias: it errs toward saying something rather than toward silence.

Source

pub fn density_policy(&self) -> DensityPolicy

How the active density is chosen. See DensityPolicy.

Source

pub fn set_density_policy(&mut self, policy: DensityPolicy)

Set the density-selection policy.

Storing a Fixed(d) policy does not by itself switch the density — call Self::set_input_density for that. FollowLastPointer is not acted on either: it is state and an accessor, and the field’s own documentation says what is still undecided about honouring it.

Source

pub fn touch_enabled(&self) -> bool

Whether touch input is accepted. See InputTokens::touch_enabled.

Source

pub fn set_touch_enabled(&mut self, enabled: bool)

The runtime touch kill switch. With false, the platform translator drops touch input and the router installs no touch-only recognizers, so an app can fall back to mouse-only behaviour at runtime.

Repaint-level only: turning touch off changes which events are accepted, never a dimension, so nothing is rebuilt or relaid out here. (The translator and router honour it from P08 / P15; this is the state.)

Source

pub fn effective_text_scale(&self) -> f32

The combined effective text scale (user_text_scale * OS text_scale_factor). Read by the layout/paint walkers to populate ctx.text_scale for widgets that size from a source other than Theme.typography.

Source

pub fn text_scale_signal(&self) -> Signal<f32>

Reactive handle on Self::effective_text_scale. Build-time binders that must react to a scale change without their own rebuild path bind this (e.g. Calendar binds it at Rebuild level so its fixed cell constants recompute). Fires on set_user_text_scale / theme / OS-pref change.

Source

pub fn set_user_text_scale(&mut self, factor: f32)

Set the user-controlled global text-scale factor (1.0 = 100 %).

The factor multiplies with the OS accessibility text-scale preference to produce the rendered scale. Recomputes the effective theme and marks all widgets dirty so every text widget grows on the next pass; no rebuild, so focus/scroll/interaction state survive. Values outside [0.25, 8.0] are clamped. Persisted by the application via teksilo_settings::TEXT_SCALE_KEY.

Source

pub fn user_text_scale(&self) -> f32

The current user-controlled text-scale factor (1.0 = 100 %).

Source

pub fn arena_mark_needs_rebuild_for_testing(&mut self, id: WidgetId)

Rebuild a single composite widget: destroy old children, re-run build(), and wire up new children. Called from process_state_changes() when a binding at BindingLevel::Rebuild fires (data-driven rebuild). Theme and locale changes do not rebuild — they update reactive signals that widgets bind to via theme_signal() / locale_signal(). Test-only: force-mark a widget for rebuild on the next layout pass. Lets regression tests exercise the rebuild path without needing to trip a Signal binding. Exposed cross-crate (not #[cfg(test)]-gated) so widget-crate tests in teksilo-widgets and elsewhere can also drive rebuilds; the _for_testing suffix marks it as not intended for application code.

Source

pub fn set_layout_direction(&mut self, direction: LayoutDirection)

Set the layout direction (LTR/RTL). Marks all widgets as needing layout.

Source

pub fn layout_direction(&self) -> LayoutDirection

The current layout direction.

Source

pub fn set_accessibility_preferences( &mut self, high_contrast: bool, reduced_motion: bool, text_scale_factor: f64, )

Set OS-level accessibility preferences.

Called by teksilo-app after querying the platform layer. Updates the values fed into PaintContext and Environment on subsequent frames. Marks all widgets dirty so the new preferences take effect immediately.

Source

pub fn prefers_high_contrast(&self) -> bool

Whether the OS has requested high-contrast mode.

Source

pub fn prefers_reduced_motion(&self) -> bool

Whether the OS has requested reduced motion.

Source

pub fn text_scale_factor(&self) -> f64

OS text scaling factor (1.0 = normal).

Source

pub fn set_screen_reader_state(&mut self, state: ScreenReaderState)

Report whether the operating system says an assistive technology is reading the screen.

Fed by teksilo-app from teksilo_platform::AccessibilityPreferences, which asks Windows for SPI_GETSCREENREADER, AT-SPI for org.a11y.Status.ScreenReaderEnabled, and macOS for NSWorkspace::isVoiceOverEnabled. A platform that cannot answer leaves it ScreenReaderState::Unknown, which behaves as “no”.

Not AccessKit activation. An AccessKit adapter activates for anything that walks the tree — a screen magnifier, a voice-control front end, a UI-automation inspector, a tree browser like Accerciser — none of which want a touch to become a probe. Treating activation as evidence of a screen reader is how explore-by-touch gets switched on under an inspector and makes the app untouchable.

Source

pub fn screen_reader_state(&self) -> ScreenReaderState

The screen-reader state most recently reported by the platform.

ScreenReaderState::Unknown until something reports one.

Source

pub fn set_explore_by_touch(&mut self, mode: ExploreByTouch)

Choose how explore-by-touch is decided for this window.

ExploreByTouch::Off is the default and today’s behaviour; ExploreByTouch::Auto follows Self::screen_reader_state; ExploreByTouch::On forces it regardless. Read the resolved answer with Self::explore_by_touch_active.

Source

pub fn explore_by_touch(&self) -> ExploreByTouch

The explore-by-touch policy most recently set.

Source

pub fn explore_by_touch_active(&self) -> bool

Whether explore-by-touch is in force right now.

On is unconditional; Auto requires the platform to have reported an active screen reader; Off is never in force. Nothing in the framework consumes this yet — the touch-as-probe interaction it gates has no owner — so it is a supply, a policy and a query, and no pointer path branches on it.

Source

pub fn set_at_client_attached(&mut self, attached: bool)

Report whether an AccessKit client is attached to this window.

Written by teksilo-app from the platform adapter’s activation and deactivation handlers, and used asymmetrically on purpose:

  • Attaching proves nothing. Magnifier, Voice Access and a UI-automation inspector all activate the adapter, so this never sets ScreenReaderState::Active.
  • Detaching proves something. When the last client goes away there is no screen reader either, so a truefalse transition forces ScreenReaderState::Inactive and an ExploreByTouch::Auto window stops exploring immediately, without waiting for the next OS query. A later OS query is free to say Active again.
Source

pub fn at_client_attached(&self) -> bool

Whether an AccessKit client is currently attached to this window.

Source

pub fn set_device_scale_factor(&mut self, scale_factor: f32)

Set the host window HiDPI device scale (physical px per logical px). Written by teksilo-app when the window is created and again on WindowEvent::ScaleFactorChanged. Surfaced to widgets via LayoutContext::scale_factor.

Layout needs no dirty-marking here: it rides the layout pass that follows, and a scale change already triggers a relayout. The accessibility tree does, because the scale is the root node’s transform (AccessKit wants physical coordinates, the tree emits logical ones) and a plain relayout does not invalidate the AT cache — so dragging a window between a 1x and a 2x monitor would otherwise leave every reported rectangle at the old display’s scale.

Source

pub fn device_scale_factor(&self) -> f32

The host window HiDPI device scale most recently set (1.0 by default).

Source

pub fn set_safe_area(&mut self, insets: EdgeInsets)

Report the host window’s platform safe-area insets — the region the window owns but a person cannot fully see or touch (a display cutout, a rounded corner, a home indicator).

Fed by teksilo-app from teksilo_platform::safe_area, which reads the window on macOS and answers ZERO everywhere else because no other desktop platform reports one. Overlays clamp into what is left; the root layout proposal is deliberately not shrunk — a safe area moves what floats over the content, not the content.

Source

pub fn safe_area(&self) -> EdgeInsets

The safe-area insets most recently set (ZERO by default).

Source

pub fn set_occluded_inset(&mut self, occluded: Option<Rect>)

Report a rectangle of the window currently covered from outside the tree — a soft keyboard, a platform IME candidate window — in window-logical pixels, or None when nothing covers it.

A rectangle, not a named edge, because that is what a platform reports and because the placement code resolves it by keeping the largest free slab rather than by insetting an edge: a keyboard at the bottom gives the band above it, a candidate window at a side gives the band beside it, and neither needs the platform to say which edge it came from.

Scope: like the safe area, this reaches overlay placement only. The root layout proposal keeps the whole window, so a scroll container still extends behind the keyboard and nothing reflows when one rises — which is what the desktop convention wants, and what keeps a keyboard appearing from being a full relayout of the document. Bringing a focused field out from behind the band is a scroll, against usable_viewport, not a resize.

Source

pub fn occluded_inset(&self) -> Option<Rect>

The occluding rectangle most recently set (None by default).

Source

pub fn usable_viewport(&self) -> Rect

The viewport overlays are placed into: the last laid-out window size, less the safe area, less anything covering it.

The same rectangle position_overlays clamps into, exposed so a consumer that must put something in front of a keyboard — a scroll-into-view for the focused field — can ask for it rather than re-deriving it.

Source

pub fn request_soft_keyboard(&mut self, visible: bool)

Ask the platform to show (true) or hide (false) its on-screen keyboard.

Recorded here rather than pushed straight at the window because the one thing the request must not do is re-assert IME allowance while a composition is live, and the IME-allowance state lives in the app layer’s per-window reconcile. teksilo-app takes the request once per dispatch, after that reconcile, and applies it against the platform’s SoftKeyboardSupport answer.

Source

pub fn take_soft_keyboard_request(&mut self) -> Option<bool>

Take the pending soft-keyboard request, if any. Called by the app layer once per dispatch.

Source

pub fn set_clips_children(&mut self, id: WidgetId, clips: bool)

Mark a widget as clipping its children to its bounds (scroll areas).

Source

pub fn set_alignment(&mut self, id: WidgetId, alignment: Alignment)

Set a per-child alignment override on a widget.

Source

pub fn binding_registry(&self) -> &BindingRegistry

Get the binding registry for registering State→Widget bindings.

Source

pub fn shortcut_registry(&self) -> &ShortcutRegistry

Shared access to the shortcut registry. Widgets register their default shortcuts through here during build() (via BuildContext::register_shortcut); settings UIs and persistence layers read and mutate overrides directly.

Source

pub fn shortcut_registry_mut(&mut self) -> &mut ShortcutRegistry

Source

pub fn begin_key_capture( &mut self, callback: impl FnOnce(KeyStroke, &mut ShortcutRegistry, &mut EventContext<'_>) + 'static, ) -> CaptureHandle

Install a one-shot key-capture callback, returning a CaptureHandle whose Drop cancels the capture if it hasn’t already fired. The next KeyDown the tree receives bypasses shortcut-registry lookup and invokes the callback with:

  • the captured KeyStroke
  • mutable access to the registry (rebind in-place)
  • a mutable EventContext (so the handler can also emit commands, send intents, dismiss overlays, …)

Calling this while a previous capture is armed creates a separate slot; the prior handle, when eventually dropped, cancels only its own (now-orphaned) slot. The new capture wins.

Source

pub fn cancel_key_capture(&mut self)

Cancel any currently-armed key capture without invoking it. Equivalent to dropping the CaptureHandle, but exposed here so callers that lost the handle (or never kept one) can still bail out.

Source

pub fn is_capturing_keys(&self) -> bool

Whether a key-capture callback is currently armed.

Source

pub fn text_surfaces(&self) -> TextSurfaces

A cloneable view of this tree’s text surfaces, for a caller that must ask the question later, without a &WidgetTree in hand.

Source

pub fn focused_text_surface(&self) -> Option<Rc<dyn TextSurface>>

The text-editing widget that currently holds the keyboard focus.

None when focus is elsewhere — or nowhere — which is exactly what a host needs in order to know that a text chord is safe to route itself.

Source

pub fn focused_is_text_surface(&self) -> bool

Is the keyboard focus inside a widget that edits text?

The cheap half of focused_text_surface, for a host that only needs to decide whether to step aside.

Source

pub fn widget_type_histogram(&self) -> HashMap<&'static str, u32>

Histogram of widget concrete-type names across the active arena. Used by the widget.census telemetry emitter to surface “which widgets does this app actually use” data back to the framework. Keyed by std::any::type_name::<T>() of the concrete widget — a dotted, fully-qualified path like teksilo_widgets::button::Button.

&'static str keys: type_name_of_val returns a compile-time string, so the histogram preserves the static lifetime all the way to the wire-format prop. This avoids any allocation for the type-name strings themselves.

Cost: one Box<dyn Widget> indirection per active node plus a HashMap insert. Sub-millisecond on arenas with thousands of widgets. Safe to call every frame in tests; in production gate behind a periodic ticker (hourly or on-idle).

Source

pub fn active_widget_count(&self) -> usize

Number of active widgets in the arena. Cheap; matches the totals returned by widget_type_histogram when summed.

Source

pub fn take_close_window_request(&mut self) -> bool

Drain the “close this window” flag set by EventContext::close_window during dispatch. A guarded close — the app routes it through the window’s close guard.

Source

pub fn take_force_close_request(&mut self) -> bool

Drain the “close this window, no questions asked” flag set by EventContext::close_window_forced during dispatch. An unconditional close that bypasses the window’s close guard.

Source

pub fn take_pending_locale_request(&mut self) -> Option<String>

Drain the pending locale switch raised by EventContext::set_locale during dispatch. The app layer (WindowManager::drain_pending_locale_requests) parses the result and routes it through WindowManager::set_locale so the I18nManager’s active locale, version signal, and layout direction all stay in sync with the tree.

Source

pub fn take_pending_theme_request(&mut self) -> Option<Theme>

Drain the pending theme switch raised by EventContext::set_theme during dispatch. The app layer (WindowManager::drain_pending_theme_requests) routes it through WindowManager::set_theme so the new theme is applied to every window, not just the one whose handler requested it.

Source

pub fn take_pending_follow_system_request(&mut self) -> bool

Drain the pending “follow OS theme” request raised by EventContext::follow_system_theme during dispatch. The app layer (WindowManager::drain_pending_follow_system_requests) switches to ThemeMode::Native and recomputes the theme from the OS for every window. Returns true if a request was pending.

Source

pub fn take_pending_text_scale_request(&mut self) -> Option<f32>

Drain the pending text-scale change raised by EventContext::set_text_scale during dispatch. The app layer (WindowManager::drain_pending_text_scale_requests) routes it through WindowManager::set_text_scale so the new factor is applied to every window, not just the one whose handler requested it.

Source

pub fn drain_pending_modal_requests(&mut self) -> Vec<QueuedModalRequest>

Drain all pending modal requests recorded during event handling.

Each request includes the originating widget so higher layers can resolve routing and focus behavior relative to the source tree.

Source

pub fn drain_pending_modal_dismissal(&mut self) -> bool

Drain whether the current native modal window should be dismissed.

Source

pub fn add(&mut self, widget: impl Widget + 'static) -> WidgetId

Add a widget to the tree.

Source

pub fn add_boxed(&mut self, widget: Box<dyn Widget>) -> WidgetId

Add a pre-boxed widget to the tree.

Source

pub fn widget_accessible_title_node(&self, id: WidgetId) -> Option<WidgetId>

The widget that paints id’s title, when it has one.

See Widget::accessible_title_node.

Source

pub fn add_child( &mut self, parent: WidgetId, widget: impl Widget + 'static, ) -> WidgetId

Add a widget as a child of another widget.

Source

pub fn visible_when(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)

Bind a widget’s visibility to a boolean prop or compatibility state binding. When false, the widget is set dormant; when true, it is activated. Accepts Signal<bool>, Prop<bool>, compatibility state bindings, or plain bool.

Source

pub fn activation_signal(&mut self, id: WidgetId) -> Signal<bool>

Install (or reuse) the activation signal on a node and return a handle to it. The framework sets it to false when the node is parked dormant (Switcher / visible_when) and true when it is re-activated — see crate::arena::WidgetArena::set_dormant / activate. The returned signal is initialised to the node’s current active state. Used by widgets owning a resource outside the paint pass (a native subview) that must hide/show it in lockstep with framework activation.

Source

pub fn widget_target_regions(&self, id: WidgetId) -> Vec<TargetRegion>

The interactive sub-regions the widget at id paints inside its own single node, in absolute arena coordinates.

The read side of Widget::target_regions: a scroll bar’s thumb, a slider’s knob, a header cell’s filter affordance. Empty for the overwhelming majority of widgets, whose node is their target and which therefore have nothing to add.

Reporting only — reading this changes nothing. It exists so a conformance audit, and a test of one, can see geometry that no layout ever produced.

Source

pub fn widget_hit_outset(&self, id: WidgetId, kind: PointerKind) -> EdgeInsets

The hit outset the mounted widget at id declares for kind, against the tree’s live input tokens.

The read side of Widget::hit_outset, and the companion of widget_target_regions: both let a conformance audit — and a test of one — see target geometry that no layout ever produced.

It has to read the mounted node rather than a freshly-built widget, because an outset is usually derived from what the widget painted, and an unmounted one has painted nothing. That is also what makes the gates assertable: a decorative avatar, an inert twist arrow, a disabled swatch and a breadcrumb’s current crumb all take no press, so each must declare EdgeInsets::ZERO — a widened node that then refuses the press is a hole punched in whatever is behind it.

The tokens are the effective theme’s, not theme’s, because that is what the hit path itself reads: hit_test_for_excluding builds its HitContext from effective_theme.input, as do the pointer profile and the touch-enabled gate in pointer_state.rs. The two themes agree only for as long as nothing between them touches inputrecompute_effective_theme currently projects typography alone — and an accessor that describes a path has to read that path’s source rather than one that happens to match it.

Reporting only — reading this changes nothing.

Source

pub fn pressed_signal(&mut self, id: WidgetId) -> Signal<bool>

Install (or reuse) the framework press signal on a node and return a handle to it.

true while the node holds a pointer press whose visual is showing: between press and release, false once the pointer leaves the press’s tap boundary and true again on re-entry, cleared on a cancel or when a peer wins the arbitration. See docs/touch-and-pen.md §7.

Source

pub fn pressed_by(&self, id: WidgetId) -> Option<PointerId>

The contact holding id’s press, whether or not its visual is showing.

None for a node nothing is pressing. A node held by a finger whose press-feedback delay has not elapsed still answers with that finger: the press is real, only its visual is waiting.

Source

pub fn is_pressed(&self, id: WidgetId) -> bool

Whether id’s press visual is showing — held, inside its tap boundary, and past any press-feedback delay. What the node’s pressed_signal mirrors.

Source

pub fn press_is_inside(&self, id: WidgetId) -> bool

Whether id is held and the pointer has not left the press’s tap boundary. True during a press-feedback delay, unlike is_pressed.

Source

pub fn press_pending(&self, id: WidgetId) -> bool

Whether id is held but its press-feedback delay has not elapsed, so the visual is deliberately withheld.

Source

pub fn set_opacity(&mut self, id: WidgetId, opacity: impl Into<Prop<f32>>)

Bind an opacity multiplier (0..1) to a widget. The render walker emits SetOpacity(value) before painting the widget’s subtree and RestoreOpacity afterwards, so the multiplier composes correctly with ancestor opacity scopes via the canvas’s stacked opacity model. Bound at Repaint level: opacity changes never trigger relayout. Pass any Prop<f32> or Signal<f32> source (typically an animated signal driven by a Fade wrapper).

Source

pub fn set_transform( &mut self, id: WidgetId, transform: impl Into<Prop<Transform2D>>, )

Bind a 2D affine transform to a widget. The render walker emits PushTransform(value) before painting the widget’s subtree and PopTransform afterwards; the renderer composes the transform onto its stack so nested wrappers and widget-internal canvas transforms compose correctly. Bound at Repaint level: visual- only transforms never trigger relayout. Wrappers that want the transform’s value change to also drive layout (e.g. Scale::reflow(true)) must additionally bind the driver signal to themselves at Relayout level — the transform prop itself stays at Repaint. Pass a Transform2D, Signal<Transform2D>, or Prop<Transform2D>.

Source

pub fn set_content_transform( &mut self, id: WidgetId, transform: impl Into<Prop<Transform2D>>, )

Like set_transform, but marks the transform as a content transform: it positions the node’s content within a fixed parent-space viewport (the node’s bounds) rather than transforming the node itself. Hit-testing then keeps the whole viewport interactive at any pan / zoom. Used by SceneView; see WidgetNode::content_transform.

Source

pub fn set_blur(&mut self, id: WidgetId, radius: impl Into<Prop<f32>>)

Bind a Gaussian-equivalent blur radius to a widget. The render walker emits BeginBlurredSubtree { bounds, radius } before painting the widget’s subtree and EndBlurredSubtree afterwards; the renderer redirects drawing into an intermediate texture, runs a dual-Kawase blur chain at the requested radius, and composites the blurred result back into the parent pass. Bound at Repaint level: blur radius changes never trigger relayout. Sub-perceptual radii (< 0.5) skip the Begin/End pair entirely so animated enable/disable patterns have zero per-frame cost when fully off. Pass any Prop<f32> or Signal<f32> source.

Source

pub fn enabled_when(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)

Bind a widget’s enabled state to a boolean prop or compatibility state binding. When false, the widget and its entire subtree ignore all events but remain visible. Focus traversal skips disabled subtrees and AccessKit marks their nodes as disabled. Accepts Signal<bool>, Prop<bool>, compatibility state bindings, or plain bool.

The bound signal registers at BindingLevel::SubtreeRepaint: when it flips, the entire subtree rooted at id is marked for repaint (not relayout — geometry doesn’t change). Leaves like IconWidget then re-resolve their role color using the new PaintContext::effective_enabled value, so a disabled subtree’s icons and text dim automatically.

Source

pub fn effective_enabled_signal(&mut self, id: WidgetId) -> Signal<bool>

Reactive view of “is this widget effectively enabled?” — the AND of the widget’s own enabled_state and every ancestor’s. Self::is_enabled is the non-reactive equivalent; this method gives composite widgets a Signal<bool> for derived state.

Leaves (IconWidget, TextWidget, RectWidget) do NOT need this — they receive the resolved bool via crate::widget::PaintContext::effective_enabled at paint time. This method is for composites that want to derive cursor / custom paint roles / etc. reactively.

Install-or-reuse, exactly like Self::activation_signal: the signal lives on the node and the framework refreshes it from the live arena once per state-change pass (flush_effective_enabled_signals).

It is deliberately NOT a signal derived by walking the ancestor chain here. A widget’s parent is still None while its own build() runs — insert_widget inserts the node parentless and wires the parent link only after build() returns — so an ancestor walk performed from inside build() (which is how every caller uses this) sees an empty chain and would capture the widget’s OWN enabled prop as the whole answer, permanently. That was a real bug: a Button inside a disabled form stayed painted as if enabled.

The value is seeded from the live arena and corrected on the next flush, so a first-build() caller (parent not yet wired) and a rebuild caller (parent wired) both converge before anything paints.

Source

pub fn is_enabled(&self, id: WidgetId) -> bool

Whether a widget is effectively enabled. Returns false if the widget itself or any ancestor has enabled_state bound to false.

Source

pub fn set_keyboard_toggle( &mut self, id: WidgetId, f: Rc<dyn Fn(&mut EventContext<'_>)>, )

Bind a widget’s Tab-key participation to a boolean prop or compatibility state binding. When false, the widget is removed from Tab / Shift+Tab traversal (cycle_focus) but remains reachable via request_focus and arrow-key navigation that calls request_focus. Implements the ARIA roving-tabindex pattern (HTML tabindex="-1" semantics). Accepts Signal<bool>, Prop<bool>, or plain bool. Publish what a data view’s Space should do when the row containing id holds the keyboard cursor. See WidgetNode::keyboard_toggle.

Source

pub fn keyboard_toggle_in( &self, root: WidgetId, ) -> Option<Rc<dyn Fn(&mut EventContext<'_>)>>

The first keyboard-toggle action published in root’s subtree, in traversal order.

Searched per keypress rather than cached: a data view rebuilds its rows as they realize, so an id recorded at build time would outlive the widget it named.

Source

pub fn set_tab_stop(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)

Source

pub fn tab_stop(&self, id: WidgetId) -> bool

Current Tab-key participation for a widget. Returns the value of the tab_stop prop if bound, or true (the default) when no binding is present. Mirrors the filter used by cycle_focus — primarily for tests asserting the roving-tabindex contract.

Source

pub fn set_traversal_scope( &mut self, id: WidgetId, policy: TraversalScopePolicy, )

Declare id as a traversal-scope boundary with the given policy. cycle_focus then treats the node’s subtree as an independent Tab group: tab_index values inside it are scoped (they never collide with sibling scopes) and policy governs Tab at the scope’s ends.

The scope node is forced non-focusable — it is a transparent boundary, never itself a Tab stop. Called from BuildContext::set_traversal_scope (which the FocusScope wrapper widget invokes during build), and directly usable from tests with no dependency on the widgets crate.

Source

pub fn clear_traversal_scope(&mut self, id: WidgetId)

Remove a previously set traversal-scope marker from id (rebuild paths where a FocusScope is replaced by a non-scope widget). Leaves node_focusable untouched — a later handler-set application resets it.

Source

pub fn traversal_scope(&self, id: WidgetId) -> Option<TraversalScopePolicy>

Current traversal-scope policy on id, if any. For tests asserting the scope marker contract.

Source

pub fn set_theme_override( &mut self, id: WidgetId, f: impl Fn(&mut Theme) + 'static, )

Set a theme override on a widget. All descendants of this widget will see the modified theme during layout and paint. The override function receives a mutable Theme to modify.

tree.set_theme_override(panel_id, |theme| {
    theme.colors = ColorTokens::dark_default();
});
Source

pub fn resolved_theme(&self, id: WidgetId) -> Theme

Get the resolved theme for a specific widget (applying ancestor overrides).

Trait Implementations§

Source§

impl Default for WidgetTree

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 = !

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.