pub trait InteractiveWidget<Id> {
type State;
// Required methods
fn sense(&self) -> Sense;
fn render(
&self,
surface: &mut Surface<'_>,
state: &mut Self::State,
response: Response<Id>,
);
}Expand description
A widget that renders itself styled by an already-resolved Response, with the Sense
it needs fixed by the widget rather than chosen at the call site.
A composite widget like Button, Scrollbar, List, or Tabs needs to know what
happened to it this frame (hovered, pressed, clicked, dragged) to pick its style and resolve
its own hit-testing, but never calls
Interaction::interact itself: doing so would let it register
the wrong rect, or let a call site register it with a Sense its presentation doesn’t
match (a click handler drawn without ever showing a hover state, say). sense
fixes what the widget needs so a call site can’t get that pairing wrong, and
render takes the resulting Response as a plain argument rather than
calling interact itself: the widget never receives an
Interaction, and has no Id type parameter, so it can’t call
interact with the wrong rect because it has nothing to call interact on.
type State covers widgets with no state (Button, Tabs: ()), a scroll position
(Scrollbar: ScrollState), or a selection/scroll index (List:
ListState), the same Widget/StatefulWidget split applied to
interactive widgets rather than a separate InteractiveStatefulWidget trait.
Has no generic method, so dyn InteractiveWidget<Id, State = ()> is object-safe,
e.g. a Vec<Box<dyn InteractiveWidget<Id, State = ()>>> of heterogeneous stateless widgets.
Id is the trait’s own type parameter (not a generic method) precisely so that stays true.
§Examples
use retroglyph_core::color::Style;
use retroglyph_core::grid::{Grid, Rect};
use retroglyph_ui::{InteractiveWidget, Response, Sense, Surface};
struct Marker(char);
impl<Id> InteractiveWidget<Id> for Marker {
type State = ();
fn sense(&self) -> Sense {
Sense::click()
}
fn render(&self, surface: &mut Surface<'_>, _state: &mut Self::State, response: Response<Id>) {
let style = if response.hovered() { Style::new().bg(retroglyph_core::color::Color::RED) } else { Style::new() };
surface.put((0, 0), self.0, style);
}
}