mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip: "multiple cascading refactors"
https://loglog.games/blog/leaving-rust-gamedev/#orphan-rule-should-be-optional is on point
This commit is contained in:
parent
20afc397ea
commit
fa8282a9d5
18 changed files with 175 additions and 222 deletions
|
|
@ -6,7 +6,7 @@ pub trait App<T: Engine> {
|
|||
}
|
||||
|
||||
/// Platform backend.
|
||||
pub trait Engine: Sized {
|
||||
pub trait Engine: Send + Sync + Sized {
|
||||
fn setup (&mut self) -> Usually<()> { Ok(()) }
|
||||
fn exited (&self) -> bool;
|
||||
fn teardown (&mut self) -> Usually<()> { Ok(()) }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ pub use once_cell::sync::Lazy;
|
|||
pub use std::sync::atomic::{Ordering, AtomicBool};
|
||||
pub use std::rc::Rc;
|
||||
pub use std::cell::RefCell;
|
||||
pub use std::marker::PhantomData;
|
||||
pub(crate) use std::error::Error;
|
||||
pub(crate) use std::io::{stdout};
|
||||
pub(crate) use std::thread::{spawn, JoinHandle};
|
||||
|
|
|
|||
|
|
@ -30,12 +30,13 @@ impl<E: Engine> Process for Mixer<E> {
|
|||
Control::Continue
|
||||
}
|
||||
}
|
||||
impl Render<Tui> for Mixer<Tui> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
impl Content for Mixer<Tui> {
|
||||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
let mut tracks = Split::right();
|
||||
for channel in self.tracks.iter() {
|
||||
tracks = tracks.add_ref(channel)
|
||||
}
|
||||
tracks.render(to)
|
||||
tracks
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
use crate::*;
|
||||
use tek_core::Direction;
|
||||
|
||||
impl Layout<Tui> for Track<Tui> {
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl Render<Tui> for Track<Tui> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
impl Content for Track<Tui> {
|
||||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
TrackView {
|
||||
chain: Some(&self),
|
||||
direction: tek_core::Direction::Right,
|
||||
|
|
@ -26,7 +22,7 @@ impl Render<Tui> for Track<Tui> {
|
|||
//pub output_ports: Vec<Port<AudioOut>>,
|
||||
//pub post_fader_meter: f64,
|
||||
//pub route: String,
|
||||
}.render(to)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct TrackView<'a, E: Engine> {
|
||||
|
|
@ -35,7 +31,11 @@ pub struct TrackView<'a, E: Engine> {
|
|||
pub focused: bool,
|
||||
pub entered: bool,
|
||||
}
|
||||
impl<'a> Render<Tui> for TrackView<'a, Tui> {
|
||||
impl<'a> Widget for TrackView<'a, Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let mut area = to.area();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pub struct Arranger<E: Engine> {
|
|||
/// Name of arranger
|
||||
pub name: Arc<RwLock<String>>,
|
||||
/// Collection of tracks.
|
||||
pub tracks: Vec<Sequencer>,
|
||||
pub tracks: Vec<Sequencer<E>>,
|
||||
/// Collection of scenes.
|
||||
pub scenes: Vec<Scene>,
|
||||
/// Currently selected element.
|
||||
|
|
@ -45,12 +45,12 @@ impl<E: Engine> Arranger<E> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn sequencer (&self) -> Option<&Sequencer> {
|
||||
pub fn sequencer (&self) -> Option<&Sequencer<E>> {
|
||||
self.selected.track()
|
||||
.map(|track|self.tracks.get(track))
|
||||
.flatten()
|
||||
}
|
||||
pub fn sequencer_mut (&mut self) -> Option<&mut Sequencer> {
|
||||
pub fn sequencer_mut (&mut self) -> Option<&mut Sequencer<E>> {
|
||||
self.selected.track()
|
||||
.map(|track|self.tracks.get_mut(track))
|
||||
.flatten()
|
||||
|
|
@ -99,13 +99,11 @@ impl ArrangerViewMode {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl Layout<Tui> for Arranger<Tui> {
|
||||
impl Widget for Arranger<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
/// Render arranger to terminal
|
||||
impl Render<Tui> for Arranger<Tui> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = (|to|match self.mode {
|
||||
ArrangerViewMode::Horizontal =>
|
||||
|
|
|
|||
|
|
@ -13,16 +13,18 @@ impl Arranger<Tui> {
|
|||
}
|
||||
}
|
||||
/// Appears on first run (i.e. if state dir is missing).
|
||||
pub struct ArrangerRenameModal {
|
||||
pub struct ArrangerRenameModal<E: Engine> {
|
||||
_engine: std::marker::PhantomData<E>,
|
||||
done: bool,
|
||||
target: ArrangerFocus,
|
||||
value: String,
|
||||
result: Arc<RwLock<String>>,
|
||||
cursor: usize
|
||||
}
|
||||
impl ArrangerRenameModal {
|
||||
impl<E: Engine> ArrangerRenameModal<E> {
|
||||
pub fn new (target: ArrangerFocus, value: &Arc<RwLock<String>>) -> Self {
|
||||
Self {
|
||||
_engine: Default::default(),
|
||||
done: false,
|
||||
target,
|
||||
value: value.read().unwrap().clone(),
|
||||
|
|
@ -31,7 +33,11 @@ impl ArrangerRenameModal {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl Render<Tui> for ArrangerRenameModal {
|
||||
impl Widget for ArrangerRenameModal<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let y = area.y() + area.h() / 2;
|
||||
|
|
@ -53,7 +59,7 @@ impl Render<Tui> for ArrangerRenameModal {
|
|||
Ok(Some(area))
|
||||
}
|
||||
}
|
||||
impl Handle<Tui> for ArrangerRenameModal {
|
||||
impl Handle<Tui> for ArrangerRenameModal<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
match from.event() {
|
||||
TuiEvent::Input(Event::Key(k)) => {
|
||||
|
|
@ -91,7 +97,7 @@ impl Handle<Tui> for ArrangerRenameModal {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl Exit for ArrangerRenameModal {
|
||||
impl<E: Engine + Send> Exit for ArrangerRenameModal<E> {
|
||||
fn exited (&self) -> bool {
|
||||
self.done
|
||||
}
|
||||
|
|
@ -99,8 +105,3 @@ impl Exit for ArrangerRenameModal {
|
|||
self.done = true
|
||||
}
|
||||
}
|
||||
impl Layout<Tui> for ArrangerRenameModal {
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ use super::Arranger;
|
|||
|
||||
/// Track management methods
|
||||
impl<E: Engine> Arranger<E> {
|
||||
pub fn track (&self) -> Option<&Sequencer> {
|
||||
pub fn track (&self) -> Option<&Sequencer<E>> {
|
||||
self.selected.track().map(|t|self.tracks.get(t)).flatten()
|
||||
}
|
||||
pub fn track_mut (&mut self) -> Option<&mut Sequencer> {
|
||||
pub fn track_mut (&mut self) -> Option<&mut Sequencer<E>> {
|
||||
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
|
||||
}
|
||||
pub fn track_next (&mut self) {
|
||||
|
|
@ -16,7 +16,7 @@ impl<E: Engine> Arranger<E> {
|
|||
pub fn track_prev (&mut self) {
|
||||
self.selected.track_prev()
|
||||
}
|
||||
pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut Sequencer> {
|
||||
pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut Sequencer<E>> {
|
||||
self.tracks.push(name.map_or_else(
|
||||
|| Sequencer::new(&self.track_default_name()),
|
||||
|name| Sequencer::new(name),
|
||||
|
|
@ -32,13 +32,13 @@ impl<E: Engine> Arranger<E> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn track_name_max_len (tracks: &[Sequencer]) -> usize {
|
||||
pub fn track_name_max_len <E: Engine> (tracks: &[Sequencer<E>]) -> usize {
|
||||
tracks.iter()
|
||||
.map(|s|s.name.read().unwrap().len())
|
||||
.fold(0, usize::max)
|
||||
}
|
||||
|
||||
pub fn track_clip_name_lengths (tracks: &[Sequencer]) -> Vec<(usize, usize)> {
|
||||
pub fn track_clip_name_lengths <E: Engine> (tracks: &[Sequencer<E>]) -> Vec<(usize, usize)> {
|
||||
let mut total = 0;
|
||||
let mut lengths: Vec<(usize, usize)> = tracks.iter().map(|track|{
|
||||
let len = 4 + track.phrases
|
||||
|
|
|
|||
|
|
@ -17,15 +17,13 @@ pub fn draw (state: &Arranger<Tui>, to: &mut Tui) -> Perhaps<[u16;4]> {
|
|||
]).render(to.with_rect(area))
|
||||
}
|
||||
|
||||
struct TrackNameColumn<'a>(&'a [Sequencer], ArrangerFocus);
|
||||
struct TrackNameColumn<'a>(&'a [Sequencer<Tui>], ArrangerFocus);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackNameColumn<'a> {
|
||||
impl<'a> Widget for TrackNameColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackNameColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let Self(tracks, selected) = self;
|
||||
|
|
@ -51,15 +49,13 @@ impl<'a> Render<Tui> for TrackNameColumn<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TrackMonitorColumn<'a>(&'a [Sequencer]);
|
||||
struct TrackMonitorColumn<'a>(&'a [Sequencer<Tui>]);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackMonitorColumn<'a> {
|
||||
impl<'a> Widget for TrackMonitorColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackMonitorColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let Self(tracks) = self;
|
||||
|
|
@ -86,15 +82,13 @@ impl<'a> Render<Tui> for TrackMonitorColumn<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TrackRecordColumn<'a>(&'a [Sequencer]);
|
||||
struct TrackRecordColumn<'a>(&'a [Sequencer<Tui>]);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackRecordColumn<'a> {
|
||||
impl<'a> Widget for TrackRecordColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackRecordColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let Self(tracks) = self;
|
||||
|
|
@ -121,15 +115,13 @@ impl<'a> Render<Tui> for TrackRecordColumn<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TrackOverdubColumn<'a>(&'a [Sequencer]);
|
||||
struct TrackOverdubColumn<'a>(&'a [Sequencer<Tui>]);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackOverdubColumn<'a> {
|
||||
impl<'a> Widget for TrackOverdubColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackOverdubColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let Self(tracks) = self;
|
||||
|
|
@ -159,15 +151,13 @@ impl<'a> Render<Tui> for TrackOverdubColumn<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TrackEraseColumn<'a>(&'a [Sequencer]);
|
||||
struct TrackEraseColumn<'a>(&'a [Sequencer<Tui>]);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackEraseColumn<'a> {
|
||||
impl<'a> Widget for TrackEraseColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackEraseColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let Self(tracks) = self;
|
||||
|
|
@ -192,15 +182,13 @@ impl<'a> Render<Tui> for TrackEraseColumn<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TrackGainColumn<'a>(&'a [Sequencer]);
|
||||
struct TrackGainColumn<'a>(&'a [Sequencer<Tui>]);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackGainColumn<'a> {
|
||||
impl<'a> Widget for TrackGainColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackGainColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
todo!();
|
||||
//let Self(tracks) = self;
|
||||
|
|
@ -225,15 +213,13 @@ impl<'a> Render<Tui> for TrackGainColumn<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TrackScenesColumn<'a>(&'a [Sequencer], &'a [Scene], ArrangerFocus);
|
||||
struct TrackScenesColumn<'a>(&'a [Sequencer<Tui>], &'a [Scene], ArrangerFocus);
|
||||
|
||||
impl<'a> Layout<Tui> for TrackScenesColumn<'a> {
|
||||
impl<'a> Widget for TrackScenesColumn<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TrackScenesColumn<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let Self(tracks, scenes, selected) = self;
|
||||
let area = to.area();
|
||||
|
|
|
|||
|
|
@ -51,13 +51,11 @@ pub fn draw <'a, 'b> (
|
|||
|
||||
struct ColumnSeparators<'a>(u16, &'a [(usize, usize)]);
|
||||
|
||||
impl<'a> Layout<Tui> for ColumnSeparators<'a> {
|
||||
impl<'a> Widget for ColumnSeparators<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for ColumnSeparators<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(offset, cols) = self;
|
||||
|
|
@ -74,13 +72,11 @@ impl<'a> Render<Tui> for ColumnSeparators<'a> {
|
|||
|
||||
struct RowSeparators<'a>(&'a [(usize, usize)]);
|
||||
|
||||
impl<'a> Layout<Tui> for RowSeparators<'a> {
|
||||
impl<'a> Widget for RowSeparators<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for RowSeparators<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(rows) = self;
|
||||
|
|
@ -103,13 +99,11 @@ struct CursorFocus<'a>(
|
|||
ArrangerFocus, u16, &'a [(usize, usize)], &'a [(usize, usize)]
|
||||
);
|
||||
|
||||
impl<'a> Layout<Tui> for CursorFocus<'a> {
|
||||
impl<'a> Widget for CursorFocus<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for CursorFocus<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(selected, offset, cols, rows) = *self;
|
||||
|
|
@ -173,15 +167,13 @@ impl<'a> Render<Tui> for CursorFocus<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer]);
|
||||
struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer<Tui>]);
|
||||
|
||||
impl<'a> Layout<Tui> for TracksHeader<'a> {
|
||||
impl<'a> Widget for TracksHeader<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for TracksHeader<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(offset, track_cols, tracks) = *self;
|
||||
|
|
@ -199,15 +191,13 @@ impl<'a> Render<Tui> for TracksHeader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer], &'a[Scene]);
|
||||
struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer<Tui>], &'a[Scene]);
|
||||
|
||||
impl<'a> Layout<Tui> for SceneRows<'a> {
|
||||
impl<'a> Widget for SceneRows<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SceneRows<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(offset, track_cols, scene_rows, tracks, scenes) = *self;
|
||||
|
|
@ -234,15 +224,13 @@ impl<'a> Render<Tui> for SceneRows<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SceneRow<'a>(&'a[Sequencer], &'a Scene, &'a[(usize, usize)], u16);
|
||||
struct SceneRow<'a>(&'a[Sequencer<Tui>], &'a Scene, &'a[(usize, usize)], u16);
|
||||
|
||||
impl<'a> Layout<Tui> for SceneRow<'a> {
|
||||
impl<'a> Widget for SceneRow<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SceneRow<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(tracks, scene, track_cols, offset) = self;
|
||||
|
|
@ -266,15 +254,13 @@ impl<'a> Render<Tui> for SceneRow<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SceneClip<'a>(&'a Sequencer, usize);
|
||||
struct SceneClip<'a>(&'a Sequencer<Tui>, usize);
|
||||
|
||||
impl<'a> Layout<Tui> for SceneClip<'a> {
|
||||
impl<'a> Widget for SceneClip<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SceneClip<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let Self(track, clip) = self;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl Scene {
|
|||
Self { name, clips, }
|
||||
}
|
||||
/// Returns the pulse length of the longest phrase in the scene
|
||||
pub fn pulses (&self, tracks: &[Sequencer]) -> usize {
|
||||
pub fn pulses <E: Engine> (&self, tracks: &[Sequencer<E>]) -> usize {
|
||||
self.clips.iter().enumerate()
|
||||
.filter_map(|(i, c)|c
|
||||
.map(|c|tracks
|
||||
|
|
@ -50,7 +50,7 @@ impl Scene {
|
|||
.fold(0, |a, p|a.max(p.read().unwrap().length))
|
||||
}
|
||||
/// Returns true if all phrases in the scene are currently playing
|
||||
pub fn is_playing (&self, tracks: &[Sequencer]) -> bool {
|
||||
pub fn is_playing <E: Engine> (&self, tracks: &[Sequencer<E>]) -> bool {
|
||||
self.clips.iter().enumerate()
|
||||
.all(|(track_index, phrase_index)|match phrase_index {
|
||||
Some(i) => tracks
|
||||
|
|
@ -68,7 +68,10 @@ pub fn scene_name_max_len (scenes: &[Scene]) -> usize {
|
|||
.fold(0, usize::max)
|
||||
}
|
||||
|
||||
pub fn scene_ppqs (tracks: &[Sequencer], scenes: &[Scene]) -> Vec<(usize, usize)> {
|
||||
pub fn scene_ppqs <E: Engine> (
|
||||
tracks: &[Sequencer<E>],
|
||||
scenes: &[Scene]
|
||||
) -> Vec<(usize, usize)> {
|
||||
let mut total = 0;
|
||||
let mut scenes: Vec<(usize, usize)> = scenes.iter().map(|scene|{
|
||||
let pulses = scene.pulses(tracks).max(96);
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ use crate::*;
|
|||
use tek_core::Direction;
|
||||
|
||||
/// Phrase editor.
|
||||
pub struct Sequencer {
|
||||
pub struct Sequencer<E: Engine> {
|
||||
pub name: Arc<RwLock<String>>,
|
||||
pub mode: bool,
|
||||
pub focused: bool,
|
||||
pub entered: bool,
|
||||
|
||||
pub phrase: Option<Arc<RwLock<Phrase>>>,
|
||||
pub transport: Option<Arc<RwLock<TransportToolbar>>>,
|
||||
pub transport: Option<Arc<RwLock<TransportToolbar<E>>>>,
|
||||
pub buffer: BigBuffer,
|
||||
pub keys: Buffer,
|
||||
/// Highlight input keys
|
||||
|
|
@ -43,7 +43,7 @@ pub struct Sequencer {
|
|||
pub notes_out: [bool;128],
|
||||
}
|
||||
|
||||
impl Sequencer {
|
||||
impl<E: Engine> Sequencer<E> {
|
||||
pub fn new (name: &str) -> Self {
|
||||
Self {
|
||||
name: Arc::new(RwLock::new(name.into())),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub struct SequencerCli {
|
|||
#[arg(short, long)] transport: Option<bool>
|
||||
}
|
||||
|
||||
impl Sequencer {
|
||||
impl Sequencer<Tui> {
|
||||
pub fn from_args () -> Self {
|
||||
let args = SequencerCli::parse();
|
||||
let mut seq = Self::new("");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::*;
|
||||
|
||||
impl Handle<Tui> for Sequencer {
|
||||
impl Handle<Tui> for Sequencer<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
match from.event() {
|
||||
// NONE, "seq_cursor_up", "move cursor up", |sequencer: &mut Sequencer| {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::*;
|
||||
|
||||
impl Layout<Tui> for Sequencer {
|
||||
impl Widget for Sequencer<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl<'a> Render<Tui> for Sequencer {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
self.horizontal_draw(to)?;
|
||||
if self.focused && self.entered {
|
||||
|
|
@ -15,7 +14,7 @@ impl<'a> Render<Tui> for Sequencer {
|
|||
}
|
||||
}
|
||||
|
||||
impl Sequencer {
|
||||
impl<E: Engine> Sequencer<E> {
|
||||
/// Select which pattern to display. This pre-renders it to the buffer at full resolution.
|
||||
pub fn show (&mut self, phrase: Option<&Arc<RwLock<Phrase>>>) -> Usually<()> {
|
||||
self.phrase = phrase.map(Clone::clone);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::*;
|
||||
|
||||
impl Sequencer {
|
||||
impl Sequencer<Tui> {
|
||||
|
||||
const H_KEYS_OFFSET: usize = 5;
|
||||
|
||||
|
|
@ -43,15 +43,13 @@ const STYLE_VALUE: Option<Style> = Some(Style {
|
|||
sub_modifier: Modifier::DIM,
|
||||
});
|
||||
|
||||
struct SequenceName<'a>(&'a Sequencer);
|
||||
struct SequenceName<'a>(&'a Sequencer<Tui>);
|
||||
|
||||
impl<'a> Layout<Tui> for SequenceName<'a> {
|
||||
impl<'a> Widget for SequenceName<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceName<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = to.area();
|
||||
let frame = [x, y, 10, 4];
|
||||
|
|
@ -64,13 +62,11 @@ impl<'a> Render<Tui> for SequenceName<'a> {
|
|||
|
||||
struct SequenceRange;
|
||||
|
||||
impl Layout<Tui> for SequenceRange {
|
||||
impl Widget for SequenceRange {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceRange {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = to.area();
|
||||
let frame = [x, y, 10, 6];
|
||||
|
|
@ -85,13 +81,11 @@ impl<'a> Render<Tui> for SequenceRange {
|
|||
|
||||
struct SequenceLoopRange;
|
||||
|
||||
impl Layout<Tui> for SequenceLoopRange {
|
||||
impl Widget for SequenceLoopRange {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceLoopRange {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = to.area();
|
||||
let range = [x, y, 10, 7];
|
||||
|
|
@ -107,13 +101,11 @@ impl<'a> Render<Tui> for SequenceLoopRange {
|
|||
|
||||
struct SequenceNoteRange;
|
||||
|
||||
impl Layout<Tui> for SequenceNoteRange {
|
||||
impl Widget for SequenceNoteRange {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceNoteRange {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = to.area();
|
||||
let range = [x, y, 10, 9];
|
||||
|
|
@ -129,15 +121,13 @@ impl<'a> Render<Tui> for SequenceNoteRange {
|
|||
}
|
||||
}
|
||||
|
||||
struct SequenceKeys<'a>(&'a Sequencer);
|
||||
struct SequenceKeys<'a>(&'a Sequencer<Tui>);
|
||||
|
||||
impl<'a> Layout<Tui> for SequenceKeys<'a> {
|
||||
impl<'a> Widget for SequenceKeys<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceKeys<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
if area.h() < 2 {
|
||||
|
|
@ -154,15 +144,13 @@ impl<'a> Render<Tui> for SequenceKeys<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SequenceNotes<'a>(&'a Sequencer);
|
||||
struct SequenceNotes<'a>(&'a Sequencer<Tui>);
|
||||
|
||||
impl<'a> Layout<Tui> for SequenceNotes<'a> {
|
||||
impl<'a> Widget for SequenceNotes<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceNotes<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
if area.h() < 2 {
|
||||
|
|
@ -189,15 +177,13 @@ impl<'a> Render<Tui> for SequenceNotes<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SequenceCursor<'a>(&'a Sequencer);
|
||||
struct SequenceCursor<'a>(&'a Sequencer<Tui>);
|
||||
|
||||
impl<'a> Layout<Tui> for SequenceCursor<'a> {
|
||||
impl<'a> Widget for SequenceCursor<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceCursor<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
if let (Some(time), Some(note)) = (self.0.time_axis.point, self.0.note_axis.point) {
|
||||
|
|
@ -211,15 +197,13 @@ impl<'a> Render<Tui> for SequenceCursor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SequenceZoom<'a>(&'a Sequencer);
|
||||
struct SequenceZoom<'a>(&'a Sequencer<Tui>);
|
||||
|
||||
impl<'a> Layout<Tui> for SequenceZoom<'a> {
|
||||
impl<'a> Widget for SequenceZoom<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceZoom<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let quant = ppq_to_name(self.0.time_axis.scale);
|
||||
|
|
@ -229,15 +213,13 @@ impl<'a> Render<Tui> for SequenceZoom<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SequenceTimer<'a>(&'a Sequencer, Arc<RwLock<Phrase>>);
|
||||
struct SequenceTimer<'a>(&'a Sequencer<Tui>, Arc<RwLock<Phrase>>);
|
||||
|
||||
impl<'a> Layout<Tui> for SequenceTimer<'a> {
|
||||
impl<'a> Widget for SequenceTimer<'a> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Render<Tui> for SequenceTimer<'a> {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let phrase = self.1.read().unwrap();
|
||||
|
|
@ -250,7 +232,7 @@ impl<'a> Render<Tui> for SequenceTimer<'a> {
|
|||
for x in x2..x3 {
|
||||
let step = (time0 + x2) * time_z;
|
||||
let next_step = (time0 + x2 + 1) * time_z;
|
||||
let style = Sequencer::style_timer_step(now, step as usize, next_step as usize);
|
||||
let style = Sequencer::<Tui>::style_timer_step(now, step as usize, next_step as usize);
|
||||
to.blit(&"-", x as u16, area.y(), Some(style))?;
|
||||
}
|
||||
return Ok(Some([area.x(), area.y(), area.w(), 1]))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::*;
|
||||
|
||||
/// Stores and displays time-related state.
|
||||
pub struct TransportToolbar {
|
||||
pub struct TransportToolbar<E: Engine> {
|
||||
/// Enable metronome?
|
||||
pub metronome: bool,
|
||||
/// Current sample rate, tempo, and PPQ.
|
||||
|
|
@ -16,13 +16,13 @@ pub struct TransportToolbar {
|
|||
|
||||
pub focused: bool,
|
||||
pub focus: usize,
|
||||
pub playing: TransportPlayPauseButton,
|
||||
pub bpm: TransportBPM,
|
||||
pub quant: TransportQuantize,
|
||||
pub sync: TransportSync,
|
||||
pub clock: TransportClock,
|
||||
pub playing: TransportPlayPauseButton<E>,
|
||||
pub bpm: TransportBPM<E>,
|
||||
pub quant: TransportQuantize<E>,
|
||||
pub sync: TransportSync<E>,
|
||||
pub clock: TransportClock<E>,
|
||||
}
|
||||
impl TransportToolbar {
|
||||
impl<E: Engine> TransportToolbar<E> {
|
||||
pub fn standalone () -> Usually<Arc<RwLock<Self>>> {
|
||||
let mut transport = Self::new(None);
|
||||
transport.focused = true;
|
||||
|
|
@ -34,7 +34,7 @@ impl TransportToolbar {
|
|||
transport.write().unwrap().jack = Some(
|
||||
jack.activate(
|
||||
&transport.clone(),
|
||||
|state: &Arc<RwLock<TransportToolbar>>, client, scope| {
|
||||
|state: &Arc<RwLock<TransportToolbar<E>>>, client, scope| {
|
||||
state.write().unwrap().process(client, scope)
|
||||
}
|
||||
)?
|
||||
|
|
@ -48,22 +48,27 @@ impl TransportToolbar {
|
|||
focus: 0,
|
||||
|
||||
playing: TransportPlayPauseButton {
|
||||
_engine: Default::default(),
|
||||
value: Some(TransportState::Stopped),
|
||||
focused: true
|
||||
},
|
||||
bpm: TransportBPM {
|
||||
_engine: Default::default(),
|
||||
value: timebase.bpm(),
|
||||
focused: false
|
||||
},
|
||||
quant: TransportQuantize {
|
||||
_engine: Default::default(),
|
||||
value: 24,
|
||||
focused: false
|
||||
},
|
||||
sync: TransportSync {
|
||||
_engine: Default::default(),
|
||||
value: timebase.ppq() as usize * 4,
|
||||
focused: false
|
||||
},
|
||||
clock: TransportClock {
|
||||
_engine: Default::default(),
|
||||
frame: 0,
|
||||
pulse: 0,
|
||||
ppq: 0,
|
||||
|
|
@ -142,7 +147,7 @@ impl TransportToolbar {
|
|||
self.timebase.frame_to_usec(self.clock.frame as f64) as usize
|
||||
}
|
||||
}
|
||||
impl Focus<5, Tui> for TransportToolbar {
|
||||
impl Focus<5, Tui> for TransportToolbar<Tui> {
|
||||
fn focus (&self) -> usize {
|
||||
self.focus
|
||||
}
|
||||
|
|
@ -168,7 +173,7 @@ impl Focus<5, Tui> for TransportToolbar {
|
|||
]
|
||||
}
|
||||
}
|
||||
impl Focusable<Tui> for TransportToolbar {
|
||||
impl Focusable<Tui> for TransportToolbar<Tui> {
|
||||
fn is_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
|
|
@ -176,16 +181,19 @@ impl Focusable<Tui> for TransportToolbar {
|
|||
self.focused = focused
|
||||
}
|
||||
}
|
||||
process!(TransportToolbar |self, _client, scope| {
|
||||
self.update(&scope);
|
||||
Control::Continue
|
||||
});
|
||||
impl<E: Engine> Process for TransportToolbar<E> {
|
||||
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
|
||||
self.update(&scope);
|
||||
Control::Continue
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransportPlayPauseButton {
|
||||
pub struct TransportPlayPauseButton<E: Engine> {
|
||||
pub _engine: PhantomData<E>,
|
||||
pub value: Option<TransportState>,
|
||||
pub focused: bool
|
||||
}
|
||||
impl Focusable<Tui> for TransportPlayPauseButton {
|
||||
impl Focusable<Tui> for TransportPlayPauseButton<Tui> {
|
||||
fn is_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
|
|
@ -194,11 +202,12 @@ impl Focusable<Tui> for TransportPlayPauseButton {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TransportBPM {
|
||||
pub struct TransportBPM<E: Engine> {
|
||||
pub _engine: PhantomData<E>,
|
||||
pub value: f64,
|
||||
pub focused: bool
|
||||
}
|
||||
impl Focusable<Tui> for TransportBPM {
|
||||
impl Focusable<Tui> for TransportBPM<Tui> {
|
||||
fn is_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
|
|
@ -207,11 +216,12 @@ impl Focusable<Tui> for TransportBPM {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TransportQuantize {
|
||||
pub struct TransportQuantize<E: Engine> {
|
||||
pub _engine: PhantomData<E>,
|
||||
pub value: usize,
|
||||
pub focused: bool
|
||||
}
|
||||
impl Focusable<Tui> for TransportQuantize {
|
||||
impl Focusable<Tui> for TransportQuantize<Tui> {
|
||||
fn is_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
|
|
@ -220,11 +230,12 @@ impl Focusable<Tui> for TransportQuantize {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TransportSync {
|
||||
pub struct TransportSync<E: Engine> {
|
||||
pub _engine: PhantomData<E>,
|
||||
pub value: usize,
|
||||
pub focused: bool
|
||||
}
|
||||
impl Focusable<Tui> for TransportSync {
|
||||
impl Focusable<Tui> for TransportSync<Tui> {
|
||||
fn is_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
|
|
@ -233,14 +244,15 @@ impl Focusable<Tui> for TransportSync {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TransportClock {
|
||||
pub struct TransportClock<E: Engine> {
|
||||
pub _engine: PhantomData<E>,
|
||||
pub frame: usize,
|
||||
pub pulse: usize,
|
||||
pub ppq: usize,
|
||||
pub usecs: usize,
|
||||
pub focused: bool,
|
||||
}
|
||||
impl Focusable<Tui> for TransportClock {
|
||||
impl Focusable<Tui> for TransportClock<Tui> {
|
||||
fn is_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::*;
|
||||
|
||||
impl Handle<Tui> for TransportToolbar {
|
||||
impl Handle<Tui> for TransportToolbar<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
Ok(None)
|
||||
//Ok(
|
||||
|
|
@ -13,13 +13,13 @@ impl Handle<Tui> for TransportToolbar {
|
|||
}
|
||||
}
|
||||
|
||||
impl Handle<Tui> for TransportPlayPauseButton {
|
||||
impl Handle<Tui> for TransportPlayPauseButton<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handle<Tui> for TransportBPM {
|
||||
impl Handle<Tui> for TransportBPM<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
//TransportFocus::BPM => {
|
||||
//transport.timebase.bpm.fetch_add(1.0, Ordering::Relaxed);
|
||||
|
|
@ -31,7 +31,7 @@ impl Handle<Tui> for TransportBPM {
|
|||
}
|
||||
}
|
||||
|
||||
impl Handle<Tui> for TransportQuantize {
|
||||
impl Handle<Tui> for TransportQuantize<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
//TransportFocus::Quant => {
|
||||
//transport.quant.value = next_note_length(transport.quant)
|
||||
|
|
@ -43,7 +43,7 @@ impl Handle<Tui> for TransportQuantize {
|
|||
}
|
||||
}
|
||||
|
||||
impl Handle<Tui> for TransportSync {
|
||||
impl Handle<Tui> for TransportSync<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
//TransportFocus::Sync => {
|
||||
//transport.sync.value = next_note_length(transport.sync)
|
||||
|
|
@ -55,7 +55,7 @@ impl Handle<Tui> for TransportSync {
|
|||
}
|
||||
}
|
||||
|
||||
impl Handle<Tui> for TransportClock {
|
||||
impl Handle<Tui> for TransportClock<Tui> {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
//TransportFocus::Sync => {
|
||||
//transport.sync.value = next_note_length(transport.sync)
|
||||
|
|
|
|||
|
|
@ -2,34 +2,26 @@ use crate::*;
|
|||
|
||||
const CORNERS: Corners = Corners(NOT_DIM_GREEN);
|
||||
|
||||
impl Layout<Tui> for TransportToolbar {
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
Ok(Some([area.x(), area.y(), area.w(), 2]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for TransportToolbar {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
impl Content for TransportToolbar<Tui> {
|
||||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
Split::right()
|
||||
.add_ref(&self.playing)
|
||||
.add_ref(&self.bpm)
|
||||
.add_ref(&self.quant)
|
||||
.add_ref(&self.sync)
|
||||
.add_ref(&self.clock)
|
||||
.render(to.with_rect(self.layout(to.area())?.unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Layout<Tui> for TransportPlayPauseButton {
|
||||
impl Widget for TransportPlayPauseButton<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
area.expect_min(10, 1)?;
|
||||
Ok(Some([area.x(), area.y(), 10, 1]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for TransportPlayPauseButton {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let Self { value, focused } = &self;
|
||||
let Self { value, focused, .. } = &self;
|
||||
Layers(&[
|
||||
&focused.then_some(CORNERS),
|
||||
&Inset::W(1, Styled(match value {
|
||||
|
|
@ -70,18 +62,16 @@ impl Render<Tui> for TransportPlayPauseButton {
|
|||
}
|
||||
}
|
||||
|
||||
impl Layout<Tui> for TransportBPM {
|
||||
impl Widget for TransportBPM<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
area.expect_min(10, 1)?;
|
||||
Ok(Some([area.x(), area.y(), 10, 1]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for TransportBPM {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let area = to.area();
|
||||
let [x, y, ..] = area;
|
||||
let Self { value, focused } = self;
|
||||
let Self { value, focused, .. } = self;
|
||||
to.blit(&"BPM", x, y, Some(NOT_DIM))?;
|
||||
let bpm = format!("{}.{:03}", value, (value * 1000.0) % 1000.0);
|
||||
to.blit(&bpm, x, y + 1, Some(NOT_DIM_BOLD))?;
|
||||
|
|
@ -96,17 +86,15 @@ impl Render<Tui> for TransportBPM {
|
|||
}
|
||||
}
|
||||
|
||||
impl Layout<Tui> for TransportQuantize {
|
||||
impl Widget for TransportQuantize<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
area.expect_min(10, 1)?;
|
||||
Ok(Some([area.x(), area.y(), 10, 1]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for TransportQuantize {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = to.area();
|
||||
let Self { value, focused } = self;
|
||||
let Self { value, focused, .. } = self;
|
||||
to.blit(&"QUANT", x, y, Some(NOT_DIM))?;
|
||||
let name = ppq_to_name(*value as usize);
|
||||
let width = name.len() as u16;
|
||||
|
|
@ -121,17 +109,15 @@ impl Render<Tui> for TransportQuantize {
|
|||
}
|
||||
}
|
||||
|
||||
impl Layout<Tui> for TransportSync {
|
||||
impl Widget for TransportSync<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
area.expect_min(10, 1)?;
|
||||
Ok(Some([area.x(), area.y(), 10, 1]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for TransportSync {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = to.area();
|
||||
let Self { value, focused } = self;
|
||||
let Self { value, focused, .. } = self;
|
||||
to.blit(&"SYNC", x, y, Some(NOT_DIM))?;
|
||||
let name = ppq_to_name(*value as usize);
|
||||
let width = name.len() as u16;
|
||||
|
|
@ -146,17 +132,15 @@ impl Render<Tui> for TransportSync {
|
|||
}
|
||||
}
|
||||
|
||||
impl Layout<Tui> for TransportClock {
|
||||
impl Widget for TransportClock<Tui> {
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
area.expect_min(10, 1)?;
|
||||
Ok(Some([area.x(), area.y(), 20, 1]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for TransportClock {
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let [x, y, width, _] = to.area();
|
||||
let Self { frame: _frame, pulse, ppq, usecs, focused } = self;
|
||||
let Self { frame: _frame, pulse, ppq, usecs, focused, .. } = self;
|
||||
let (beats, pulses) = if *ppq > 0 { (pulse / ppq, pulse % ppq) } else { (0, 0) };
|
||||
let (bars, beats) = ((beats / 4) + 1, (beats % 4) + 1);
|
||||
let (seconds, msecs) = (usecs / 1000000, usecs / 1000 % 1000);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue