Expand description
InteractionState — a single hover/pressed store keyed by
WidgetId.
§Why this exists
Before this type, every primitive that wanted hover/pressed
highlighting grew its own bespoke tracker:
crate::compose::ToolbarHoverTracker for crate::Toolbar,
crate::compose::StatusBarInteraction for crate::StatusBar,
and a handful of examples that inlined two Option<WidgetId>
fields by hand. Each reimplements the same bookkeeping, and each
is scoped to a single primitive even though hover/pressed state
is a generic, per-frame concept that applies to any widget with
an id.
InteractionState is the one generic store: a single instance can
track the hovered/pressed widget across an entire frame’s worth of
primitives — a toolbar, a status bar, a sidebar panel — because
it’s keyed by WidgetId, not tied to one primitive’s layout
type.
§The Backend trait
Every Backend method that took a WidgetId-keyed hover/pressed
pair now has an *_interactive twin that takes one
&InteractionState instead, and the twin is the method each
backend implements:
| positional (deprecated) | implemented |
|---|---|
draw_toolbar(rect, bar, hovered_id, pressed_id) | crate::Backend::draw_toolbar_interactive |
draw_status_bar(rect, bar, hovered_id, pressed_id) | crate::Backend::draw_status_bar_interactive |
draw_sidebar_panel(rect, panel, hovered_toolbar_id, pressed_toolbar_id) | crate::Backend::draw_sidebar_panel_interactive |
The positional names survive as #[deprecated] trait defaults that
rebuild an InteractionState via InteractionState::from_parts
and forward.
§Methods that remain positional
Four Backend methods still take a positional hover argument, keyed
by position within a collection rather than WidgetId:
draw_activity_bar(.., hovered_idx: Option<usize>)draw_tab_bar(.., hovered_close_tab: Option<usize>)draw_data_table(.., hovered_idx: Option<usize>)draw_chart(.., hovered_point: Option<(usize, usize)>)
These would need stable ids for their items before moving into
InteractionState.
§Ownership
Every consumer owns and feeds its own InteractionState instance
by hand inside its own AppLogic::handle. The runner does not hold
a centralized instance.
§Usage
use quadraui::{mouse_moved, InteractionState, WidgetId};
let mut interaction = InteractionState::new();
// On every event, feed it through with a hit-test closure that
// knows how to resolve a screen position to a widget id (built
// from whatever layout the app already computed to paint).
let event = mouse_moved(5.0, 0.0, Default::default());
let hit_test = |x: f32, _y: f32| {
if x < 10.0 {
Some(WidgetId::new("demo:button"))
} else {
None
}
};
if interaction.handle_mouse(&event, hit_test) {
// redraw
}
// At paint time, hand the whole state to the rasteriser — one
// argument, not two positional slots:
// backend.draw_toolbar_interactive(rect, &bar, &interaction);
assert_eq!(interaction.hovered(), Some(&WidgetId::new("demo:button")));examples/common/toolbar_app.rs demonstrates the whole loop
end-to-end against a real backend, and
tests/tui_example_driver.rs’s
toolbar_hover_paints_hover_background_at_the_cursor asserts the
painted consequence.
Structs§
- Interaction
State - Tracks which widget is hovered and which is pressed, keyed by
WidgetIdrather than by index or raw coordinates.