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 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.
Sourcepub fn a11y_walk_generation(&self) -> u64
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.
Sourcepub fn accessibility_tree_snapshot(&self) -> TreeUpdate
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.
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.
§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.
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 abort_external_drag(&mut self, ops: &mut dyn WindowOps)
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.
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 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_in_band(
&mut self,
request: OverlayRequest,
band: OverlayBand,
) -> OverlayId
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.
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
Sourcepub fn start_fling(
&mut self,
target: WidgetId,
velocity: Vec2,
chain: Vec<(WidgetId, PanClaim)>,
)
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.
Sourcepub fn stop_fling(&mut self, target: WidgetId)
pub fn stop_fling(&mut self, target: WidgetId)
Stop target’s coast, if it has one. Idempotent.
Sourcepub fn is_flinging(&self, target: WidgetId) -> bool
pub fn is_flinging(&self, target: WidgetId) -> bool
Whether target is coasting.
Sourcepub fn tick_flings(&mut self, now: Instant)
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.
Sourcepub fn tick_flings_with_ops(&mut self, now: Instant, ops: &mut dyn WindowOps)
pub fn tick_flings_with_ops(&mut self, now: Instant, ops: &mut dyn WindowOps)
tick_flings with the caller’s
WindowOps sink.
Sourcepub fn dispatch_os_gesture(
&mut self,
gesture: GestureEvent,
at: Option<Point>,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn touch_pinch_active(&self) -> bool
pub fn touch_pinch_active(&self) -> bool
Whether a two-contact pinch is in progress.
Sourcepub fn set_backend_reports_palm(&mut self, reports: bool)
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.
Sourcepub fn palm_fallback_active(&self) -> bool
pub fn palm_fallback_active(&self) -> bool
Whether the palm fallback is running.
Sourcepub fn next_input_deadline(&self) -> Option<Instant>
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
impl WidgetTree
Sourcepub fn cancel_pointer(
&mut self,
pointer: PointerId,
reason: CancelReason,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn cancel_pointer_to(
&mut self,
pointer: PointerId,
reason: CancelReason,
recipient: Option<WidgetId>,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn cancel_all_pointers(
&mut self,
reason: CancelReason,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn cancel_pointers_in_subtree(
&mut self,
root: WidgetId,
reason: CancelReason,
ops: &mut dyn WindowOps,
)
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
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.
Sourcepub fn dispatch_pointer(&mut self, sample: PointerSample)
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.
Sourcepub fn dispatch_pointer_with_ops(
&mut self,
sample: PointerSample,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn dispatch_scroll(&mut self, sample: ScrollSample)
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.
Sourcepub fn dispatch_scroll_with_ops(
&mut self,
sample: ScrollSample,
ops: &mut dyn WindowOps,
)
pub fn dispatch_scroll_with_ops( &mut self, sample: ScrollSample, ops: &mut dyn WindowOps, )
dispatch_scroll with the caller’s app-level
WindowOps sink.
Sourcepub fn pointer_left_window(&mut self, ops: &mut dyn WindowOps)
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.
Sourcepub fn hit_test(&self, point: Point) -> Option<WidgetId>
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.
Sourcepub fn hit_test_for(
&self,
point: Point,
pointer: &PointerInfo,
) -> Option<WidgetId>
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.
Sourcepub fn hit_test_for_excluding(
&self,
point: Point,
pointer: &PointerInfo,
exclude_overlay: Option<OverlayId>,
exclude_widget: Option<WidgetId>,
) -> Option<WidgetId>
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.
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.
Mouse, exact — the pointer-aware twin is
hit_test_for_excluding.
Source§impl WidgetTree
impl WidgetTree
Sourcepub fn input_clock(&self) -> Rc<dyn InputClock>
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.
Sourcepub fn set_input_clock(&mut self, clock: Rc<dyn InputClock>)
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.
Sourcepub fn resume_real_time(&mut self)
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.
Sourcepub fn input_now(&self) -> EventTime
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.
Sourcepub fn sequence_winner(&self, pointer: PointerId) -> Option<WidgetId>
pub fn sequence_winner(&self, pointer: PointerId) -> Option<WidgetId>
The winner of pointer’s sequence, if one has been decided.
Sourcepub fn sequence_members(
&self,
pointer: PointerId,
) -> Vec<(WidgetId, MemberRole, MemberState)>
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.
Sourcepub fn sequence_touch_action(&self, pointer: PointerId) -> TouchAction
pub fn sequence_touch_action(&self, pointer: PointerId) -> TouchAction
The TouchAction frozen for pointer’s press.
pub fn tick_gestures(&mut self, now: Instant)
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.
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 pointer_position(&self, pointer: PointerId) -> Option<Point>
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.
Sourcepub fn captured_by(&self, pointer: PointerId) -> Option<WidgetId>
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.
Sourcepub fn pointer_captured_by(&self) -> Option<WidgetId>
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.
Sourcepub fn live_pointers(&self) -> impl Iterator<Item = PointerInfo> + '_
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.
Sourcepub fn primary_pointer(&self) -> Option<PointerInfo>
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.
Sourcepub fn hover_owner(&self) -> Option<PointerInfo>
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.
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_for(&self, pointer: PointerId) -> Option<WidgetId>
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.
Sourcepub fn has_pending_dispatch(&self) -> bool
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.
Sourcepub fn last_pointer_kind_signal(&self) -> Signal<PointerKind>
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.
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 const FLING_SAMPLE_INTERVAL: Duration
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.
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 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 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 fromrender()and has no simulated door at all. - A deferred member’s
eligible_aton aPointerSequence. 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 itslong_pressis already eligible on its very next move. SeePointerSequence::next_hold_deadline. A hold’smax_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.
Sourcepub fn advance_time_with_ops(
&mut self,
duration: Duration,
ops: &mut dyn WindowOps,
)
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.
Sourcepub fn advance_input_time(&mut self, duration: Duration)
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.
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 tab_stops_within(&self, root: WidgetId) -> Vec<WidgetId>
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.
pub fn widget_count(&self) -> usize
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 assert_no_leaked_pointer_state(&self)
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.
Sourcepub fn new_contact(&self) -> PointerId
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.
Sourcepub fn touch_down(&mut self, pointer: PointerId, at: Point)
pub fn touch_down(&mut self, pointer: PointerId, at: Point)
A finger lands at at.
Sourcepub fn touch_move(&mut self, pointer: PointerId, at: Point)
pub fn touch_move(&mut self, pointer: PointerId, at: Point)
That finger moves to at, still down.
Sourcepub fn touch_cancel(&mut self, pointer: PointerId, at: Point)
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.
Sourcepub fn pen_down(&mut self, at: Point, pressure: f32, tilt: (f32, f32))
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.
Sourcepub fn pen_move(&mut self, at: Point, pressure: f32, tilt: (f32, f32))
pub fn pen_move(&mut self, at: Point, pressure: f32, tilt: (f32, f32))
The stylus draws to at, still on the surface.
Sourcepub fn pen_up(&mut self, at: Point, pressure: f32, tilt: (f32, f32))
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.
Sourcepub fn pen_hover(&mut self, at: Point)
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.
Sourcepub fn tap_with(&mut self, kind: PointerKind, at: Point) -> PointerId
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.
Sourcepub fn long_press_at(&mut self, kind: PointerKind, at: Point) -> PointerId
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.
Sourcepub fn touch_drag(&mut self, from: Point, to: Point, steps: usize) -> PointerId
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.
Sourcepub fn fling(&mut self, from: Point, to: Point, over: Duration) -> PointerId
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.
Sourcepub fn pinch(
&mut self,
a0: Point,
b0: Point,
a1: Point,
b1: Point,
steps: usize,
) -> (PointerId, PointerId)
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.
Sourcepub fn set_density(&mut self, density: TargetDensity)
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.
Sourcepub fn touch_action_for(&self, id: WidgetId) -> TouchAction
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.
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.
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.
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 announce(&mut self, message: impl Into<String>)
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.
Sourcepub fn announce_with(
&mut self,
message: impl Into<String>,
politeness: Politeness,
)
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.
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 set_window_active_with_ops(
&mut self,
active: bool,
ops: &mut dyn WindowOps,
)
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.
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_animations(&mut self, duration: Duration)
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”.
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 input_density(&self) -> TargetDensity
pub fn input_density(&self) -> TargetDensity
The TargetDensity the active theme was projected onto.
Sourcepub fn set_input_density(&mut self, density: TargetDensity)
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.
Sourcepub fn set_density_announcement(
&mut self,
wording: Option<Rc<dyn Fn(TargetDensity) -> String>>,
)
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.
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.
Sourcepub fn announce_unless_widget_speaks(
&mut self,
widget: WidgetId,
message: impl Into<String>,
) -> bool
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.
Sourcepub fn density_policy(&self) -> DensityPolicy
pub fn density_policy(&self) -> DensityPolicy
How the active density is chosen. See DensityPolicy.
Sourcepub fn set_density_policy(&mut self, policy: DensityPolicy)
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.
Sourcepub fn touch_enabled(&self) -> bool
pub fn touch_enabled(&self) -> bool
Whether touch input is accepted. See
InputTokens::touch_enabled.
Sourcepub fn set_touch_enabled(&mut self, enabled: bool)
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.)
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_screen_reader_state(&mut self, state: ScreenReaderState)
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.
Sourcepub fn screen_reader_state(&self) -> ScreenReaderState
pub fn screen_reader_state(&self) -> ScreenReaderState
The screen-reader state most recently reported by the platform.
ScreenReaderState::Unknown until something reports one.
Sourcepub fn set_explore_by_touch(&mut self, mode: ExploreByTouch)
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.
Sourcepub fn explore_by_touch(&self) -> ExploreByTouch
pub fn explore_by_touch(&self) -> ExploreByTouch
The explore-by-touch policy most recently set.
Sourcepub fn explore_by_touch_active(&self) -> bool
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.
Sourcepub fn set_at_client_attached(&mut self, attached: bool)
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
true→falsetransition forcesScreenReaderState::Inactiveand anExploreByTouch::Autowindow stops exploring immediately, without waiting for the next OS query. A later OS query is free to sayActiveagain.
Sourcepub fn at_client_attached(&self) -> bool
pub fn at_client_attached(&self) -> bool
Whether an AccessKit client is currently attached to this window.
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).
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.
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_safe_area(&mut self, insets: EdgeInsets)
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.
Sourcepub fn safe_area(&self) -> EdgeInsets
pub fn safe_area(&self) -> EdgeInsets
The safe-area insets most recently set (ZERO by default).
Sourcepub fn set_occluded_inset(&mut self, occluded: Option<Rect>)
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.
Sourcepub fn occluded_inset(&self) -> Option<Rect>
pub fn occluded_inset(&self) -> Option<Rect>
The occluding rectangle most recently set (None by default).
Sourcepub fn usable_viewport(&self) -> Rect
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.
Sourcepub fn request_soft_keyboard(&mut self, visible: bool)
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.
Sourcepub fn take_soft_keyboard_request(&mut self) -> Option<bool>
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.
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 widget_accessible_title_node(&self, id: WidgetId) -> Option<WidgetId>
pub fn widget_accessible_title_node(&self, id: WidgetId) -> Option<WidgetId>
The widget that paints id’s title, when it has one.
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 widget_target_regions(&self, id: WidgetId) -> Vec<TargetRegion>
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.
Sourcepub fn widget_hit_outset(&self, id: WidgetId, kind: PointerKind) -> EdgeInsets
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 input — recompute_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.
Sourcepub fn pressed_signal(&mut self, id: WidgetId) -> Signal<bool>
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.
Sourcepub fn pressed_by(&self, id: WidgetId) -> Option<PointerId>
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.
Sourcepub fn is_pressed(&self, id: WidgetId) -> bool
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.
Sourcepub fn press_is_inside(&self, id: WidgetId) -> bool
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.
Sourcepub fn press_pending(&self, id: WidgetId) -> bool
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.
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_keyboard_toggle(
&mut self,
id: WidgetId,
f: Rc<dyn Fn(&mut EventContext<'_>)>,
)
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.
Sourcepub fn keyboard_toggle_in(
&self,
root: WidgetId,
) -> Option<Rc<dyn Fn(&mut EventContext<'_>)>>
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.
pub fn set_tab_stop(&mut self, id: WidgetId, state: impl Into<Prop<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).