pub struct WidgetTree { /* private fields */ }Implementations§
Source§impl WidgetTree
impl WidgetTree
Sourcepub fn sync_accessibility(&mut self) -> TreeUpdate
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 only rebuilds when layout has changed.
Sourcepub fn dispatch_access_action(
&mut self,
node_id: NodeId,
action: Action,
data: Option<ActionData>,
ops: &mut dyn WindowOps,
) -> bool
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.
Sourcepub fn widget_for_synthetic(&self, node_id: NodeId) -> Option<WidgetId>
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.
pub fn accessibility_node(&self, id: WidgetId) -> AccessibilityInfo
pub fn find_by_role(&self, role: Role) -> Option<WidgetId>
pub fn find_by_label(&self, label: &str) -> Option<WidgetId>
pub fn find_by_action(&self, action: Action) -> Option<WidgetId>
Sourcepub fn text_content(&self, id: WidgetId) -> Option<String>
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.
Sourcepub fn text_value(&self, id: WidgetId) -> Option<String>
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
impl WidgetTree
Sourcepub fn begin_external_drag(
&mut self,
position: Point,
data: ExternalDropData,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn update_external_drag(&mut self, position: Point, ops: &mut dyn WindowOps)
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.
Sourcepub fn end_external_drag(
&mut self,
position: Point,
data: ExternalDropData,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn cancel_external_drag(&mut self, ops: &mut dyn WindowOps)
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.
Sourcepub fn handle_os_drag_ended(
&mut self,
outcome: DropOutcome,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn abort_outbound_drag(&mut self)
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
impl WidgetTree
Sourcepub fn dispatch_event_with_ops(
&mut self,
event: WidgetEvent,
ops: &mut dyn WindowOps,
)
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).
Sourcepub fn dispatch_event(&mut self, event: WidgetEvent)
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.
pub fn hit_test(&self, point: Point) -> Option<WidgetId>
Sourcepub fn hit_test_excluding_overlay_and_widget(
&self,
point: Point,
exclude_overlay: Option<OverlayId>,
exclude_widget: Option<WidgetId>,
) -> Option<WidgetId>
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.
Source§impl WidgetTree
impl WidgetTree
Sourcepub fn focus_with_origin_ops(
&mut self,
id: WidgetId,
origin: FocusOrigin,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn focus_with_origin(&mut self, id: WidgetId, origin: FocusOrigin)
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(...).
Sourcepub fn focus(&mut self, id: WidgetId)
pub fn focus(&mut self, id: WidgetId)
Set focus to a specific widget (programmatic origin, no ops).
Sourcepub fn focus_ops(&mut self, id: WidgetId, ops: &mut dyn WindowOps)
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.
Sourcepub fn ime_context_for_focused(&self) -> Option<ImeContext>
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.
Sourcepub fn first_focusable_descendant(&self, root: WidgetId) -> Option<WidgetId>
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.
Sourcepub fn is_active(&self, id: WidgetId) -> bool
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.
Sourcepub fn widget_initial_focus_hint(&self, id: WidgetId) -> Option<WidgetId>
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.
Sourcepub fn focus_origin(&self) -> Option<FocusOrigin>
pub fn focus_origin(&self) -> Option<FocusOrigin>
How the currently focused widget gained focus.
Sourcepub fn focus_visible_signal(&self) -> Signal<bool>
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.
Sourcepub fn view_focus_active_for(&mut self, node_id: WidgetId) -> Signal<bool>
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.
Sourcepub fn begin_view_focus(&mut self, node_id: WidgetId) -> Signal<bool>
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.
Sourcepub fn end_view_focus(&mut self)
pub fn end_view_focus(&mut self)
Pop the innermost focus scope pushed by begin_view_focus.
Sourcepub fn current_view_focus(&self) -> Option<Signal<bool>>
pub fn current_view_focus(&self) -> Option<Signal<bool>>
The innermost active build-time focus scope, if any.
Source§impl WidgetTree
impl WidgetTree
Sourcepub fn layout(&mut self, proposal: SizeProposal)
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.
Sourcepub fn measure_root_intrinsic(&self, proposal: SizeProposal) -> Option<Size>
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).
Sourcepub fn layout_with_ops(
&mut self,
proposal: SizeProposal,
ops: &mut dyn WindowOps,
)
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
impl WidgetTree
Sourcepub fn attach_tooltip(
&mut self,
anchor_id: WidgetId,
content_id: WidgetId,
delay: Duration,
)
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).
Sourcepub fn attach_tooltip_with_placement(
&mut self,
anchor_id: WidgetId,
content_id: WidgetId,
delay: Duration,
placement: TooltipPlacement,
)
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 TooltipPlacement
— Side for anchors stacked vertically (menu items, a vertical tab
strip, list/tree rows) where Below would cover the next sibling.
Sourcepub fn attach_tooltip_with_sticky(
&mut self,
anchor_id: WidgetId,
content_id: WidgetId,
delay: Duration,
sticky_after: Option<Duration>,
)
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.
Sourcepub 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>>>,
)
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.
Sourcepub 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,
)
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.
pub fn is_descendant_of(&self, widget_id: WidgetId, ancestor: WidgetId) -> bool
Sourcepub fn promote_tooltip_to_sticky(&mut self, content_id: WidgetId)
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_leaveno longer auto-dismisses it, - Swaps the overlay’s dismiss behavior to
EscapeOrClickOutsideso 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.
Sourcepub fn next_timer_deadline(&self) -> Option<Instant>
pub fn next_timer_deadline(&self) -> Option<Instant>
Returns the earliest deadline for a pending tooltip or delayed overlay (if any).
pub fn overlay_manager(&self) -> &OverlayManager
Sourcepub fn overlay_manager_mut(&mut self) -> &mut OverlayManager
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.
pub fn active_overlays(&self) -> Vec<OverlayId>
Sourcepub fn overlay_content_bounds(&self, id: OverlayId) -> Option<Rect>
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.
pub fn show_overlay(&mut self, request: OverlayRequest) -> OverlayId
Sourcepub fn show_overlay_from_source(
&mut self,
source_widget: WidgetId,
request: OverlayRequest,
) -> OverlayId
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.
pub fn show_overlay_for( &mut self, request: OverlayRequest, duration: Duration, ) -> OverlayId
Sourcepub fn dismiss_overlay(&mut self, id: OverlayId)
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.
Sourcepub fn dismiss_overlay_with_ops(
&mut self,
id: OverlayId,
ops: &mut dyn WindowOps,
)
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.
pub fn is_visible(&self, id: WidgetId) -> bool
Source§impl WidgetTree
impl WidgetTree
pub fn bounds(&self, id: WidgetId) -> Rect
Sourcepub fn last_pointer_position(&self) -> Option<Point>
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.
Sourcepub fn widget_as_any(&self, id: WidgetId) -> Option<&dyn Any>
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.
Sourcepub fn widget_as_any_mut(&mut self, id: WidgetId) -> Option<&mut dyn Any>
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).
pub fn children(&self, id: WidgetId) -> Vec<WidgetId>
Sourcepub fn roots(&self) -> Vec<WidgetId>
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.
Sourcepub fn widget_type_name(&self, id: WidgetId) -> Option<&'static str>
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.
Sourcepub fn widget_debug_string(&self, id: WidgetId) -> Option<String>
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.
Sourcepub fn widget_clips_children(&self, id: WidgetId) -> bool
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.
Sourcepub fn last_proposal(&self) -> SizeProposal
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.
Sourcepub fn at_version(&self) -> &Signal<u64>
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.
Sourcepub fn announcements_since(&self, seq: u64) -> Vec<Announcement>
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.
Sourcepub fn parent(&self, id: WidgetId) -> Option<WidgetId>
pub fn parent(&self, id: WidgetId) -> Option<WidgetId>
Parent widget id in the arena graph, or None for roots.
pub fn needs_layout(&self) -> bool
pub fn needs_paint(&self) -> bool
pub fn active_animation_count(&self) -> usize
pub fn pending_tooltip_count(&self) -> usize
Sourcepub fn has_idle_work(&self) -> bool
pub fn has_idle_work(&self) -> bool
Whether there are pending idle callbacks to run.
pub fn has_pending_modal_requests(&self) -> bool
pub fn has_pending_modal_dismissal(&self) -> bool
pub fn current_cursor(&self) -> CursorIcon
Sourcepub fn hovered(&self) -> Option<WidgetId>
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).
Sourcepub fn hovered_signal(&self) -> Signal<Option<WidgetId>>
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).
Sourcepub fn focused_signal(&self) -> Signal<Option<WidgetId>>
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.
Sourcepub fn run_idle_callbacks(&mut self, budget: Duration)
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
impl WidgetTree
Sourcepub fn render(&mut self) -> Rc<RenderFrame>
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.
Sourcepub fn render_with_ops(&mut self, ops: &mut dyn WindowOps) -> Rc<RenderFrame>
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
impl WidgetTree
Sourcepub fn tooltip_content_within(&self, widget: WidgetId) -> Option<WidgetId>
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.
Sourcepub fn tooltip_is_sticky_within(&self, widget: WidgetId) -> bool
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.
Sourcepub fn synthesise_tap(&mut self, id: WidgetId)
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.
Sourcepub fn synthesise_tap_with_ops(&mut self, id: WidgetId, ops: &mut dyn WindowOps)
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.
Sourcepub fn pointer_move(&mut self, position: Point)
pub fn pointer_move(&mut self, position: Point)
Simulate pointer movement to a position.
Sourcepub fn press_key(&mut self, key: Key, modifiers: Modifiers)
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.
Sourcepub fn type_text(&mut self, _widget: WidgetId, text: &str)
pub fn type_text(&mut self, _widget: WidgetId, text: &str)
Simulate typing text into the focused widget.
Simulate a pointer down at a specific position with a specific button.
Simulate a pointer up at a specific position with a specific button.
Sourcepub fn armed_drag_observers(&self) -> &[WidgetId]
pub fn armed_drag_observers(&self) -> &[WidgetId]
The draggable ancestors armed by the current pointer press — the
observable state of the cross-widget tap-vs-drag disambiguation (see
arm_drag_observers).
Empty when the press landed inside a
gesture_dead_zone, or when
the pressed widget carries its own drag (the innermost drag owns the
gesture). Exposed so an app built on teksilo can assert the same thing
this crate’s own gesture_dead_zone_blocks_ancestor_drag_arming asserts —
that a press on an interactive control inside a draggable container cannot
start the container’s drag. Read-only; test support.
Sourcepub fn child_bounds(&self, parent: WidgetId, index: usize) -> Rect
pub fn child_bounds(&self, parent: WidgetId, index: usize) -> Rect
Get bounds of a child by index.
Sourcepub fn child_widget(&self, parent: WidgetId, index: usize) -> WidgetId
pub fn child_widget(&self, parent: WidgetId, index: usize) -> WidgetId
Get a child widget ID by index.
Sourcepub fn advance_time(&mut self, duration: Duration)
pub fn advance_time(&mut self, duration: Duration)
Advance the simulated clock by the given duration. Triggers time-dependent behavior such as long-press gesture recognition and tooltip timers. Enables deterministic testing without real delays.
Sourcepub fn simulated_now(&self) -> Instant
pub fn simulated_now(&self) -> Instant
Get the current simulated clock value.
Sourcepub fn tooltip_entry_count(&self) -> usize
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.
Sourcepub fn widget_count(&self) -> usize
pub fn widget_count(&self) -> usize
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.
Sourcepub fn destroy_subtree_for_testing(&mut self, id: WidgetId)
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.
Sourcepub fn mark_needs_paint(&mut self, id: WidgetId)
pub fn mark_needs_paint(&mut self, id: WidgetId)
Mark a widget as needing repaint.
Sourcepub fn set_dormant(&mut self, id: WidgetId)
pub fn set_dormant(&mut self, id: WidgetId)
Set a widget subtree as dormant.
Sourcepub fn invalidate_all_paints(&mut self)
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
impl WidgetTree
pub fn new() -> Self
Sourcepub fn run_with_event_context<F>(&mut self, ops: &mut dyn WindowOps, f: F)where
F: FnOnce(&mut EventContext<'_>),
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).
Sourcepub fn has_pending_mount_actions(&self) -> bool
pub fn has_pending_mount_actions(&self) -> bool
Whether any post-mount actions are waiting to run.
Sourcepub fn run_mount_actions(&mut self, ops: &mut dyn WindowOps)
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.
Sourcepub fn set_window_state(&mut self, state: WindowState)
pub fn set_window_state(&mut self, state: WindowState)
Attach the WindowState for this
tree’s hosting window. Called by WindowManager::create_window.
pub fn window_state(&self) -> Option<&WindowState>
Sourcepub fn frame_request_handle(&self) -> Rc<Cell<bool>>
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).
Sourcepub fn wake_at_handle(&self) -> Rc<Cell<Option<Instant>>>
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.
Sourcepub fn request_wake_at(&self, at: Instant)
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.
Sourcepub fn frame_tick(&self) -> Signal<f32>
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.
Sourcepub fn request_frame(&self)
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.
Sourcepub fn request_accessibility_update(&self)
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.
Sourcepub fn a11y_request_handle(&self) -> Rc<Cell<bool>>
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.
Sourcepub fn frame_requested(&self) -> bool
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.
Sourcepub fn frame_tick_deadline(&self) -> Option<Instant>
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.
Sourcepub fn subscribe_frame_tick(&self, owner: WidgetId) -> FrameTickSubscription
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.
Sourcepub fn subscribe_frame_tick_throttled(
&self,
owner: WidgetId,
interval: Duration,
) -> FrameTickSubscription
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.
Sourcepub fn set_app_context(&mut self, app_context: Rc<TreeAppContext>)
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.
Sourcepub fn app_context(&self) -> &Rc<TreeAppContext>
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.
Sourcepub fn set_locale(&mut self, locale: String)
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().
Sourcepub fn locale_signal(&self) -> &Signal<Option<String>>
pub fn locale_signal(&self) -> &Signal<Option<String>>
Reactive handle on the current locale. Mirrors locale() but updates
observers when set_locale is called.
pub fn with_theme(self, theme: Theme) -> Self
pub fn with_text_backend(self, backend: Rc<RefCell<dyn TextBackend>>) -> Self
Sourcepub fn with_title_bar_host(self, host: Rc<dyn PlatformTitleBarHost>) -> Self
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.
pub fn set_title_bar_host(&mut self, host: Rc<dyn PlatformTitleBarHost>)
Sourcepub fn title_bar_host(&self) -> Option<Rc<dyn PlatformTitleBarHost>>
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).
pub fn theme(&self) -> &Theme
Sourcepub fn theme_signal(&self) -> &Signal<Theme>
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(...).
Sourcepub fn needs_redraw(&self) -> bool
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.
Sourcepub fn needs_render(&self) -> bool
pub fn needs_render(&self) -> bool
Whether a render pass is needed (any widget needs layout or paint).
Sourcepub fn needs_reconcile(&self) -> bool
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_atand the 60 Hz frame tick are all timing driven, and every one of them contributes tonext_timer_deadline— whichrequest_redraw_duepolls to wake precisely the due windows; - drag ticks follow that window’s own pointer stream;
- a handler that called
request_rebuildmarked the arena directly, soneeds_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.
Sourcepub fn register_animated_signal(
&mut self,
signal: &Signal<f32>,
owner: WidgetId,
)
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.
Sourcepub fn has_active_animations(&self) -> bool
pub fn has_active_animations(&self) -> bool
Whether any animation is currently running.
Sourcepub fn mark_all_needs_paint_only(&mut self)
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.
Sourcepub fn set_window_active(&mut self, active: bool)
pub fn set_window_active(&mut self, active: bool)
strictly lighter than set_theme’s mark_all_dirty (layout + paint).
Sourcepub fn is_window_active(&self) -> bool
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.
Sourcepub fn window_active_signal(&self) -> Signal<bool>
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.
Sourcepub fn register_animated_quad(
&mut self,
owner: WidgetId,
kind: AnimatedQuadKind,
) -> AnimatedQuadHandle
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.
Sourcepub fn animated_quad_count(&self) -> usize
pub fn animated_quad_count(&self) -> usize
Active animated-quad slot count. Test / debug helper.
Sourcepub fn tick_gestures(&mut self, now: Instant)
pub fn tick_gestures(&mut self, now: Instant)
Advance time-driven gesture recognizers (currently only
crate::gesture::LongPressRecognizer) across every widget that
has a gesture arena. Must be called by the event loop on each
wake-up; otherwise long-press will never fire during an idle hold.
When a recognizer transitions to Recognized, the corresponding
handler on the owning widget is invoked with a fresh
EventContext, and any commands / overlay requests it emits are
collected through the normal post-event path.
Sourcepub fn tick_gestures_with_ops(&mut self, now: Instant, ops: &mut dyn WindowOps)
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.
Sourcepub fn next_gesture_deadline(&self) -> Option<Instant>
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.
Sourcepub fn tick_animations(&mut self, duration: Duration)
pub fn tick_animations(&mut self, duration: Duration)
Advance animations by simulated time (for deterministic testing).
Pending animate_to requests are started at the current sim_clock,
then time advances by duration, and the scheduler ticks at the new time.
Sourcepub fn set_theme(&mut self, theme: Theme)
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.
Sourcepub fn effective_text_scale(&self) -> f32
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.
Sourcepub fn text_scale_signal(&self) -> Signal<f32>
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.
Sourcepub fn set_user_text_scale(&mut self, factor: f32)
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.
Sourcepub fn user_text_scale(&self) -> f32
pub fn user_text_scale(&self) -> f32
The current user-controlled text-scale factor (1.0 = 100 %).
Sourcepub fn arena_mark_needs_rebuild_for_testing(&mut self, id: WidgetId)
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.
Sourcepub fn set_layout_direction(&mut self, direction: LayoutDirection)
pub fn set_layout_direction(&mut self, direction: LayoutDirection)
Set the layout direction (LTR/RTL). Marks all widgets as needing layout.
Sourcepub fn layout_direction(&self) -> LayoutDirection
pub fn layout_direction(&self) -> LayoutDirection
The current layout direction.
Sourcepub fn set_accessibility_preferences(
&mut self,
high_contrast: bool,
reduced_motion: bool,
text_scale_factor: f64,
)
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.
Sourcepub fn prefers_high_contrast(&self) -> bool
pub fn prefers_high_contrast(&self) -> bool
Whether the OS has requested high-contrast mode.
Sourcepub fn prefers_reduced_motion(&self) -> bool
pub fn prefers_reduced_motion(&self) -> bool
Whether the OS has requested reduced motion.
Sourcepub fn text_scale_factor(&self) -> f64
pub fn text_scale_factor(&self) -> f64
OS text scaling factor (1.0 = normal).
Sourcepub fn set_device_scale_factor(&mut self, scale_factor: f32)
pub fn set_device_scale_factor(&mut self, scale_factor: f32)
Set the host window HiDPI device scale (physical px per logical px).
Called by teksilo-app before each layout from
platform_window.scale_factor(). Surfaced to widgets via
LayoutContext::scale_factor. No dirty-marking: it rides the layout
pass that follows, and a scale change already triggers a relayout.
Sourcepub fn device_scale_factor(&self) -> f32
pub fn device_scale_factor(&self) -> f32
The host window HiDPI device scale most recently set (1.0 by default).
Sourcepub fn set_clips_children(&mut self, id: WidgetId, clips: bool)
pub fn set_clips_children(&mut self, id: WidgetId, clips: bool)
Mark a widget as clipping its children to its bounds (scroll areas).
Sourcepub fn set_alignment(&mut self, id: WidgetId, alignment: Alignment)
pub fn set_alignment(&mut self, id: WidgetId, alignment: Alignment)
Set a per-child alignment override on a widget.
Sourcepub fn binding_registry(&self) -> &BindingRegistry
pub fn binding_registry(&self) -> &BindingRegistry
Get the binding registry for registering State→Widget bindings.
Sourcepub fn shortcut_registry(&self) -> &ShortcutRegistry
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.
pub fn shortcut_registry_mut(&mut self) -> &mut ShortcutRegistry
Sourcepub fn begin_key_capture(
&mut self,
callback: impl FnOnce(KeyStroke, &mut ShortcutRegistry, &mut EventContext<'_>) + 'static,
) -> CaptureHandle
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.
Sourcepub fn cancel_key_capture(&mut self)
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.
Sourcepub fn is_capturing_keys(&self) -> bool
pub fn is_capturing_keys(&self) -> bool
Whether a key-capture callback is currently armed.
Sourcepub fn text_surfaces(&self) -> TextSurfaces
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.
Sourcepub fn focused_text_surface(&self) -> Option<Rc<dyn TextSurface>>
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.
Sourcepub fn focused_is_text_surface(&self) -> bool
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.
Sourcepub fn widget_type_histogram(&self) -> HashMap<&'static str, u32>
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).
Sourcepub fn active_widget_count(&self) -> usize
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.
Sourcepub fn take_close_window_request(&mut self) -> bool
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.
Sourcepub fn take_force_close_request(&mut self) -> bool
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.
Sourcepub fn take_pending_locale_request(&mut self) -> Option<String>
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.
Sourcepub fn take_pending_theme_request(&mut self) -> Option<Theme>
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.
Sourcepub fn take_pending_follow_system_request(&mut self) -> bool
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.
Sourcepub fn take_pending_text_scale_request(&mut self) -> Option<f32>
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.
Sourcepub fn drain_pending_modal_requests(&mut self) -> Vec<QueuedModalRequest>
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.
Sourcepub fn drain_pending_modal_dismissal(&mut self) -> bool
pub fn drain_pending_modal_dismissal(&mut self) -> bool
Drain whether the current native modal window should be dismissed.
Sourcepub fn add_boxed(&mut self, widget: Box<dyn Widget>) -> WidgetId
pub fn add_boxed(&mut self, widget: Box<dyn Widget>) -> WidgetId
Add a pre-boxed widget to the tree.
Sourcepub fn add_child(
&mut self,
parent: WidgetId,
widget: impl Widget + 'static,
) -> WidgetId
pub fn add_child( &mut self, parent: WidgetId, widget: impl Widget + 'static, ) -> WidgetId
Add a widget as a child of another widget.
Sourcepub fn visible_when(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)
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.
Sourcepub fn activation_signal(&mut self, id: WidgetId) -> Signal<bool>
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.
Sourcepub fn set_opacity(&mut self, id: WidgetId, opacity: impl Into<Prop<f32>>)
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).
Sourcepub fn set_transform(
&mut self,
id: WidgetId,
transform: impl Into<Prop<Transform2D>>,
)
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>.
Sourcepub fn set_content_transform(
&mut self,
id: WidgetId,
transform: impl Into<Prop<Transform2D>>,
)
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.
Sourcepub fn set_blur(&mut self, id: WidgetId, radius: impl Into<Prop<f32>>)
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.
Sourcepub fn enabled_when(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)
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.
Sourcepub fn effective_enabled_signal(&mut self, id: WidgetId) -> Signal<bool>
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.
Sourcepub fn is_enabled(&self, id: WidgetId) -> bool
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.
Sourcepub fn set_tab_stop(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)
pub fn set_tab_stop(&mut self, id: WidgetId, state: impl Into<Prop<bool>>)
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.
Sourcepub fn tab_stop(&self, id: WidgetId) -> bool
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.
Sourcepub fn set_traversal_scope(
&mut self,
id: WidgetId,
policy: TraversalScopePolicy,
)
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.
Sourcepub fn clear_traversal_scope(&mut self, id: WidgetId)
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.
Sourcepub fn traversal_scope(&self, id: WidgetId) -> Option<TraversalScopePolicy>
pub fn traversal_scope(&self, id: WidgetId) -> Option<TraversalScopePolicy>
Current traversal-scope policy on id, if any. For tests asserting
the scope marker contract.
Sourcepub fn set_theme_override(
&mut self,
id: WidgetId,
f: impl Fn(&mut Theme) + 'static,
)
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();
});Sourcepub fn resolved_theme(&self, id: WidgetId) -> Theme
pub fn resolved_theme(&self, id: WidgetId) -> Theme
Get the resolved theme for a specific widget (applying ancestor overrides).