mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-26 20:40:44 +00:00
docs: add mouse-drawing example (#1546)
Demonstrates how to handle mouse events
This commit is contained in:
parent
9275d3421c
commit
ed071f3723
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -1561,6 +1561,15 @@ dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "line_drawing"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1478a313008a3e6c8149995e90a99ee9094034b5c5c3da1eeb81183cb61d1d"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
@ -1680,6 +1689,17 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mouse-drawing"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"line_drawing",
|
||||
"rand 0.8.5",
|
||||
"ratatui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.4"
|
||||
|
@ -48,3 +48,7 @@ This is the original demo example from the main README. It is available for each
|
||||
This is the demo example from the main README and crate page. [Source](./apps/demo2/).
|
||||
|
||||

|
||||
|
||||
## Mouse Drawing demo
|
||||
|
||||
Shows how to handle mouse events. [Source](./apps/mouse-drawing/).
|
||||
|
17
examples/apps/mouse-drawing/Cargo.toml
Normal file
17
examples/apps/mouse-drawing/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "mouse-drawing"
|
||||
publish = false
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
color-eyre.workspace = true
|
||||
crossterm.workspace = true
|
||||
## a collection of line drawing algorithms (e.g. Bresenham's line algorithm)
|
||||
line_drawing = "1.0.0"
|
||||
rand = "0.8.5"
|
||||
ratatui.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
9
examples/apps/mouse-drawing/README.md
Normal file
9
examples/apps/mouse-drawing/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Mouse drawing demo
|
||||
|
||||
This example shows how to receive mouse and handle mouse events.
|
||||
|
||||
To run this demo:
|
||||
|
||||
```shell
|
||||
cargo run -p mouse-drawing
|
||||
```
|
123
examples/apps/mouse-drawing/src/main.rs
Normal file
123
examples/apps/mouse-drawing/src/main.rs
Normal file
@ -0,0 +1,123 @@
|
||||
/// A Ratatui example that demonstrates how to handle mouse events.
|
||||
///
|
||||
/// This example demonstrates how to handle mouse events in Ratatui. You can draw lines by
|
||||
/// clicking and dragging the mouse.
|
||||
///
|
||||
/// This example runs with the Ratatui library code in the branch that you are currently
|
||||
/// reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||
/// release.
|
||||
///
|
||||
/// [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||
use color_eyre::Result;
|
||||
use crossterm::{
|
||||
event::{
|
||||
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, MouseEvent,
|
||||
MouseEventKind,
|
||||
},
|
||||
execute,
|
||||
};
|
||||
use ratatui::{
|
||||
layout::{Position, Rect, Size},
|
||||
style::{Color, Stylize},
|
||||
symbols,
|
||||
text::Line,
|
||||
DefaultTerminal, Frame,
|
||||
};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let result = MouseDrawingApp::default().run(terminal);
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MouseDrawingApp {
|
||||
// Whether the app should exit
|
||||
pub should_exit: bool,
|
||||
// The last known mouse position
|
||||
pub mouse_position: Option<Position>,
|
||||
// The points that have been clicked / drawn by dragging the mouse
|
||||
pub points: Vec<(Position, Color)>,
|
||||
// The color to draw with
|
||||
pub current_color: Color,
|
||||
}
|
||||
|
||||
impl MouseDrawingApp {
|
||||
fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
execute!(std::io::stdout(), EnableMouseCapture)?;
|
||||
while !self.should_exit {
|
||||
terminal.draw(|frame| self.render(frame))?;
|
||||
self.handle_events()?;
|
||||
}
|
||||
execute!(std::io::stdout(), DisableMouseCapture)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_events(&mut self) -> Result<()> {
|
||||
match event::read()? {
|
||||
Event::Key(event) => self.on_key_event(event),
|
||||
Event::Mouse(event) => self.on_mouse_event(event),
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Quit the app if the user presses 'q' or 'Esc'
|
||||
fn on_key_event(&mut self, event: KeyEvent) {
|
||||
match event.code {
|
||||
KeyCode::Char(' ') => {
|
||||
self.current_color = Color::Rgb(rand::random(), rand::random(), rand::random());
|
||||
}
|
||||
KeyCode::Char('q') | KeyCode::Esc => self.should_exit = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds any points which were clicked or dragged to the `points` vector.
|
||||
fn on_mouse_event(&mut self, event: MouseEvent) {
|
||||
let position = Position::new(event.column, event.row);
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => self.points.push((position, self.current_color)),
|
||||
MouseEventKind::Drag(_) => self.draw_line(position),
|
||||
_ => {}
|
||||
}
|
||||
self.mouse_position = Some(position);
|
||||
}
|
||||
|
||||
/// Draw a line between the last point and the given position
|
||||
fn draw_line(&mut self, position: Position) {
|
||||
if let Some(start) = self.points.last() {
|
||||
let (x0, y0) = (i32::from(start.0.x), i32::from(start.0.y));
|
||||
let (x1, y1) = (i32::from(position.x), i32::from(position.y));
|
||||
for (x, y) in line_drawing::Bresenham::new((x0, y0), (x1, y1)) {
|
||||
let point = (Position::new(x as u16, y as u16), self.current_color);
|
||||
self.points.push(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
// call order is important here as later elements are drawn on top of earlier elements
|
||||
self.render_points(frame);
|
||||
self.render_mouse_cursor(frame);
|
||||
let value = "Mouse Example ('Esc' to quit. Click / drag to draw. 'Space' to change color)";
|
||||
let title = Line::from(value).centered();
|
||||
frame.render_widget(title, frame.area());
|
||||
}
|
||||
|
||||
fn render_points(&self, frame: &mut Frame<'_>) {
|
||||
for (position, color) in &self.points {
|
||||
let area = Rect::from((*position, Size::new(1, 1))).clamp(frame.area());
|
||||
frame.render_widget(symbols::block::FULL.fg(*color), area);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_mouse_cursor(&self, frame: &mut Frame<'_>) {
|
||||
if let Some(position) = self.mouse_position {
|
||||
let area = Rect::from((position, Size::new(1, 1))).clamp(frame.area());
|
||||
frame.render_widget("╳".bg(self.current_color), area);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user