mirror of
https://github.com/ratatui/ratatui.git
synced 2025-10-02 15:25:54 +00:00
chore(examples): add canvas demo app (#1578)
related #1512 This moves the canvas example to the apps and adds some interactivity via changing the marker by pressing enter.
This commit is contained in:
parent
9a541981b8
commit
9721300a47
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -316,6 +316,16 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "canvas"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"color-eyre",
|
||||||
|
"crossterm",
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"ratatui",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cargo-platform"
|
name = "cargo-platform"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
15
examples/apps/canvas/Cargo.toml
Normal file
15
examples/apps/canvas/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "canvas"
|
||||||
|
publish = false
|
||||||
|
license.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
color-eyre.workspace = true
|
||||||
|
crossterm.workspace = true
|
||||||
|
itertools.workspace = true
|
||||||
|
ratatui.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
9
examples/apps/canvas/README.md
Normal file
9
examples/apps/canvas/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Canvas demo
|
||||||
|
|
||||||
|
This example shows how to render various shapes and a map on a canvas.
|
||||||
|
|
||||||
|
To run this demo:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo run -p canvas
|
||||||
|
```
|
@ -1,18 +1,13 @@
|
|||||||
//! # [Ratatui] Canvas example
|
/// A Ratatui example that demonstrates how to draw on a canvas.
|
||||||
//!
|
///
|
||||||
//! The latest version of this example is available in the [examples] folder in the repository.
|
/// This example demonstrates how to draw various shapes such as rectangles, circles, and lines
|
||||||
//!
|
/// on a canvas. It also demonstrates how to draw a map.
|
||||||
//! Please note that the examples are designed to be run against the `main` branch of the Github
|
///
|
||||||
//! repository. This means that you may not be able to compile with the latest release version on
|
/// This example runs with the Ratatui library code in the branch that you are currently
|
||||||
//! crates.io, or the one that you have installed locally.
|
/// reading. See the [`latest`] branch for the code which works with the most recent Ratatui
|
||||||
//!
|
/// release.
|
||||||
//! See the [examples readme] for more information on finding examples that match the version of the
|
///
|
||||||
//! library you are using.
|
/// [`latest`]: https://github.com/ratatui/ratatui/tree/latest
|
||||||
//!
|
|
||||||
//! [Ratatui]: https://github.com/ratatui/ratatui
|
|
||||||
//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples
|
|
||||||
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::stdout,
|
io::stdout,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@ -29,6 +24,7 @@ use ratatui::{
|
|||||||
layout::{Constraint, Layout, Position, Rect},
|
layout::{Constraint, Layout, Position, Rect},
|
||||||
style::{Color, Stylize},
|
style::{Color, Stylize},
|
||||||
symbols::Marker,
|
symbols::Marker,
|
||||||
|
text::Text,
|
||||||
widgets::{
|
widgets::{
|
||||||
canvas::{Canvas, Circle, Map, MapResolution, Points, Rectangle},
|
canvas::{Canvas, Circle, Map, MapResolution, Points, Rectangle},
|
||||||
Block, Widget,
|
Block, Widget,
|
||||||
@ -54,7 +50,6 @@ struct App {
|
|||||||
playground: Rect,
|
playground: Rect,
|
||||||
vx: f64,
|
vx: f64,
|
||||||
vy: f64,
|
vy: f64,
|
||||||
tick_count: u64,
|
|
||||||
marker: Marker,
|
marker: Marker,
|
||||||
points: Vec<Position>,
|
points: Vec<Position>,
|
||||||
is_drawing: bool,
|
is_drawing: bool,
|
||||||
@ -75,7 +70,6 @@ impl App {
|
|||||||
playground: Rect::new(10, 10, 200, 100),
|
playground: Rect::new(10, 10, 200, 100),
|
||||||
vx: 1.0,
|
vx: 1.0,
|
||||||
vy: 1.0,
|
vy: 1.0,
|
||||||
tick_count: 0,
|
|
||||||
marker: Marker::Dot,
|
marker: Marker::Dot,
|
||||||
points: vec![],
|
points: vec![],
|
||||||
is_drawing: false,
|
is_drawing: false,
|
||||||
@ -114,6 +108,15 @@ impl App {
|
|||||||
KeyCode::Up | KeyCode::Char('k') => self.y -= 1.0,
|
KeyCode::Up | KeyCode::Char('k') => self.y -= 1.0,
|
||||||
KeyCode::Right | KeyCode::Char('l') => self.x += 1.0,
|
KeyCode::Right | KeyCode::Char('l') => self.x += 1.0,
|
||||||
KeyCode::Left | KeyCode::Char('h') => self.x -= 1.0,
|
KeyCode::Left | KeyCode::Char('h') => self.x -= 1.0,
|
||||||
|
KeyCode::Enter => {
|
||||||
|
self.marker = match self.marker {
|
||||||
|
Marker::Dot => Marker::Braille,
|
||||||
|
Marker::Braille => Marker::Block,
|
||||||
|
Marker::Block => Marker::HalfBlock,
|
||||||
|
Marker::HalfBlock => Marker::Bar,
|
||||||
|
Marker::Bar => Marker::Dot,
|
||||||
|
};
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,17 +133,6 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_tick(&mut self) {
|
fn on_tick(&mut self) {
|
||||||
self.tick_count += 1;
|
|
||||||
// only change marker every 180 ticks (3s) to avoid stroboscopic effect
|
|
||||||
if (self.tick_count % 180) == 0 {
|
|
||||||
self.marker = match self.marker {
|
|
||||||
Marker::Dot => Marker::Braille,
|
|
||||||
Marker::Braille => Marker::Block,
|
|
||||||
Marker::Block => Marker::HalfBlock,
|
|
||||||
Marker::HalfBlock => Marker::Bar,
|
|
||||||
Marker::Bar => Marker::Dot,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// bounce the ball by flipping the velocity vector
|
// bounce the ball by flipping the velocity vector
|
||||||
let ball = &self.ball;
|
let ball = &self.ball;
|
||||||
let playground = self.playground;
|
let playground = self.playground;
|
||||||
@ -154,18 +146,28 @@ impl App {
|
|||||||
{
|
{
|
||||||
self.vy = -self.vy;
|
self.vy = -self.vy;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ball.x += self.vx;
|
self.ball.x += self.vx;
|
||||||
self.ball.y += self.vy;
|
self.ball.y += self.vy;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, frame: &mut Frame) {
|
fn draw(&self, frame: &mut Frame) {
|
||||||
|
let header = Text::from_iter([
|
||||||
|
"Canvas Example".bold(),
|
||||||
|
"<q> Quit | <enter> Change Marker | <hjkl> Move".into(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let vertical = Layout::vertical([
|
||||||
|
Constraint::Length(header.height() as u16),
|
||||||
|
Constraint::Percentage(50),
|
||||||
|
Constraint::Percentage(50),
|
||||||
|
]);
|
||||||
|
let [text_area, up, down] = vertical.areas(frame.area());
|
||||||
|
frame.render_widget(header.centered(), text_area);
|
||||||
|
|
||||||
let horizontal =
|
let horizontal =
|
||||||
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]);
|
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]);
|
||||||
let vertical = Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]);
|
let [draw, pong] = horizontal.areas(up);
|
||||||
let [left, right] = horizontal.areas(frame.area());
|
let [map, boxes] = horizontal.areas(down);
|
||||||
let [draw, map] = vertical.areas(left);
|
|
||||||
let [pong, boxes] = vertical.areas(right);
|
|
||||||
|
|
||||||
frame.render_widget(self.map_canvas(), map);
|
frame.render_widget(self.map_canvas(), map);
|
||||||
frame.render_widget(self.draw_canvas(draw), draw);
|
frame.render_widget(self.draw_canvas(draw), draw);
|
@ -142,11 +142,6 @@ bench = false
|
|||||||
name = "main"
|
name = "main"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "canvas"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "chart"
|
name = "chart"
|
||||||
required-features = ["crossterm"]
|
required-features = ["crossterm"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user