mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-22 12:43:16 +00:00
Cache layout and performance fixes
This commit is contained in:
parent
07ff2b08eb
commit
d7131ead11
5 changed files with 61 additions and 31 deletions
|
@ -82,7 +82,7 @@ struct App {
|
|||
progress: u16,
|
||||
data: Vec<u64>,
|
||||
data2: Vec<(f64, f64)>,
|
||||
window: [f64; 2],
|
||||
data3: Vec<(f64, f64)>,
|
||||
colors: [Color; 2],
|
||||
color_index: usize,
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ fn main() {
|
|||
|
||||
let mut rand_signal = RandomSignal::new(Range::new(0, 100));
|
||||
let mut sin_signal = SinSignal::new(4.0, 20.0);
|
||||
let mut sin_signal2 = SinSignal::new(2.0, 10.0);
|
||||
|
||||
let mut app = App {
|
||||
name: String::from("Test app"),
|
||||
|
@ -119,7 +120,7 @@ fn main() {
|
|||
progress: 0,
|
||||
data: rand_signal.clone().take(100).collect(),
|
||||
data2: sin_signal.clone().take(100).collect(),
|
||||
window: [0.0, 100.0],
|
||||
data3: sin_signal2.clone().take(100).collect(),
|
||||
colors: [Color::Magenta, Color::Red],
|
||||
color_index: 0,
|
||||
};
|
||||
|
@ -141,7 +142,7 @@ fn main() {
|
|||
let tx = tx.clone();
|
||||
loop {
|
||||
tx.send(Event::Tick).unwrap();
|
||||
thread::sleep(time::Duration::from_millis(500));
|
||||
thread::sleep(time::Duration::from_millis(1000));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -184,8 +185,8 @@ fn main() {
|
|||
app.data.pop();
|
||||
app.data2.remove(0);
|
||||
app.data2.push(sin_signal.next().unwrap());
|
||||
app.window[0] += 1.0;
|
||||
app.window[1] += 1.0;
|
||||
app.data3.remove(0);
|
||||
app.data3.push(sin_signal2.next().unwrap());
|
||||
app.selected += 1;
|
||||
if app.selected >= app.items.len() {
|
||||
app.selected = 0;
|
||||
|
@ -206,14 +207,14 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||
.direction(Direction::Vertical)
|
||||
.alignment(Alignment::Left)
|
||||
.chunks(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)])
|
||||
.render(&Terminal::size().unwrap(), |chunks| {
|
||||
.render(t, &Terminal::size().unwrap(), |t, chunks| {
|
||||
Block::default().borders(border::ALL).title("Graphs").render(&chunks[0], t);
|
||||
Group::default()
|
||||
.direction(Direction::Vertical)
|
||||
.alignment(Alignment::Left)
|
||||
.margin(1)
|
||||
.chunks(&[Size::Fixed(2), Size::Fixed(3)])
|
||||
.render(&chunks[0], |chunks| {
|
||||
.render(t, &chunks[0], |t, chunks| {
|
||||
Gauge::default()
|
||||
.block(Block::default().title("Gauge:"))
|
||||
.bg(Color::Yellow)
|
||||
|
@ -234,7 +235,7 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||
.direction(Direction::Horizontal)
|
||||
.alignment(Alignment::Left)
|
||||
.chunks(&sizes)
|
||||
.render(&chunks[1], |chunks| {
|
||||
.render(t, &chunks[1], |t, chunks| {
|
||||
List::default()
|
||||
.block(Block::default().borders(border::ALL).title("List"))
|
||||
.render(&chunks[0], t);
|
||||
|
@ -243,9 +244,10 @@ fn draw(t: &mut Terminal, app: &App) {
|
|||
.block(Block::default()
|
||||
.borders(border::ALL)
|
||||
.title("Chart"))
|
||||
.x_axis(Axis::default().title("X").bounds(app.window))
|
||||
.x_axis(Axis::default().title("X").bounds([0.0, 100.0]))
|
||||
.y_axis(Axis::default().title("Y").bounds([0.0, 40.0]))
|
||||
.datasets(&[Dataset::default().color(Color::Cyan).data(&app.data2)])
|
||||
.datasets(&[Dataset::default().color(Color::Cyan).data(&app.data2),
|
||||
Dataset::default().color(Color::Yellow).data(&app.data3)])
|
||||
.render(&chunks[1], t);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,7 +6,10 @@ use cassowary::WeightedRelation::*;
|
|||
use cassowary::strength::{WEAK, REQUIRED};
|
||||
|
||||
use buffer::Buffer;
|
||||
use terminal::Terminal;
|
||||
use util::hash;
|
||||
|
||||
#[derive(Hash)]
|
||||
pub enum Alignment {
|
||||
Top,
|
||||
Left,
|
||||
|
@ -15,12 +18,13 @@ pub enum Alignment {
|
|||
Right,
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
pub enum Direction {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct Rect {
|
||||
pub x: u16,
|
||||
pub y: u16,
|
||||
|
@ -235,6 +239,7 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
pub struct Group {
|
||||
direction: Direction,
|
||||
alignment: Alignment,
|
||||
|
@ -273,14 +278,26 @@ impl Group {
|
|||
self.chunks = Vec::from(chunks);
|
||||
self
|
||||
}
|
||||
pub fn render<F>(&self, area: &Rect, mut f: F)
|
||||
where F: FnMut(&[Rect])
|
||||
pub fn render<F>(&self, t: &mut Terminal, area: &Rect, mut f: F)
|
||||
where F: FnMut(&mut Terminal, &[Rect])
|
||||
{
|
||||
let chunks = split(area,
|
||||
&self.direction,
|
||||
&self.alignment,
|
||||
self.margin,
|
||||
&self.chunks);
|
||||
f(&chunks);
|
||||
let hash = hash(self, area);
|
||||
let (cache_update, chunks) = match t.get_layout(hash) {
|
||||
Some(chs) => (false, chs.to_vec()),
|
||||
None => {
|
||||
(true,
|
||||
split(area,
|
||||
&self.direction,
|
||||
&self.alignment,
|
||||
self.margin,
|
||||
&self.chunks))
|
||||
}
|
||||
};
|
||||
|
||||
f(t, &chunks);
|
||||
|
||||
if cache_update {
|
||||
t.set_layout(hash, chunks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,16 +8,19 @@ use termion::raw::{IntoRawMode, RawTerminal};
|
|||
use buffer::Buffer;
|
||||
use widgets::Widget;
|
||||
use layout::Rect;
|
||||
use util::hash;
|
||||
|
||||
pub struct Terminal {
|
||||
stdout: RawTerminal<io::Stdout>,
|
||||
layout_cache: HashMap<u64, Vec<Rect>>,
|
||||
}
|
||||
|
||||
impl Terminal {
|
||||
pub fn new() -> Result<Terminal, io::Error> {
|
||||
let stdout = try!(io::stdout().into_raw_mode());
|
||||
Ok(Terminal { stdout: stdout })
|
||||
Ok(Terminal {
|
||||
stdout: stdout,
|
||||
layout_cache: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn size() -> Result<Rect, io::Error> {
|
||||
|
@ -30,20 +33,29 @@ impl Terminal {
|
|||
})
|
||||
}
|
||||
|
||||
// FIXME: Clean cache to prevent memory leak
|
||||
pub fn get_layout(&self, hash: u64) -> Option<&Vec<Rect>> {
|
||||
self.layout_cache.get(&hash)
|
||||
}
|
||||
|
||||
pub fn set_layout(&mut self, hash: u64, chunks: Vec<Rect>) {
|
||||
self.layout_cache.insert(hash, chunks);
|
||||
}
|
||||
|
||||
pub fn render_buffer(&mut self, buffer: Buffer) {
|
||||
let mut string = String::with_capacity(buffer.area().area() as usize);
|
||||
for (i, cell) in buffer.content().iter().enumerate() {
|
||||
let (lx, ly) = buffer.pos_of(i).unwrap();
|
||||
let (x, y) = (lx + buffer.area().x, ly + buffer.area().y);
|
||||
if cell.symbol != "" {
|
||||
write!(self.stdout,
|
||||
"{}{}{}{}",
|
||||
termion::cursor::Goto(x + 1, y + 1),
|
||||
cell.fg.fg(),
|
||||
cell.bg.bg(),
|
||||
cell.symbol)
|
||||
.unwrap();
|
||||
string.push_str(&format!("{}{}{}{}",
|
||||
termion::cursor::Goto(x + 1, y + 1),
|
||||
cell.fg.fg(),
|
||||
cell.bg.bg(),
|
||||
cell.symbol))
|
||||
}
|
||||
}
|
||||
write!(self.stdout, "{}", string);
|
||||
self.stdout.flush().unwrap();
|
||||
}
|
||||
pub fn clear(&mut self) {
|
||||
|
|
|
@ -3,9 +3,10 @@ use std::hash::{Hash, Hasher, BuildHasher};
|
|||
|
||||
use layout::Rect;
|
||||
|
||||
pub fn hash<T: Hash>(t: &T) -> u64 {
|
||||
pub fn hash<T: Hash>(t: &T, area: &Rect) -> u64 {
|
||||
let state = RandomState::new();
|
||||
let mut hasher = state.build_hasher();
|
||||
t.hash(&mut hasher);
|
||||
area.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
|
|
@ -138,7 +138,6 @@ impl<'a> Widget<'a> for Chart<'a> {
|
|||
|
||||
let margin_x = chart_area.x - area.x;
|
||||
let margin_y = chart_area.y - area.y;
|
||||
// info!("{:?}", self.datasets[0].data[0]);
|
||||
|
||||
for dataset in self.datasets {
|
||||
for &(x, y) in dataset.data.iter() {
|
||||
|
@ -150,7 +149,6 @@ impl<'a> Widget<'a> for Chart<'a> {
|
|||
(self.y_axis.bounds[1] - self.y_axis.bounds[0]);
|
||||
let dx = (self.x_axis.bounds[1] - x) * (chart_area.width - 1) as f64 /
|
||||
(self.x_axis.bounds[1] - self.x_axis.bounds[0]);
|
||||
info!("{} {}", dx, dy);
|
||||
buf.update_cell(dx as u16 + margin_x, dy as u16 + margin_y, |c| {
|
||||
c.symbol = symbols::DOT;
|
||||
c.fg = dataset.color;
|
||||
|
|
Loading…
Reference in a new issue