mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 04:36:45 +01:00
separate control layer
This commit is contained in:
parent
416acd9f7b
commit
9319315595
29 changed files with 1647 additions and 1641 deletions
260
crates/tek_tui/src/tui_control_arranger.rs
Normal file
260
crates/tek_tui/src/tui_control_arranger.rs
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
use crate::*;
|
||||
|
||||
impl Handle<Tui> for ArrangerTui {
|
||||
fn handle (&mut self, i: &TuiInput) -> Perhaps<bool> {
|
||||
ArrangerCommand::execute_with_state(self, i)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ArrangerCommand {
|
||||
Focus(FocusCommand),
|
||||
Undo,
|
||||
Redo,
|
||||
Clear,
|
||||
Color(ItemColor),
|
||||
Clock(ClockCommand),
|
||||
Scene(ArrangerSceneCommand),
|
||||
Track(ArrangerTrackCommand),
|
||||
Clip(ArrangerClipCommand),
|
||||
Select(ArrangerSelection),
|
||||
Zoom(usize),
|
||||
Phrases(PhrasesCommand),
|
||||
Editor(PhraseCommand),
|
||||
}
|
||||
|
||||
impl Command<ArrangerTui> for ArrangerCommand {
|
||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||
use ArrangerCommand::*;
|
||||
Ok(match self {
|
||||
Focus(cmd) => cmd.execute(state)?.map(Focus),
|
||||
Scene(cmd) => cmd.execute(state)?.map(Scene),
|
||||
Track(cmd) => cmd.execute(state)?.map(Track),
|
||||
Clip(cmd) => cmd.execute(state)?.map(Clip),
|
||||
Phrases(cmd) => cmd.execute(state)?.map(Phrases),
|
||||
Editor(cmd) => cmd.execute(state)?.map(Editor),
|
||||
Clock(cmd) => cmd.execute(state)?.map(Clock),
|
||||
Zoom(zoom) => { todo!(); },
|
||||
Select(selected) => {
|
||||
*state.selected_mut() = selected;
|
||||
None
|
||||
},
|
||||
_ => { todo!() }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<ArrangerTui> for ArrangerSceneCommand {
|
||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||
todo!();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<ArrangerTui> for ArrangerTrackCommand {
|
||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||
todo!();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<ArrangerTui> for ArrangerClipCommand {
|
||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||
todo!();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArrangerControl: TransportControl {
|
||||
fn selected (&self) -> ArrangerSelection;
|
||||
fn selected_mut (&mut self) -> &mut ArrangerSelection;
|
||||
fn activate (&mut self) -> Usually<()>;
|
||||
fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>>;
|
||||
fn toggle_loop (&mut self);
|
||||
fn randomize_color (&mut self);
|
||||
}
|
||||
|
||||
impl ArrangerControl for ArrangerTui {
|
||||
fn selected (&self) -> ArrangerSelection {
|
||||
self.selected
|
||||
}
|
||||
fn selected_mut (&mut self) -> &mut ArrangerSelection {
|
||||
&mut self.selected
|
||||
}
|
||||
fn activate (&mut self) -> Usually<()> {
|
||||
if let ArrangerSelection::Scene(s) = self.selected {
|
||||
for (t, track) in self.tracks.iter_mut().enumerate() {
|
||||
let phrase = self.scenes[s].clips[t].clone();
|
||||
if track.player.play_phrase.is_some() || phrase.is_some() {
|
||||
track.enqueue_next(phrase.as_ref());
|
||||
}
|
||||
}
|
||||
if self.is_stopped() {
|
||||
self.play_from(Some(0))?;
|
||||
}
|
||||
} else if let ArrangerSelection::Clip(t, s) = self.selected {
|
||||
let phrase = self.scenes()[s].clips[t].clone();
|
||||
self.tracks_mut()[t].enqueue_next(phrase.as_ref());
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
|
||||
self.selected_scene()?.clips.get(self.selected.track()?)?.clone()
|
||||
}
|
||||
fn toggle_loop (&mut self) {
|
||||
if let Some(phrase) = self.selected_phrase() {
|
||||
phrase.write().unwrap().toggle_loop()
|
||||
}
|
||||
}
|
||||
fn randomize_color (&mut self) {
|
||||
match self.selected {
|
||||
ArrangerSelection::Mix => {
|
||||
self.color = ItemColor::random_dark()
|
||||
},
|
||||
ArrangerSelection::Track(t) => {
|
||||
self.tracks_mut()[t].color = ItemColor::random()
|
||||
},
|
||||
ArrangerSelection::Scene(s) => {
|
||||
self.scenes_mut()[s].color = ItemColor::random()
|
||||
},
|
||||
ArrangerSelection::Clip(t, s) => {
|
||||
if let Some(phrase) = &self.scenes_mut()[s].clips[t] {
|
||||
phrase.write().unwrap().color = ItemColorTriplet::random();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl InputToCommand<Tui, ArrangerTui> for ArrangerCommand {
|
||||
fn input_to_command (state: &ArrangerTui, input: &TuiInput) -> Option<Self> {
|
||||
to_arranger_command(state, input)
|
||||
.or_else(||to_focus_command(input).map(ArrangerCommand::Focus))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn to_arranger_command (state: &ArrangerTui, input: &TuiInput) -> Option<ArrangerCommand> {
|
||||
use ArrangerCommand as Cmd;
|
||||
use KeyCode::Char;
|
||||
if !state.entered() {
|
||||
return None
|
||||
}
|
||||
Some(match input.event() {
|
||||
key!(Char('e')) => Cmd::Editor(PhraseCommand::Show(state.phrase_to_edit().clone())),
|
||||
_ => match state.focused() {
|
||||
AppFocus::Menu => { todo!() },
|
||||
AppFocus::Content(focused) => match focused {
|
||||
ArrangerFocus::Transport(_) => {
|
||||
use TransportCommand::{Clock, Focus};
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
Clock(_) => { todo!() },
|
||||
Focus(command) => Cmd::Focus(command)
|
||||
}
|
||||
},
|
||||
ArrangerFocus::PhraseEditor => {
|
||||
Cmd::Editor(PhraseCommand::input_to_command(state, input)?)
|
||||
},
|
||||
ArrangerFocus::Phrases => {
|
||||
Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?)
|
||||
},
|
||||
ArrangerFocus::Arranger => {
|
||||
use ArrangerSelection::*;
|
||||
match input.event() {
|
||||
key!(Char('l')) => Cmd::Clip(ArrangerClipCommand::SetLoop(false)),
|
||||
key!(Char('+')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('=')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('_')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('-')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('`')) => { todo!("toggle state mode") },
|
||||
key!(Ctrl-Char('a')) => Cmd::Scene(ArrangerSceneCommand::Add),
|
||||
key!(Ctrl-Char('t')) => Cmd::Track(ArrangerTrackCommand::Add),
|
||||
_ => match state.selected() {
|
||||
Mix => to_arranger_mix_command(input)?,
|
||||
Track(t) => to_arranger_track_command(input, t)?,
|
||||
Scene(s) => to_arranger_scene_command(input, s)?,
|
||||
Clip(t, s) => to_arranger_clip_command(input, t, s)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn to_arranger_mix_command (input: &TuiInput) -> Option<ArrangerCommand> {
|
||||
use KeyCode::{Char, Down, Right, Delete};
|
||||
use ArrangerCommand as Cmd;
|
||||
use ArrangerSelection as Select;
|
||||
Some(match input.event() {
|
||||
key!(Down) => Cmd::Select(Select::Scene(0)),
|
||||
key!(Right) => Cmd::Select(Select::Track(0)),
|
||||
key!(Char(',')) => Cmd::Zoom(0),
|
||||
key!(Char('.')) => Cmd::Zoom(0),
|
||||
key!(Char('<')) => Cmd::Zoom(0),
|
||||
key!(Char('>')) => Cmd::Zoom(0),
|
||||
key!(Delete) => Cmd::Clear,
|
||||
key!(Char('c')) => Cmd::Color(ItemColor::random()),
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
|
||||
fn to_arranger_track_command (input: &TuiInput, t: usize) -> Option<ArrangerCommand> {
|
||||
use KeyCode::{Char, Down, Left, Right, Delete};
|
||||
use ArrangerCommand as Cmd;
|
||||
use ArrangerSelection as Select;
|
||||
use ArrangerTrackCommand as Track;
|
||||
Some(match input.event() {
|
||||
key!(Down) => Cmd::Select(Select::Clip(t, 0)),
|
||||
key!(Left) => Cmd::Select(if t > 0 { Select::Track(t - 1) } else { Select::Mix }),
|
||||
key!(Right) => Cmd::Select(Select::Track(t + 1)),
|
||||
key!(Char(',')) => Cmd::Track(Track::Swap(t, t - 1)),
|
||||
key!(Char('.')) => Cmd::Track(Track::Swap(t, t + 1)),
|
||||
key!(Char('<')) => Cmd::Track(Track::Swap(t, t - 1)),
|
||||
key!(Char('>')) => Cmd::Track(Track::Swap(t, t + 1)),
|
||||
key!(Delete) => Cmd::Track(Track::Delete(t)),
|
||||
//key!(Char('c')) => Cmd::Track(Track::Color(t, ItemColor::random())),
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
|
||||
fn to_arranger_scene_command (input: &TuiInput, s: usize) -> Option<ArrangerCommand> {
|
||||
use KeyCode::{Char, Up, Down, Right, Enter, Delete};
|
||||
use ArrangerCommand as Cmd;
|
||||
use ArrangerSelection as Select;
|
||||
use ArrangerSceneCommand as Scene;
|
||||
Some(match input.event() {
|
||||
key!(Up) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }),
|
||||
key!(Down) => Cmd::Select(Select::Scene(s + 1)),
|
||||
key!(Right) => Cmd::Select(Select::Clip(0, s)),
|
||||
key!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)),
|
||||
key!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)),
|
||||
key!(Char('<')) => Cmd::Scene(Scene::Swap(s, s - 1)),
|
||||
key!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)),
|
||||
key!(Enter) => Cmd::Scene(Scene::Play(s)),
|
||||
key!(Delete) => Cmd::Scene(Scene::Delete(s)),
|
||||
//key!(Char('c')) => Cmd::Track(Scene::Color(s, ItemColor::random())),
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
|
||||
fn to_arranger_clip_command (input: &TuiInput, t: usize, s: usize) -> Option<ArrangerCommand> {
|
||||
use KeyCode::{Char, Up, Down, Left, Right, Delete};
|
||||
use ArrangerCommand as Cmd;
|
||||
use ArrangerSelection as Select;
|
||||
use ArrangerClipCommand as Clip;
|
||||
Some(match input.event() {
|
||||
key!(Up) => Cmd::Select(if s > 0 { Select::Clip(t, s - 1) } else { Select::Track(t) }),
|
||||
key!(Down) => Cmd::Select(Select::Clip(t, s + 1)),
|
||||
key!(Left) => Cmd::Select(if t > 0 { Select::Clip(t - 1, s) } else { Select::Scene(s) }),
|
||||
key!(Right) => Cmd::Select(Select::Clip(t + 1, s)),
|
||||
key!(Char(',')) => Cmd::Clip(Clip::Set(t, s, None)),
|
||||
key!(Char('.')) => Cmd::Clip(Clip::Set(t, s, None)),
|
||||
key!(Char('<')) => Cmd::Clip(Clip::Set(t, s, None)),
|
||||
key!(Char('>')) => Cmd::Clip(Clip::Set(t, s, None)),
|
||||
key!(Delete) => Cmd::Clip(Clip::Set(t, s, None)),
|
||||
//key!(Char('c')) => Cmd::Clip(Clip::Color(t, s, ItemColor::random())),
|
||||
//key!(Char('g')) => Cmd::Clip(Clip(Clip::Get(t, s))),
|
||||
//key!(Char('s')) => Cmd::Clip(Clip(Clip::Set(t, s))),
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue