mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-27 04:50:46 +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",
|
"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"
|
||||||
|
@ -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/).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## 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