wip: refactor pt.15: 107 errors

This commit is contained in:
🪞👃🪞 2024-11-11 00:39:45 +01:00
parent 8b68a993bc
commit 5823d0b746
8 changed files with 423 additions and 455 deletions

View file

@ -113,12 +113,12 @@ impl ArrangementScene {
/// Returns true if all phrases in the scene are /// Returns true if all phrases in the scene are
/// currently playing on the given collection of tracks. /// currently playing on the given collection of tracks.
pub fn is_playing (&self, tracks: &[MIDIPlayer]) -> bool { pub fn is_playing (&self, tracks: &[ArrangementTrack]) -> bool {
self.clips.iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate() self.clips.iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate()
.all(|(track_index, clip)|match clip { .all(|(track_index, clip)|match clip {
Some(clip) => tracks Some(clip) => tracks
.get(track_index) .get(track_index)
.map(|track|if let Some((_, Some(phrase))) = &track.phrase { .map(|track|if let Some((_, Some(phrase))) = &track.player.phrase {
*phrase.read().unwrap() == *clip.read().unwrap() *phrase.read().unwrap() == *clip.read().unwrap()
} else { } else {
false false

View file

@ -14,9 +14,9 @@ pub enum ArrangementCommand {
#[derive(Clone)] #[derive(Clone)]
pub enum ArrangementSceneCommand { pub enum ArrangementSceneCommand {
Add, Add,
Delete, Delete(usize),
RandomColor, RandomColor,
Play, Play(usize),
Swap(usize), Swap(usize),
SetSize(usize), SetSize(usize),
SetZoom(usize), SetZoom(usize),
@ -25,7 +25,7 @@ pub enum ArrangementSceneCommand {
#[derive(Clone)] #[derive(Clone)]
pub enum ArrangementTrackCommand { pub enum ArrangementTrackCommand {
Add, Add,
Delete, Delete(usize),
RandomColor, RandomColor,
Stop, Stop,
Swap(usize), Swap(usize),

View file

@ -45,9 +45,9 @@ impl Content for ArrangementEditor<Tui> {
Layers::new(move |add|{ Layers::new(move |add|{
match self.mode { match self.mode {
ArrangementEditorMode::Horizontal => ArrangementEditorMode::Horizontal =>
add(&HorizontalArranger(&self))?, add(&arranger_content_horizontal(self))?,
ArrangementEditorMode::Vertical(factor) => ArrangementEditorMode::Vertical(factor) =>
add(&VerticalArranger(&self, factor))? add(&arranger_content_vertical(self, factor))?
}; };
add(&self.size) add(&self.size)
}) })

View file

@ -94,7 +94,7 @@ impl InputToCommand<Tui, ArrangementEditor<Tui>> for ArrangementEditorCommand {
key!(KeyCode::Enter) => match state.selected { key!(KeyCode::Enter) => match state.selected {
ArrangementEditorFocus::Mix => return None, ArrangementEditorFocus::Mix => return None,
ArrangementEditorFocus::Track(t) => return None, ArrangementEditorFocus::Track(t) => return None,
ArrangementEditorFocus::Scene(s) => return None, ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Play(s))),
ArrangementEditorFocus::Clip(t, s) => return None, ArrangementEditorFocus::Clip(t, s) => return None,
}, },
@ -129,16 +129,16 @@ impl InputToCommand<Tui, ArrangementEditor<Tui>> for ArrangementEditorCommand {
} }
impl<E: Engine> Command<ArrangementEditor<E>> for ArrangementEditorCommand { impl<E: Engine> Command<ArrangementEditor<E>> for ArrangementEditorCommand {
fn execute (self, state: &mut ArrangementEditor<E>) -> Perhaps<Self> { fn execute (self, view: &mut ArrangementEditor<E>) -> Perhaps<Self> {
match self { match self {
Self::Zoom(zoom) => { Self::Zoom(zoom) => {
todo!(); todo!();
}, },
Self::Select(selected) => { Self::Select(selected) => {
state.selected = selected; view.selected = selected;
}, },
Self::Edit(command) => { Self::Edit(command) => {
return command.execute(state.state).map(Self::Edit) return Ok(command.execute(&mut view.model)?.map(Self::Edit))
}, },
} }
Ok(None) Ok(None)

View file

@ -88,12 +88,8 @@ impl<E: Engine> ArrangerView<E> {
} }
/// Toggle global play/pause /// Toggle global play/pause
pub fn toggle_play (&mut self) -> Perhaps<bool> { pub fn toggle_play (&mut self) -> Usually<()> {
match self.transport { self.sequencer.transport.model.toggle_play()
Some(ref mut transport) => { transport.write().unwrap().toggle_play()?; },
None => { return Ok(None) }
}
Ok(Some(true))
} }
pub fn next_color (&self) -> ItemColor { pub fn next_color (&self) -> ItemColor {
if let ArrangementEditorFocus::Clip(track, scene) = self.arrangement.selected { if let ArrangementEditorFocus::Clip(track, scene) = self.arrangement.selected {
@ -225,30 +221,6 @@ impl<E: Engine> ArrangerView<E> {
phrase.write().unwrap().toggle_loop() phrase.write().unwrap().toggle_loop()
} }
} }
pub fn go_up (&mut self) {
match self.mode {
ArrangementEditorMode::Horizontal => self.track_prev(),
_ => self.scene_prev(),
};
}
pub fn go_down (&mut self) {
match self.mode {
ArrangementEditorMode::Horizontal => self.track_next(),
_ => self.scene_next(),
};
}
pub fn go_left (&mut self) {
match self.mode {
ArrangementEditorMode::Horizontal => self.scene_prev(),
_ => self.track_prev(),
};
}
pub fn go_right (&mut self) {
match self.mode {
ArrangementEditorMode::Horizontal => self.scene_next(),
_ => self.track_next(),
};
}
pub fn move_back (&mut self) { pub fn move_back (&mut self) {
match self.selected { match self.selected {
ArrangementEditorFocus::Scene(s) => { ArrangementEditorFocus::Scene(s) => {

View file

@ -4,8 +4,8 @@ use crate::*;
pub enum ArrangerViewCommand { pub enum ArrangerViewCommand {
Focus(FocusCommand), Focus(FocusCommand),
Arrangement(ArrangementEditorCommand), Arrangement(ArrangementEditorCommand),
Transport(TransportCommand), Transport(TransportViewCommand),
Phrases(PhrasePoolCommand), Phrases(PhrasePoolViewCommand),
Editor(PhraseEditorCommand), Editor(PhraseEditorCommand),
EditPhrase(Option<Arc<RwLock<Phrase>>>), EditPhrase(Option<Arc<RwLock<Phrase>>>),
} }
@ -18,44 +18,48 @@ impl Handle<Tui> for ArrangerView<Tui> {
} }
impl InputToCommand<Tui, ArrangerView<Tui>> for ArrangerViewCommand { impl InputToCommand<Tui, ArrangerView<Tui>> for ArrangerViewCommand {
fn input_to_command (state: &ArrangerView<Tui>, input: &TuiInput) -> Option<Self> { fn input_to_command (view: &ArrangerView<Tui>, input: &TuiInput) -> Option<Self> {
use FocusCommand::*; use FocusCommand::*;
use ArrangerViewCommand::*; use ArrangerViewCommand::*;
match input.event() { Some(match input.event() {
key!(KeyCode::Tab) => Some(Focus(Next)), key!(KeyCode::Tab) => Focus(Next),
key!(Shift-KeyCode::Tab) => Some(Focus(Prev)), key!(Shift-KeyCode::Tab) => Focus(Prev),
key!(KeyCode::BackTab) => Some(Focus(Prev)), key!(KeyCode::BackTab) => Focus(Prev),
key!(Shift-KeyCode::BackTab) => Some(Focus(Prev)), key!(Shift-KeyCode::BackTab) => Focus(Prev),
key!(KeyCode::Up) => Some(Focus(Up)), key!(KeyCode::Up) => Focus(Up),
key!(KeyCode::Down) => Some(Focus(Down)), key!(KeyCode::Down) => Focus(Down),
key!(KeyCode::Left) => Some(Focus(Left)), key!(KeyCode::Left) => Focus(Left),
key!(KeyCode::Right) => Some(Focus(Right)), key!(KeyCode::Right) => Focus(Right),
key!(KeyCode::Enter) => Some(Focus(Enter)), key!(KeyCode::Enter) => Focus(Enter),
key!(KeyCode::Esc) => Some(Focus(Exit)), key!(KeyCode::Esc) => Focus(Exit),
//key!(KeyCode::Char(' ')) => Some(Transport(TransportCommand::PlayToggle)), key!(KeyCode::Char(' ')) => {
_ => match state.focused() { Transport(TransportViewCommand::Transport(TransportCommand::Play(None)))
ArrangerViewFocus::Transport => state.transport.as_ref() },
.map(|t|TransportCommand::input_to_command(&*t.read().unwrap(), input) _ => match view.focused() {
.map(Transport)) ArrangerViewFocus::Transport => Transport(
.flatten(), TransportViewCommand::input_to_command(&view.sequencer.transport, input)?
ArrangerViewFocus::PhrasePool => { ),
let phrases = state.phrases.read().unwrap(); ArrangerViewFocus::PhraseEditor => Editor(
match input.event() { PhraseEditorCommand::input_to_command(&view.sequencer.editor, input)?
key!(KeyCode::Char('e')) => Some(EditPhrase(Some(phrases.phrase().clone()))), ),
_ => PhrasePoolCommand::input_to_command(&*phrases, input) ArrangerViewFocus::PhrasePool => match input.event() {
.map(Phrases) key!(KeyCode::Char('e')) => EditPhrase(
} Some(view.sequencer.phrases.phrase().clone())
),
_ => Phrases(
PhrasePoolViewCommand::input_to_command(&view.sequencer.phrases, input)?
)
}, },
ArrangerViewFocus::PhraseEditor =>
PhraseEditorCommand::input_to_command(&state.editor, input)
.map(Editor),
ArrangerViewFocus::Arrangement => match input.event() { ArrangerViewFocus::Arrangement => match input.event() {
key!(KeyCode::Char('e')) => Some(EditPhrase(state.arrangement.phrase())), key!(KeyCode::Char('e')) => EditPhrase(
_ => ArrangementCommand::input_to_command(&state.arrangement, &input) view.arrangement.phrase()
.map(Arrangement) ),
} _ => Arrangement(
ArrangementEditorCommand::input_to_command(&view.arrangement, &input)?
)
} }
} }
})
} }
} }
@ -69,7 +73,7 @@ impl<E: Engine> Command<ArrangerView<E>> for ArrangerViewCommand {
Self::Editor(cmd) => Self::Editor(cmd) =>
delegate(cmd, Self::Editor, &mut view.sequencer.editor), delegate(cmd, Self::Editor, &mut view.sequencer.editor),
Self::Transport(cmd) => Self::Transport(cmd) =>
delegate(cmd, Self::Transport, &mut view.sequencer.transport.state), delegate(cmd, Self::Transport, &mut view.sequencer.transport),
Self::Arrangement(cmd) => Self::Arrangement(cmd) =>
delegate(cmd, Self::Arrangement, &mut view.arrangement), delegate(cmd, Self::Arrangement, &mut view.arrangement),
Self::EditPhrase(phrase) => { Self::EditPhrase(phrase) => {
@ -79,8 +83,8 @@ impl<E: Engine> Command<ArrangerView<E>> for ArrangerViewCommand {
Ok(None) Ok(None)
} }
}?; }?;
view.sequencer.show_phrase(); view.show_phrase();
view.sequencer.update_status(); view.update_status();
return Ok(undo); return Ok(undo);
} }
} }

View file

@ -1,15 +1,12 @@
use crate::*; use crate::*;
/// Arrangement, rendered horizontally (arrangement/track mode). pub fn arranger_content_horizontal (
pub struct HorizontalArranger<'a, E: Engine>(pub &'a Arrangement<E>); state: &ArrangementEditor<Tui>,
) -> impl Widget<Engine = Tui> + use<'_> {
impl<'a> Content for HorizontalArranger<'a, Tui> { let focused = state.focused;
type Engine = Tui; let _tracks = state.model.tracks.as_slice();
fn content (&self) -> impl Widget<Engine = Tui> {
let Arrangement { tracks, focused, .. } = self.0;
let _tracks = tracks.as_slice();
lay!( lay!(
focused.then_some(Background(Arranger::<Tui>::border_bg())), focused.then_some(Background(TuiTheme::border_bg())),
row!( row!(
// name // name
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{ CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
@ -161,7 +158,8 @@ impl<'a> Content for HorizontalArranger<'a, Tui> {
}), }),
// scenes // scenes
CustomWidget::new(|_|{todo!()}, |to: &mut TuiOutput|{ CustomWidget::new(|_|{todo!()}, |to: &mut TuiOutput|{
let Arrangement { scenes, selected, .. } = self.0; let selected = &state.selected;
let scenes = &state.model.scenes;
let area = to.area(); let area = to.area();
let mut x2 = 0; let mut x2 = 0;
let [x, y, _, height] = area; let [x, y, _, height] = area;
@ -197,4 +195,3 @@ impl<'a> Content for HorizontalArranger<'a, Tui> {
) )
) )
} }
}

View file

@ -1,22 +1,19 @@
use crate::*; use crate::*;
/// Arrangement, rendered vertically (session/grid mode). pub fn arranger_content_vertical (
pub struct VerticalArranger<'a, E: Engine>(pub &'a Arrangement<E>, pub usize); view: &ArrangerView<Tui>,
factor: usize
impl<'a> Content for VerticalArranger<'a, Tui> { ) -> impl Widget<Engine = Tui> + use<'_> {
type Engine = Tui; let tracks = view.arrangement.model.tracks.as_ref() as &[ArrangementTrack];
fn content (&self) -> impl Widget<Engine = Tui> { let scenes = view.arrangement.model.scenes.as_ref();
let Self(state, factor) = self; let cols = view.arrangement.track_widths();
let tracks = state.tracks.as_ref() as &[ArrangementTrack]; let rows = ArrangementScene::ppqs(scenes, factor);
let scenes = state.scenes.as_ref(); let bg = view.arrangement.color;
let cols = state.track_widths();
let rows = ArrangementScene::ppqs(scenes, *factor);
let bg = state.color;
let clip_bg = TuiTheme::border_bg(); let clip_bg = TuiTheme::border_bg();
let sep_fg = TuiTheme::separator_fg(false); let sep_fg = TuiTheme::separator_fg(false);
let header_h = 3u16;//5u16; let header_h = 3u16;//5u16;
let scenes_w = 3 + ArrangementScene::longest_name(scenes) as u16; // x of 1st track let scenes_w = 3 + ArrangementScene::longest_name(scenes) as u16; // x of 1st track
let clock = &self.0.clock; let clock = &view.sequencer.transport.model.clock;
let arrangement = Layers::new(move |add|{ let arrangement = Layers::new(move |add|{
let rows: &[(usize, usize)] = rows.as_ref(); let rows: &[(usize, usize)] = rows.as_ref();
let cols: &[(usize, usize)] = cols.as_ref(); let cols: &[(usize, usize)] = cols.as_ref();
@ -129,14 +126,14 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
}) })
}).fixed_y(height) }).fixed_y(height)
} }
).fixed_y((self.0.size.h() as u16).saturating_sub(header_h)); ).fixed_y((view.size.h() as u16).saturating_sub(header_h));
// full grid with header and footer // full grid with header and footer
add(&col!(header, content))?; add(&col!(header, content))?;
// cursor // cursor
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{ add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
let area = to.area(); let area = to.area();
let focused = state.focused; let focused = view.arrangement.focused;
let selected = state.selected; let selected = view.arrangement.selected;
let get_track_area = |t: usize| [ let get_track_area = |t: usize| [
scenes_w + area.x() + cols[t].1 as u16, area.y(), scenes_w + area.x() + cols[t].1 as u16, area.y(),
cols[t].0 as u16, area.h(), cols[t].0 as u16, area.h(),
@ -188,10 +185,8 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
}) })
})) }))
}).bg(bg.rgb); }).bg(bg.rgb);
let color = TuiTheme::title_fg(self.0.focused); let color = TuiTheme::title_fg(view.arrangement.focused);
let size = format!("{}x{}", self.0.size.w(), self.0.size.h()); let size = format!("{}x{}", view.size.w(), view.size.h());
let lower_right = TuiStyle::fg(size, color).pull_x(1).align_se().fill_xy(); let lower_right = TuiStyle::fg(size, color).pull_x(1).align_se().fill_xy();
lay!(arrangement, lower_right) lay!(arrangement, lower_right)
} }
}