wip: refactor pt.10, 165 errors

This commit is contained in:
🪞👃🪞 2024-11-10 19:58:16 +01:00
parent 1405b82341
commit 355b34c738
9 changed files with 96 additions and 204 deletions

View file

@ -117,4 +117,37 @@ impl ArrangementScene {
//clips, //clips,
//}) //})
//} //}
pub fn ppqs (scenes: &[Self], factor: usize) -> Vec<(usize, usize)> {
let mut total = 0;
if factor == 0 {
scenes.iter().map(|scene|{
let pulses = scene.pulses().max(PPQ);
total = total + pulses;
(pulses, total - pulses)
}).collect()
} else {
(0..=scenes.len()).map(|i|{
(factor*PPQ, factor*PPQ*i)
}).collect()
}
}
pub fn longest_name (scenes: &[Self]) -> usize {
scenes.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
}
}
impl ArrangementTrack {
pub fn longest_name (tracks: &[Self]) -> usize {
tracks.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
}
pub const MIN_WIDTH: usize = 3;
pub fn width_inc (&mut self) {
self.width += 1;
}
pub fn width_dec (&mut self) {
if self.width > Self::MIN_WIDTH {
self.width -= 1;
}
}
} }

View file

@ -41,8 +41,8 @@ submod! {
tui_pool_length tui_pool_length
tui_pool_rename tui_pool_rename
tui_sampler //tui_sampler // TODO
tui_sampler_cmd //tui_sampler_cmd
tui_sequencer tui_sequencer
tui_sequencer_bar tui_sequencer_bar

View file

@ -25,7 +25,7 @@ where
C: Command<T>, C: Command<T>,
U: From<Arc<RwLock<T>>> + Widget<Engine = E> + Handle<E>, U: From<Arc<RwLock<T>>> + Widget<Engine = E> + Handle<E>,
A: From<Arc<RwLock<T>>> + Audio, A: From<Arc<RwLock<T>>> + Audio,
S: From<Arc<RwLock<T>>> + Widget<Engine = E> S: From<Arc<RwLock<T>>> + StatusBar<E>
{ {
fn from (model: T) -> Self { fn from (model: T) -> Self {
let model = Arc::new(RwLock::new(model)); let model = Arc::new(RwLock::new(model));
@ -35,7 +35,7 @@ where
menu_bar: None, menu_bar: None,
status_bar: None, status_bar: None,
history: vec![], history: vec![],
size: (0, 0).into(), size: Measure::new(),
ui: U::from(model.clone()), ui: U::from(model.clone()),
audio: A::from(model.clone()), audio: A::from(model.clone()),
model, model,

View file

@ -447,28 +447,6 @@ impl<E: Engine> Arrangement<E> {
} }
} }
impl ArrangementTrack {
pub fn new (
jack: &Arc<RwLock<JackClient>>,
clock: &Arc<Clock>,
name: &str,
color: Option<ItemColor>
) -> Usually<Self> {
Ok(Self {
name: Arc::new(RwLock::new(name.into())),
width: name.len() + 2,
color: color.unwrap_or_else(ItemColor::random),
player: PhrasePlayer::new(&jack, clock, name)?,
})
}
pub fn longest_name (tracks: &[Self]) -> usize {
tracks.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
}
pub const MIN_WIDTH: usize = 3;
pub fn width_inc (&mut self) { self.width += 1; }
pub fn width_dec (&mut self) { if self.width > Self::MIN_WIDTH { self.width -= 1; } }
}
/// Arranger display mode can be cycled /// Arranger display mode can be cycled
impl ArrangementEditorMode { impl ArrangementEditorMode {
/// Cycle arranger display mode /// Cycle arranger display mode
@ -482,33 +460,3 @@ impl ArrangementEditorMode {
} }
} }
} }
impl ArrangementScene {
pub fn new (
name: impl AsRef<str>,
clips: impl AsRef<[Option<Arc<RwLock<Phrase>>>]>,
color: Option<ItemColor>,
) -> Self {
Self {
name: Arc::new(RwLock::new(name.as_ref().into())),
clips: clips.as_ref().iter().map(|x|x.clone()).collect(),
color: color.unwrap_or_else(ItemColor::random),
}
}
pub fn ppqs (scenes: &[Self], factor: usize) -> Vec<(usize, usize)> {
let mut total = 0;
if factor == 0 {
scenes.iter().map(|scene|{
let pulses = scene.pulses().max(PPQ);
total = total + pulses;
(pulses, total - pulses)
}).collect()
} else {
(0..=scenes.len()).map(|i|{
(factor*PPQ, factor*PPQ*i)
}).collect()
}
}
pub fn longest_name (scenes: &[Self]) -> usize {
scenes.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
}
}

