diff --git a/src/core/render.rs b/src/core/render.rs index a5c99d5a..00d6bcad 100644 --- a/src/core/render.rs +++ b/src/core/render.rs @@ -62,6 +62,12 @@ pub trait Render: Send { } } +impl Render for () { + fn render (&self, b: &mut Buffer, a: Rect) -> Usually { + Ok(Rect { x: a.x, y: a.y, width: 0, height: 0 }) + } +} + impl Usually + Send> Render for T { fn render (&self, b: &mut Buffer, a: Rect) -> Usually { (*self)(b, a) diff --git a/src/view.rs b/src/view.rs index 12913c89..1457f0c6 100644 --- a/src/view.rs +++ b/src/view.rs @@ -6,9 +6,11 @@ pub mod sequencer; pub mod transport; pub mod plugin; pub mod border; +pub mod split; pub use self::border::*; pub use self::layout::*; +pub use self::split::*; pub use self::transport::TransportView; pub use self::arranger::*; pub use self::chain::ChainView; @@ -17,49 +19,62 @@ pub use self::sequencer::SequencerView; use crate::{render, App, AppSection, core::*}; render!(App |self, buf, area| { - let Rect { x, y, width, height } = area; - let transport = TransportView::new(self).render(buf, area)?; - let y = y + transport.height; - let arranger = Rect { x, y, width, height }; - let arranger = ArrangerView::new(&self, !self.arranger_mode).render(buf, arranger)?; - let style_entered = if self.entered { - Style::default().green() - } else { - Style::default().green().dim() - }; - if self.section == AppSection::Arranger { - QuarterV(style_entered).draw(buf, arranger) - } - let y = y + arranger.height; - if self.track_cursor > 0 { - let chain = Rect { x, y: y + height - height / 3 - 1, width, height: height / 3 }; - let chain = ChainView::new(&self, false).render(buf, chain)?; - if self.section == AppSection::Chain { - QuarterV(style_entered).draw(buf, Rect { width, ..chain }) - } - let phrase = Rect { x, y, width, height: height - height / 3 }; - let phrase = SequencerView::new(&self).render(buf, phrase)?; - if self.section == AppSection::Sequencer { - QuarterV(style_entered).draw(buf, phrase) - } - } else { - let area = Rect { x, y, width, height }; - let mut x = area.x; - for track in self.tracks.iter() { - track.name.blit(buf, x + 1, area.y, Some(Style::default().white().bold())); - let chain = Rect { x, y: area.y + 1, width: width, height: height - y - 1 }; - x = x + ChainView { - focused: self.section == AppSection::Chain, - track: Some(track), - vertical: true, - } - .render(buf, chain)? - .width - .max(track.name.len() as u16); - } - }; + Split::down([ + &TransportView::new(self), + &Split::down([ + &ArrangerView::new(&self, !self.arranger_mode), + &Split::down([ + &SequencerView::new(&self), + &ChainView::new(&self, false) + ]) + ]) + ]).render(buf, area)?; if let Some(ref modal) = self.modal { modal.render(buf, area)?; } Ok(area) + + //let transport = transport.render(buf, area)?; + //let y = y + transport.height; + + //let arranger = arranger.render(buf, Rect { x, y, width, height })?; + //let style_entered = if self.entered { + //Style::default().green() + //} else { + //Style::default().green().dim() + //}; + //if self.section == AppSection::Arranger { + //QuarterV(style_entered).draw(buf, arranger) + //} + //let y = y + arranger.height; + //if self.track_cursor > 0 { + //let chain = ChainView::new(&self, false); + //let phrase = SequencerView::new(&self); + + //let chain = chain.render(buf, chain_area)?; + //if self.section == AppSection::Chain { + //QuarterV(style_entered).draw(buf, Rect { width, ..chain }) + //} + //let phrase = phrase.render(buf, Rect { + //x, y, width, height: height - height / 3 + //})?; + //if self.section == AppSection::Sequencer { + //QuarterV(style_entered).draw(buf, phrase) + //} + //} else { + //let area = Rect { x, y, width, height }; + //let mut x = area.x; + //for track in self.tracks.iter() { + //let chain = ChainView { + //focused: self.section == AppSection::Chain, + //track: Some(track), + //vertical: true, + //}; + //track.name.blit(buf, x + 1, area.y, Some(Style::default().white().bold())); + //let chain = chain.render(buf, Rect { + //x, y: area.y + 1, width: width, height: height - y - 1 + //})?; + //x = x + chain.width.max(track.name.len() as u16); + //} + //}; }); diff --git a/src/view/split.rs b/src/view/split.rs new file mode 100644 index 00000000..1c22454f --- /dev/null +++ b/src/view/split.rs @@ -0,0 +1,97 @@ +use crate::core::*; + +pub enum Direction { + Down, + Right, +} + +pub struct Split<'a, const N: usize>(pub Direction, pub [&'a (dyn Render + Sync);N]); + +impl<'a, const N: usize> Split<'a, N> { + pub fn down (items: [&'a (dyn Render + Sync);N]) -> Self { + Self(Direction::Down, items) + } +} + +impl<'a, const N: usize> Render for Split<'a, N> { + fn render (&self, buf: &mut Buffer, area: Rect) -> Usually { + let Rect { mut x, mut y, mut width, mut height } = area; + for item in self.1 { + if width == 0 || height == 0 { + break + } + let result = item.render(buf, Rect { x, y, width, height })?; + match self.0 { + Direction::Down => { + y = y + result.height; + height = height.saturating_sub(result.height); + }, + Direction::Right => { + x = x + result.width; + width = width.saturating_sub(result.width); + }, + } + } + Ok(area) + } +} + +//pub struct Split<'a> { + //a: &'a (dyn Render + Sync), + //b: &'a (dyn Render + Sync), + //direction: Direction, + //reverse: bool +//} + +//impl<'a> Split<'a> { + //pub fn lr (a: &'a (dyn Render + Sync), b: &'a (dyn Render + Sync)) -> Self { + //Self { a, b, direction: Direction::X, reverse: false } + //} + //pub fn rl (a: &'a (dyn Render + Sync), b: &'a (dyn Render + Sync)) -> Self { + //Self { a, b, direction: Direction::X, reverse: true } + //} + //pub fn tb (a: &'a (dyn Render + Sync), b: &'a (dyn Render + Sync)) -> Self { + //Self { a, b, direction: Direction::Y, reverse: false } + //} + //pub fn bt (a: &'a (dyn Render + Sync), b: &'a (dyn Render + Sync)) -> Self { + //Self { a, b, direction: Direction::Y, reverse: true } + //} + + //fn split (&self, length: u16) -> (u16, u16) { + //let l1 = (length as f64 * self.proportion).round() as u16; + //let l2 = length.saturating_sub(l1); + //(l1, l2) + //} +//} + +//impl<'a> Render for Split<'a> { + //fn render (&self, buf: &mut Buffer, area: Rect) -> Usually { + //let Rect { x, y, width, height } = area; + //let area1 = if self.reverse { self.b } else { self.a } + //.render(buf, area)?; + //let area2 = if self.reverse { self.a } else { self.b } + //.render(buf, match (self.direction, self.reverse)Rect { + //})?; + //let (area1, area2) = match self.direction { + //Direction::X => { + //let (w1, w2) = self.split(width); + //(Rect { x, y, width: w1, height }, Rect { x: x + w1, y, width: w2, height }) + //}, + //Direction::Y => { + //let (h1, h2) = self.split(height); + //(Rect { x, y, width, height: h1 }, Rect { x, y: y + h1, width, height: h2 }) + //}, + //}; + //match self.reverse { + //true => { + //self.b.render(buf, area1)?; + //self.a.render(buf, area2)?; + //}, + //false => { + //self.a.render(buf, area1)?; + //self.b.render(buf, area2)?; + //}, + //}; + //Ok(area) + //} +//}