diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index ee76a8ce..84469a69 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -183,6 +183,36 @@ pub trait ContentComponent: Widget + Handle {} /// Everything that implements [Render] and [Handle] is a [Component]. impl + Handle> ContentComponent for C {} +pub struct CustomWidget< + E: Engine, + L: Send + Sync + Fn(E::Size)->Perhaps, + R: Send + Sync + Fn(&mut E::Output)->Usually<()> +>(L, R, PhantomData); + +impl< + E: Engine, + L: Send + Sync + Fn(E::Size)->Perhaps, + R: Send + Sync + Fn(&mut E::Output)->Usually<()> +> CustomWidget { + pub fn new (layout: L, render: R) -> Self { + Self(layout, render, Default::default()) + } +} +impl< + E: Engine, + L: Send + Sync + Fn(E::Size)->Perhaps, + R: Send + Sync + Fn(&mut E::Output)->Usually<()> +> Widget for CustomWidget { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + self.0(to) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + self.1(to) + } +} + + pub trait Exit: Send { fn exited (&self) -> bool; fn exit (&mut self); diff --git a/crates/tek_sequencer/src/sequencer.rs b/crates/tek_sequencer/src/sequencer.rs index 3b7125ec..799735f4 100644 --- a/crates/tek_sequencer/src/sequencer.rs +++ b/crates/tek_sequencer/src/sequencer.rs @@ -1357,11 +1357,76 @@ impl Content for Sequencer { }.min_xy(10, 9), ); let content = lay!( - SequenceKeys(&self).fill_y(), + + // keys + CustomWidget::new(|to|Ok(Some([32,4])), |to: &mut TuiOutput|{ + let area = to.area(); + if area.h() < 2 { + return Ok(()) + } + let area = [area.x(), area.y(), 5, area.h() - 2]; + to.buffer_update(area, &|cell, x, y|{ + let y = y + self.note_axis.start as u16; + if x < self.keys.area.width && y < self.keys.area.height { + *cell = self.keys.get(x, y).clone() + } + }); + Ok(()) + }).fill_y(), + self.phrase.as_ref().map(|phrase|SequenceTimer(&self, phrase.clone()).fill_x()), - SequenceNotes(&self).fill_x(), - SequenceCursor(&self), - SequenceZoom(&self), + + // notes + CustomWidget::new(|to|Ok(Some([32,4])), |to: &mut TuiOutput|{ + let area = to.area(); + if area.h() < 2 { + return Ok(())//Some(area)) + } + let area = [ + area.x() + Sequencer::H_KEYS_OFFSET as u16, + area.y() + 1, + area.w().saturating_sub(Sequencer::H_KEYS_OFFSET as u16), + area.h().saturating_sub(2), + ]; + to.buffer_update(area, &move |cell, x, y|{ + let src_x = ((x as usize + self.time_axis.start) * self.time_axis.scale) as usize; + let src_y = (y as usize + self.note_axis.start) as usize; + if src_x < self.buffer.width && src_y < self.buffer.height - 1 { + let src = self.buffer.get(src_x, self.buffer.height - src_y); + src.map(|src|{ + cell.set_symbol(src.symbol()); + cell.set_fg(src.fg); + }); + } + }); + Ok(())//Some(area)) + }).fill_x(), + + // cursor + CustomWidget::new(|to|Ok(Some([1,1])), |to: &mut TuiOutput|{ + let area = to.area(); + if let (Some(time), Some(note)) = (self.time_axis.point, self.note_axis.point) { + let x = area.x() + Sequencer::H_KEYS_OFFSET as u16 + time as u16; + let y = area.y() + 1 + note as u16 / 2; + let c = if note % 2 == 0 { "▀" } else { "▄" }; + to.blit(&c, x, y, self.style_focus()); + Ok(()) + } else { + //Ok(Some([0,0,0,0])) + Ok(()) + } + }), + + //zoom + CustomWidget::new(|to|Ok(Some([10,1])), |to: &mut TuiOutput|{ + let area = to.area(); + let quant = ppq_to_name(self.time_axis.scale); + let quant_x = area.x() + area.w() - 1 - quant.len() as u16; + let quant_y = area.y() + area.h() - 2; + to.blit(&quant, quant_x, quant_y, self.style_focus()); + Ok(()) + }), + ); row!(toolbar, content) .fill_x() @@ -1556,105 +1621,6 @@ pub(crate) fn keys_vert () -> Buffer { buffer } -/////////////////////////////////////////////////////////////////////////////////////////////////// - -struct SequenceKeys<'a>(&'a Sequencer); -impl<'a> Widget for SequenceKeys<'a> { - type Engine = Tui; - fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - Ok(Some([32,4])) - } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { - let area = to.area(); - if area.h() < 2 { - return Ok(()) - } - let area = [area.x(), area.y(), 5, area.h() - 2]; - to.buffer_update(area, &|cell, x, y|{ - let y = y + self.0.note_axis.start as u16; - if x < self.0.keys.area.width && y < self.0.keys.area.height { - *cell = self.0.keys.get(x, y).clone() - } - }); - Ok(()) - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -struct SequenceNotes<'a>(&'a Sequencer); -impl<'a> Widget for SequenceNotes<'a> { - type Engine = Tui; - fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - Ok(Some([32,4])) - } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { - let area = to.area(); - if area.h() < 2 { - return Ok(())//Some(area)) - } - let area = [ - area.x() + Sequencer::H_KEYS_OFFSET as u16, - area.y() + 1, - area.w().saturating_sub(Sequencer::H_KEYS_OFFSET as u16), - area.h().saturating_sub(2), - ]; - to.buffer_update(area, &move |cell, x, y|{ - let src_x = ((x as usize + self.0.time_axis.start) * self.0.time_axis.scale) as usize; - let src_y = (y as usize + self.0.note_axis.start) as usize; - if src_x < self.0.buffer.width && src_y < self.0.buffer.height - 1 { - let src = self.0.buffer.get(src_x, self.0.buffer.height - src_y); - src.map(|src|{ - cell.set_symbol(src.symbol()); - cell.set_fg(src.fg); - }); - } - }); - Ok(())//Some(area)) - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -struct SequenceCursor<'a>(&'a Sequencer); -impl<'a> Widget for SequenceCursor<'a> { - type Engine = Tui; - fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - Ok(Some([1,1])) - } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { - let area = to.area(); - if let (Some(time), Some(note)) = (self.0.time_axis.point, self.0.note_axis.point) { - let x = area.x() + Sequencer::H_KEYS_OFFSET as u16 + time as u16; - let y = area.y() + 1 + note as u16 / 2; - let c = if note % 2 == 0 { "▀" } else { "▄" }; - to.blit(&c, x, y, self.0.style_focus()); - Ok(()) - } else { - //Ok(Some([0,0,0,0])) - Ok(()) - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -struct SequenceZoom<'a>(&'a Sequencer); -impl<'a> Widget for SequenceZoom<'a> { - type Engine = Tui; - fn layout (&self, _to: [u16;2]) -> Perhaps<[u16;2]> { - Ok(Some([10,1])) - } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { - let area = to.area(); - let quant = ppq_to_name(self.0.time_axis.scale); - let quant_x = area.x() + area.w() - 1 - quant.len() as u16; - let quant_y = area.y() + area.h() - 2; - to.blit(&quant, quant_x, quant_y, self.0.style_focus()); - Ok(()) - } -} - ////////////////////////////////////////////////////////////////////////////////////////////////// struct SequenceTimer<'a>(&'a Sequencer, Arc>);