Skip to main content

Module interaction

Module interaction 

Source
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§

InteractionState
Tracks which widget is hovered and which is pressed, keyed by WidgetId rather than by index or raw coordinates.