wip: "multiple cascading refactors"

https://loglog.games/blog/leaving-rust-gamedev/#orphan-rule-should-be-optional is on point
This commit is contained in:
🪞👃🪞 2024-09-09 21:25:04 +03:00
parent 20afc397ea
commit fa8282a9d5
18 changed files with 175 additions and 222 deletions

View file

@ -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(()) }

View file

@ -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};

View file

@ -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
}
}

View file

@ -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();

View file

@ -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 =>

View file

@ -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!()
}
}

View file

@ -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

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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())),

View file

@ -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("");

View file

@ -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| {

View file

@ -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);

View file

@ -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]))

View file

@ -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| {
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
}

View file

@ -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)

View file

@ -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);