diff --git a/src/buffer.rs b/src/buffer.rs index ca910c1..dc0e51b 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -80,7 +80,11 @@ impl Buffer { pub fn index_of(&self, x: u16, y: u16) -> usize { let index = (y * self.area.width + x) as usize; - debug_assert!(index < self.content.len()); + debug_assert!(index < self.content.len(), + "Trying to access position x:{}, y:{} in buffer {:?}", + x, + y, + self.area); index } diff --git a/src/layout.rs b/src/layout.rs index 0928750..40bfdc8 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,13 +1,13 @@ use std::cmp::{min, max}; use std::collections::HashMap; -use cassowary::{Solver, Variable, Constraint}; +use cassowary::{Solver, Variable, Expression, Constraint}; use cassowary::WeightedRelation::*; use cassowary::strength::{REQUIRED, WEAK}; use terminal::Terminal; -#[derive(Hash, PartialEq)] +#[derive(Debug, Hash, PartialEq)] pub enum Direction { Horizontal, Vertical, @@ -118,12 +118,11 @@ pub enum Size { /// # Examples /// ``` /// extern crate tui; -/// use tui::layout::{Rect, Size, Alignment, Direction, split}; +/// use tui::layout::{Rect, Size, Direction, split}; /// /// fn main() { /// let chunks = split(&Rect{x: 2, y: 2, width: 10, height: 10}, /// &Direction::Vertical, -/// &Alignment::Left, /// 0, /// &[Size::Fixed(5), Size::Min(5)]); /// } @@ -142,22 +141,24 @@ pub fn split(area: &Rect, dir: &Direction, margin: u16, sizes: &[Size]) -> Vec = Vec::new(); + let mut constraints: Vec = Vec::with_capacity(elements.len() * 4 + sizes.len() * 6); + for elt in &elements { + constraints.push(elt.left() | GE(REQUIRED) | dest_area.left() as f64); + constraints.push(elt.top() | GE(REQUIRED) | dest_area.top() as f64); + constraints.push(elt.right() | LE(REQUIRED) | dest_area.right() as f64); + constraints.push(elt.bottom() | LE(REQUIRED) | dest_area.bottom() as f64); + } if let Some(first) = elements.first() { constraints.push(match *dir { - Direction::Horizontal => first.x | EQ(REQUIRED) | dest_area.x as f64, - Direction::Vertical => first.y | EQ(REQUIRED) | dest_area.y as f64, + Direction::Horizontal => first.left() | EQ(REQUIRED) | dest_area.left() as f64, + Direction::Vertical => first.top() | EQ(REQUIRED) | dest_area.top() as f64, }); } if let Some(last) = elements.last() { constraints.push(match *dir { - Direction::Horizontal => { - (last.x + last.width) | EQ(REQUIRED) | (dest_area.x + dest_area.width) as f64 - } - Direction::Vertical => { - (last.y + last.height) | EQ(REQUIRED) | (dest_area.y + dest_area.height) as f64 - } - }) + Direction::Horizontal => last.right() | EQ(REQUIRED) | dest_area.right() as f64, + Direction::Vertical => last.bottom() | EQ(REQUIRED) | dest_area.bottom() as f64, + }); } match *dir { Direction::Horizontal => { @@ -196,30 +197,21 @@ pub fn split(area: &Rect, dir: &Direction, margin: u16, sizes: &[Size]) -> Vec { - if value <= dest_area.right() { - results[index].x = value; - } + results[index].x = value; } 1 => { - if value <= dest_area.bottom() { - results[index].y = value; - } + results[index].y = value; } 2 => { - if value <= dest_area.width { - results[index].width = value; - } + results[index].width = value; } 3 => { - if value <= dest_area.height { - results[index].height = value; - } + results[index].height = value; } _ => {} } @@ -243,9 +235,25 @@ impl Element { height: Variable::new(), } } + + fn left(&self) -> Variable { + self.x + } + + fn top(&self) -> Variable { + self.y + } + + fn right(&self) -> Expression { + self.x + self.width + } + + fn bottom(&self) -> Expression { + self.y + self.height + } } -#[derive(Hash)] +#[derive(Debug, Hash)] pub struct Group { pub direction: Direction, pub margin: u16, diff --git a/src/terminal.rs b/src/terminal.rs index 6c0bd67..5ffacfa 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -11,6 +11,7 @@ use widgets::Widget; use style::Color; use util::hash; +#[derive(Debug)] pub struct LayoutEntry { chunks: Vec, hot: bool, @@ -49,8 +50,12 @@ impl Terminal { let hash = hash(group, area); let entry = self.layout_cache .entry(hash) - .or_insert({ + .or_insert_with(|| { let chunks = split(area, &group.direction, group.margin, &group.sizes); + debug!("New layout computed:\n* Group = {:?}\n* Chunks = {:?}\n* Hash = {}", + group, + chunks, + hash); LayoutEntry { chunks: chunks, hot: true, @@ -102,7 +107,7 @@ impl Terminal { inst += 1; } string.push_str(&format!("{}{}", Color::Reset.fg(), Color::Reset.bg())); - info!("{}", inst); + debug!("{} instructions outputed.", inst); write!(self.stdout, "{}", string).unwrap(); } @@ -116,6 +121,7 @@ impl Terminal { self.buffers[self.current].resize(area); self.buffers[1 - self.current].resize(area); self.buffers[1 - self.current].reset(); + self.layout_cache.clear(); self.clear(); } @@ -129,10 +135,15 @@ impl Terminal { .iter() .filter_map(|(h, e)| if !e.hot { Some(*h) } else { None }) .collect::>(); + for h in to_remove { self.layout_cache.remove(&h); } + for (_, e) in &mut self.layout_cache { + e.hot = false; + } + // Swap buffers self.buffers[1 - self.current].reset(); self.current = 1 - self.current; diff --git a/src/widgets/barchart.rs b/src/widgets/barchart.rs index 4b41714..37f7300 100644 --- a/src/widgets/barchart.rs +++ b/src/widgets/barchart.rs @@ -87,7 +87,7 @@ impl<'a> Widget for BarChart<'a> { None => *area, }; - if chart_area.height < 1 { + if chart_area.height < 2 { return; } diff --git a/src/widgets/list.rs b/src/widgets/list.rs index c79df87..4343e01 100644 --- a/src/widgets/list.rs +++ b/src/widgets/list.rs @@ -79,6 +79,10 @@ impl<'a> Widget for List<'a> { None => *area, }; + if list_area.height < 1 { + return; + } + let list_length = self.items.len(); let list_height = list_area.height as usize; let bound = min(list_height, list_length);