The ratatui
library for building terminal apps has a widget for rendering rectangles on screen called Block
. https://docs.rs/ratatui/latest/ratatui/widgets/block/struct.Block.html.
I would like to detect mouse click events on a Block when using ratatui with crossterm, i.e. invoke a callback when a click falls anywhere within the bounds of the block. I'm aware that this functionality isn't natively provided "out of the box" by either library, so I'm mostly asking
Because ratatui
is an immediate-mode rendering framework, the most natural way to do this is to detect mouse events in render()
and pass the events as a parameter to your widgets during the render loop:
pub struct MyWidget {
pub event: Option<MouseEvent>
}
Then in the implementation of your widget, you can check whether the event falls within the bounds that you're drawing:
impl Widget for MyWidget {
fn render(self, area: Rect, buf: &mut Buffer) {
let Block = Block::default();
let target = block.inner(area);
if self.event.kind == MouseEventKind::Up(MouseButton::Left) &&
target.contains(Position::new(self.event.column, self.event.row)) {
// Handle click event
}
block.render(area, buf);
}
}
Unlike with a traditional retained-mode UI framework, it's standard to combine event handling code inline with drawing code in this manner.