View file

@ -118,7 +118,6 @@ impl Content for ArrangerStatusBar {
//.cmd("s", "Save project", ArrangerViewCommand::Arrangement(Save)) //.cmd("s", "Save project", ArrangerViewCommand::Arrangement(Save))
//}) //})
//.add({ //.add({
//use TransportViewCommand::*;
//Menu::new("Transport") //Menu::new("Transport")
//.cmd("p", "Play", TransportCommand::Transport(Play(None))) //.cmd("p", "Play", TransportCommand::Transport(Play(None)))
//.cmd("P", "Play from start", TransportCommand::Transport(Play(Some(0)))) //.cmd("P", "Play from start", TransportCommand::Transport(Play(Some(0))))

View file

@ -3,27 +3,16 @@ use crate::*;
#[derive(Clone)] #[derive(Clone)]
pub enum ArrangerViewCommand { pub enum ArrangerViewCommand {
Focus(FocusCommand), Focus(FocusCommand),
Transport(TransportCommand),
Arrangement(ArrangementEditorCommand), Arrangement(ArrangementEditorCommand),
EditPhrase(Option<Arc<RwLock<Phrase>>>), Transport(TransportCommand),
Phrases(PhrasePoolCommand), Phrases(PhrasePoolCommand),
Editor(PhraseEditorCommand), Editor(PhraseEditorCommand),
EditPhrase(Option<Arc<RwLock<Phrase>>>),
} }
/// Handle top-level events in standalone arranger. /// Handle top-level events in standalone arranger.
impl Handle<Tui> for ArrangerView<Tui> { impl Handle<Tui> for ArrangerView<Tui> {
fn handle (&mut self, i: &TuiInput) -> Perhaps<bool> { fn handle (&mut self, i: &TuiInput) -> Perhaps<bool> {
if let Some(entered) = self.entered() {
use ArrangerViewFocus::*;
if let Some(true) = match entered {
Transport => self.sequencer.transport.map(|t|t.handle(i)).transpose()?.flatten(),
Arrangement => self.arrangement.handle(i)?,
PhrasePool => self.sequencer.phrases.handle(i)?,
PhraseEditor => self.sequencer.editor.handle(i)?,
} {
return Ok(Some(true))
}
}
ArrangerViewCommand::execute_with_state(self, i) ArrangerViewCommand::execute_with_state(self, i)
} }
} }
@ -70,87 +59,28 @@ impl InputToCommand<Tui, ArrangerView<Tui>> for ArrangerViewCommand {
} }
} }
//impl ArrangerView<Tui> {
///// Helper for event passthru to focused component
//fn handle_focused (&mut self, from: &TuiInput) -> Perhaps<bool> {
//match self.focused() {
//ArrangerViewFocus::Transport => self.transport.handle(from),
//ArrangerViewFocus::PhrasePool => self.handle_pool(from),
//ArrangerViewFocus::PhraseEditor => self.editor.handle(from),
//ArrangerViewFocus::Arrangement => self.handle_arrangement(from)
//.and_then(|result|{self.show_phrase();Ok(result)}),
//}
//}
///// Helper for phrase event passthru when phrase pool is focused
//fn handle_pool (&mut self, from: &TuiInput) -> Perhaps<bool> {
//match from.event() {
//key!(KeyCode::Char('<')) => {
//self.phrases_split = self.phrases_split.saturating_sub(1).max(12);
//},
//key!(KeyCode::Char('>')) => {
//self.phrases_split = self.phrases_split + 1;
//},
//_ => return self.phrases.handle(from)
//}
//Ok(Some(true))
//}
///// Helper for phrase event passthru when arrangement is focused
//fn handle_arrangement (&mut self, from: &TuiInput) -> Perhaps<bool> {
//let mut handle_phrase = ||{
//let result = self.phrases.handle(from);
//self.arrangement.phrase_put();
//result
//};
//match from.event() {
//key!(KeyCode::Char('a')) => return handle_phrase(),
//key!(KeyCode::Char('i')) => return handle_phrase(),
//key!(KeyCode::Char('d')) => return handle_phrase(),
//key!(KeyCode::Char('<')) => if self.arrangement.selected == ArrangementFocus::Mix {
//self.arrangement_split = self.arrangement_split.saturating_sub(1).max(12);
//} else {
//return self.arrangement.handle(from)
//},
//key!(KeyCode::Char('>')) => if self.arrangement.selected == ArrangementFocus::Mix {
//self.arrangement_split = self.arrangement_split + 1;
//} else {
//return self.arrangement.handle(from)
//},
//_ => return self.arrangement.handle(from)
//}
//self.show_phrase();
//Ok(Some(true))
//}
//}
impl<E: Engine> Command<ArrangerView<E>> for ArrangerViewCommand { impl<E: Engine> Command<ArrangerView<E>> for ArrangerViewCommand {
fn execute (self, state: &mut ArrangerView<E>) -> Perhaps<Self> { fn execute (self, view: &mut ArrangerView<E>) -> Perhaps<Self> {
let undo = match self { let undo = match self {
Self::Focus(cmd) => { Self::Focus(cmd) =>
delegate(cmd, Self::Focus, state) delegate(cmd, Self::Focus, view),
}, Self::Phrases(cmd) =>
Self::Phrases(cmd) => { delegate(cmd, Self::Phrases, &mut view.sequencer.phrases),
delegate(cmd, Self::Phrases, &mut*state.sequencer.phrases.write().unwrap()) Self::Editor(cmd) =>
}, delegate(cmd, Self::Editor, &mut view.sequencer.editor),
Self::Editor(cmd) => { Self::Transport(cmd) =>
delegate(cmd, Self::Editor, &mut state.sequencer.editor) delegate(cmd, Self::Transport, &mut view.sequencer.transport.state),
}, Self::Arrangement(cmd) =>
Self::Arrangement(cmd) => { delegate(cmd, Self::Arrangement, &mut view.arrangement),
delegate(cmd, Self::Arrangement, &mut state.arrangement)
},
Self::Transport(cmd) => if let Some(ref transport) = state.sequencer.transport {
delegate(cmd, Self::Transport, &mut*transport.write().unwrap())
} else {
Ok(None)
},
Self::EditPhrase(phrase) => { Self::EditPhrase(phrase) => {
state.sequencer.editor.phrase = phrase.clone(); view.sequencer.editor.phrase = phrase.clone();
state.focus(ArrangerViewFocus::PhraseEditor); view.focus(ArrangerViewFocus::PhraseEditor);
state.focus_enter(); view.focus_enter();
Ok(None) Ok(None)
} }
}?; }?;
state.sequencer.show_phrase(); view.sequencer.show_phrase();
state.sequencer.update_status(); view.sequencer.update_status();
return Ok(undo); return Ok(undo);
} }
} }

