docs: add mouse-drawing example (#1546)

Demonstrates how to handle mouse events
This commit is contained in:
Josh McKinney 2024-12-04 13:34:12 -08:00 committed by GitHub
parent 9275d3421c
commit ed071f3723
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 173 additions and 0 deletions

20
Cargo.lock generated
View File

@ -1561,6 +1561,15 @@ dependencies = [
"bitflags 2.6.0", "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]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.14" version = "0.4.14"
@ -1680,6 +1689,17 @@ dependencies = [
"windows-sys 0.52.0", "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]] [[package]]
name = "nix" name = "nix"
version = "0.26.4" version = "0.26.4"

View File

@ -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/). This is the demo example from the main README and crate page. [Source](./apps/demo2/).
![Demo2](https://github.com/ratatui/ratatui/blob/images/examples/demo2.gif?raw=true) ![Demo2](https://github.com/ratatui/ratatui/blob/images/examples/demo2.gif?raw=true)
## Mouse Drawing demo
Shows how to handle mouse events. [Source](./apps/mouse-drawing/).

View 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

View 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
```

View 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);
}
}
}