View file

@ -3,77 +3,55 @@ use crate::*;
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum SequencerViewCommand { pub enum SequencerViewCommand {
Focus(FocusCommand), Focus(FocusCommand),
Transport(TransportCommand), Transport(TransportViewCommand),
Phrases(PhrasePoolCommand), Phrases(PhrasePoolViewCommand),
Editor(PhraseEditorCommand), Editor(PhraseEditorCommand),
} }
impl Handle<Tui> for SequencerView<Tui> { impl Handle<Tui> for SequencerView<Tui> {
fn handle (&mut self, i: &TuiInput) -> Perhaps<bool> { fn handle (&mut self, i: &TuiInput) -> Perhaps<bool> {
if let Some(entered) = self.entered() { SequencerViewCommand::execute_with_state(self, i)
use SequencerFocus::*;
if let Some(true) = match entered {
Transport => self.transport.as_mut().map(|t|t.handle(i)).transpose()?.flatten(),
PhrasePool => self.phrases.write().unwrap().handle(i)?,
PhraseEditor => self.editor.handle(i)?,
} {
return Ok(Some(true))
}
}
if let Some(command) = SequencerCommand::input_to_command(self, i) {
let _undo = command.execute(self)?;
return Ok(Some(true))
}
Ok(None)
} }
} }
impl<E: Engine> Command<SequencerView<E>> for SequencerViewCommand { impl<E: Engine> Command<SequencerView<E>> for SequencerViewCommand {
fn execute (self, state: &mut SequencerView<E>) -> Perhaps<Self> { fn execute (self, state: &mut SequencerView<E>) -> Perhaps<Self> {
match self { match self {
Self::Focus(cmd) => { Self::Focus(cmd) =>
return delegate(cmd, Self::Focus, state) delegate(cmd, Self::Focus, state),
}, Self::Phrases(cmd) =>
Self::Phrases(cmd) => { delegate(cmd, Self::Phrases, &mut state.phrases),
return delegate(cmd, Self::Phrases, &mut*state.phrases.write().unwrap()) Self::Editor(cmd) =>
}, delegate(cmd, Self::Editor, &mut state.editor),
Self::Editor(cmd) => { Self::Transport(cmd) =>
return delegate(cmd, Self::Editor, &mut state.editor) delegate(cmd, Self::Transport, &mut state.transport)
},
Self::Transport(cmd) => if let Some(ref transport) = state.transport {
return delegate(cmd, Self::Transport, &mut*transport.write().unwrap())
},
} }
Ok(None)
} }
} }
impl InputToCommand<Tui, SequencerView<Tui>> for SequencerViewCommand { impl InputToCommand<Tui, SequencerView<Tui>> for SequencerViewCommand {
fn input_to_command (state: &SequencerView<Tui>, input: &TuiInput) -> Option<Self> { fn input_to_command (state: &SequencerView<Tui>, input: &TuiInput) -> Option<Self> {
use SequencerViewCommand::*;
use FocusCommand::*; use FocusCommand::*;
match input.event() { match input.event() {
key!(KeyCode::Tab) => Some(Focus(Next)), key!(KeyCode::Tab) => Some(Self::Focus(Next)),
key!(Shift-KeyCode::Tab) => Some(Focus(Prev)), key!(Shift-KeyCode::Tab) => Some(Self::Focus(Prev)),
key!(KeyCode::BackTab) => Some(Focus(Prev)), key!(KeyCode::BackTab) => Some(Self::Focus(Prev)),
key!(Shift-KeyCode::BackTab) => Some(Focus(Prev)), key!(Shift-KeyCode::BackTab) => Some(Self::Focus(Prev)),
key!(KeyCode::Up) => Some(Focus(Up)), key!(KeyCode::Up) => Some(Self::Focus(Up)),
key!(KeyCode::Down) => Some(Focus(Down)), key!(KeyCode::Down) => Some(Self::Focus(Down)),
key!(KeyCode::Left) => Some(Focus(Left)), key!(KeyCode::Left) => Some(Self::Focus(Left)),
key!(KeyCode::Right) => Some(Focus(Right)), key!(KeyCode::Right) => Some(Self::Focus(Right)),
//key!(KeyCode::Char(' ')) => Some(Transport(TransportViewCommand::PlayToggle)),
_ => match state.focused() { _ => match state.focused() {
SequencerFocus::Transport => if let Some(t) = state.transport.as_ref() { SequencerFocus::Transport => TransportViewCommand::input_to_command(
TransportViewCommand::input_to_command(&*t.read().unwrap(), input).map(Transport) &state.transport, input
} else { ).map(Self::Transport),
None SequencerFocus::PhrasePool => PhrasePoolViewCommand::input_to_command(
}, &state.phrases, input
SequencerFocus::PhrasePool => ).map(Self::Phrases),
PhrasePoolCommand::input_to_command(&*state.phrases.read().unwrap(), input) SequencerFocus::PhraseEditor => PhraseEditorCommand::input_to_command(
.map(Phrases), &state.editor, input
SequencerFocus::PhraseEditor => ).map(Self::Editor),
PhraseEditorCommand::input_to_command(&state.editor, input)
.map(Editor),
} }
} }
} }

View file

@ -11,7 +11,7 @@ use crate::*;
} }
/// Focus layout of sequencer app /// Focus layout of sequencer app
impl<E: Engine> FocusGrid for Sequencer<E> { impl<E: Engine> FocusGrid for SequencerView<E> {
type Item = SequencerFocus; type Item = SequencerFocus;
fn cursor (&self) -> (usize, usize) { fn cursor (&self) -> (usize, usize) {
self.focus_cursor self.focus_cursor

View file

@ -1,14 +1,17 @@
use crate::*; use crate::*;
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum TransportViewCommand { pub enum TransportViewCommand {
Focus(FocusCommand), Focus(FocusCommand),
Transport(TransportCommand), Transport(TransportCommand),
} }
impl Handle<Tui> for TransportView<Tui> { impl Handle<Tui> for TransportView<Tui> {
fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> { fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> {
TransportViewCommand::execute_with_state(self, from) TransportViewCommand::execute_with_state(self, from)
} }
} }
impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand { impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
fn input_to_command (state: &TransportView<Tui>, input: &TuiInput) -> Option<Self> { fn input_to_command (state: &TransportView<Tui>, input: &TuiInput) -> Option<Self> {
use TransportViewFocus as Focus; use TransportViewFocus as Focus;
@ -55,15 +58,16 @@ impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
impl<E: Engine> Command<TransportView<E>> for TransportViewCommand { impl<E: Engine> Command<TransportView<E>> for TransportViewCommand {
fn execute (self, state: &mut TransportView<E>) -> Perhaps<Self> { fn execute (self, state: &mut TransportView<E>) -> Perhaps<Self> {
Ok(match self { Ok(Some(match self {
Self::Focus(command) => { Self::Focus(command) => Self::Focus({
use FocusCommand::*; use FocusCommand::*;
match command { match command {
Next => { todo!() }, Next => { todo!() },
Prev => { todo!() }, Prev => { todo!() },
_ => { todo!() }
} }
}, }),
Self::Transport(command) => { Self::Transport(command) => Self::Transport({
use TransportCommand::*; use TransportCommand::*;
match command { match command {
SetBpm(bpm) => SetBpm(state.state.clock.timebase().bpm.set(bpm)), SetBpm(bpm) => SetBpm(state.state.clock.timebase().bpm.set(bpm)),
@ -71,7 +75,7 @@ impl<E: Engine> Command<TransportView<E>> for TransportViewCommand {
SetSync(sync) => SetSync(state.state.clock.sync.set(sync)), SetSync(sync) => SetSync(state.state.clock.sync.set(sync)),
_ => { todo!() } _ => { todo!() }
} }
}, }),
}) }))
} }
} }