From 9bed07451fae3972afe42b700448207b8980c2af Mon Sep 17 00:00:00 2001
From: unspeaker <hora.nqma@protonmail.com>
Date: Tue, 24 Dec 2024 01:15:35 +0100
Subject: [PATCH] put phrase

---
 .scratch.rs                          |  62 +++++++++++++
 crates/tek/src/tui/app_arranger.rs   | 101 +++++++-------------
 crates/tek/src/tui/arranger_clip.rs  |  14 +++
 crates/tek/src/tui/arranger_scene.rs | 133 ++++++++-------------------
 crates/tek/src/tui/arranger_track.rs | 103 +++++++++++----------
 5 files changed, 202 insertions(+), 211 deletions(-)

diff --git a/.scratch.rs b/.scratch.rs
index 4eead468..9bd28f30 100644
--- a/.scratch.rs
+++ b/.scratch.rs
@@ -311,3 +311,65 @@
     //)
 //}
 
+//impl Command<ArrangerModel> for ArrangerSceneCommand {
+//}
+            //Edit(phrase)   => { state.state.phrase = phrase.clone() },
+            //ToggleViewMode => { state.state.mode.to_next(); },
+            //Delete         => { state.state.delete(); },
+            //Activate       => { state.state.activate(); },
+            //ZoomIn         => { state.state.zoom_in(); },
+            //ZoomOut        => { state.state.zoom_out(); },
+            //MoveBack       => { state.state.move_back(); },
+            //MoveForward    => { state.state.move_forward(); },
+            //RandomColor    => { state.state.randomize_color(); },
+            //Put            => { state.state.phrase_put(); },
+            //Get            => { state.state.phrase_get(); },
+            //AddScene       => { state.state.scene_add(None, None)?; },
+            //AddTrack       => { state.state.track_add(None, None)?; },
+            //ToggleLoop     => { state.state.toggle_loop() },
+    //pub fn zoom_in (&mut self) {
+        //if let ArrangerEditorMode::V(factor) = self.mode {
+            //self.mode = ArrangerEditorMode::V(factor + 1)
+        //}
+    //}
+    //pub fn zoom_out (&mut self) {
+        //if let ArrangerEditorMode::V(factor) = self.mode {
+            //self.mode = ArrangerEditorMode::V(factor.saturating_sub(1))
+        //}
+    //}
+    //pub fn move_back (&mut self) {
+        //match self.selected {
+            //ArrangerEditorFocus::Scene(s) => {
+                //if s > 0 {
+                    //self.scenes.swap(s, s - 1);
+                    //self.selected = ArrangerEditorFocus::Scene(s - 1);
+                //}
+            //},
+            //ArrangerEditorFocus::Track(t) => {
+                //if t > 0 {
+                    //self.tracks.swap(t, t - 1);
+                    //self.selected = ArrangerEditorFocus::Track(t - 1);
+                    //// FIXME: also swap clip order in scenes
+                //}
+            //},
+            //_ => todo!("arrangement: move forward")
+        //}
+    //}
+    //pub fn move_forward (&mut self) {
+        //match self.selected {
+            //ArrangerEditorFocus::Scene(s) => {
+                //if s < self.scenes.len().saturating_sub(1) {
+                    //self.scenes.swap(s, s + 1);
+                    //self.selected = ArrangerEditorFocus::Scene(s + 1);
+                //}
+            //},
+            //ArrangerEditorFocus::Track(t) => {
+                //if t < self.tracks.len().saturating_sub(1) {
+                    //self.tracks.swap(t, t + 1);
+                    //self.selected = ArrangerEditorFocus::Track(t + 1);
+                    //// FIXME: also swap clip order in scenes
+                //}
+            //},
+            //_ => todo!("arrangement: move forward")
+        //}
+    //}
diff --git a/crates/tek/src/tui/app_arranger.rs b/crates/tek/src/tui/app_arranger.rs
index eaa8ab48..8ee16467 100644
--- a/crates/tek/src/tui/app_arranger.rs
+++ b/crates/tek/src/tui/app_arranger.rs
@@ -177,7 +177,8 @@ handle!(<Tui>|self: ArrangerTui, input|ArrangerCommand::execute_with_state(self,
     Zoom(usize),
     Phrases(PhrasesCommand),
     Editor(PhraseCommand),
-    ShowPool(bool)
+    ShowPool(bool),
+    Put(usize, usize, Option<Arc<RwLock<Phrase>>>),
 }
 input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{
     use ArrangerSelection as Selected;
@@ -205,25 +206,10 @@ input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{
         key_pat!(Ctrl-Char('t')) =>
             Self::Track(ArrangerTrackCommand::Add),
         key_pat!(Char('0')) => match state.selected() {
-            Selected::Mix        => StopAll,
-            Selected::Track(t)   => return None,
-            Selected::Scene(s)   => return None,
-            Selected::Clip(t, s) => return None,
-        },
-        key_pat!(Char('g')) => if let Selected::Clip(t, s) = state.selected() {
-            Self::Phrases(PhrasesCommand::Select(0))
-        } else {
-            return None
-        },
-        key_pat!(Char('p')) => if let Selected::Clip(t, s) = state.selected() {
-            Self::Clip(ArrangerClipCommand::Select(0))
-        } else {
-            return None
-        },
-        key_pat!(Char('q')) => if let Selected::Clip(t, s) = state.selected() {
-            todo!("enqueue clip")
-        } else {
-            return None
+            Selected::Mix          => StopAll,
+            Selected::Track(_t)    => return None,
+            Selected::Scene(_s)    => return None,
+            Selected::Clip(_t, _s) => return None,
         },
         // Tab: Toggle visibility of phrase pool column
         key_pat!(Tab) =>
@@ -232,10 +218,23 @@ input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{
             let t_len = state.tracks.len();
             let s_len = state.scenes.len();
             match state.selected() {
-                Selected::Mix        => to_arranger_mix_command(input),
-                Selected::Track(t)   => to_arranger_track_command(input, t, t_len),
+                Selected::Clip(t, s) => match input.event() {
+                    key_pat!(Char('g')) => Some(Self::Phrases(PhrasesCommand::Select(0))),
+                    key_pat!(Char('p')) => Some(Self::Put(t, s, Some(state.phrases.phrase().clone()))),
+                    key_pat!(Char('q')) => { todo!("enqueue") },
+                    _ => to_arranger_clip_command(input, t, t_len, s, s_len)
+                },
                 Selected::Scene(s)   => to_arranger_scene_command(input, s, s_len),
-                Selected::Clip(t, s) => to_arranger_clip_command(input, t, t_len, s, s_len),
+                Selected::Track(t)   => to_arranger_track_command(input, t, t_len),
+                Selected::Mix        => match input.event() {
+                    // 0: Enqueue phrase 0 (stop all)
+                    key_pat!(Char('0')) => Some(Self::StopAll),
+                    key_pat!(Char('s')) => Some(Self::Select(Selected::Scene(0))),
+                    key_pat!(Char('d')) => Some(Self::Select(Selected::Track(0))),
+                    key_pat!(Delete)    => Some(Self::Clear),
+                    key_pat!(Char('c')) => Some(Self::Color(ItemPalette::random())),
+                    _ => None
+                },
             }
         }.or_else(||if let Some(command) = PhraseCommand::input_to_command(&state.editor, input) {
             Some(Self::Editor(command))
@@ -246,23 +245,6 @@ input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{
         })?
     }
 });
-fn to_arranger_mix_command (input: &TuiInput) -> Option<ArrangerCommand> {
-    use ArrangerCommand   as Cmd;
-    use ArrangerSelection as Select;
-    Some(match input.event() {
-        // 0: Enqueue phrase 0 (stop all)
-        key_pat!(Char('0')) => Cmd::StopAll,
-        key_pat!(Char('s')) => Cmd::Select(Select::Scene(0)),
-        key_pat!(Char('d')) => Cmd::Select(Select::Track(0)),
-        key_pat!(Char(',')) => Cmd::Zoom(0),
-        key_pat!(Char('.')) => Cmd::Zoom(0),
-        key_pat!(Char('<')) => Cmd::Zoom(0),
-        key_pat!(Char('>')) => Cmd::Zoom(0),
-        key_pat!(Delete)    => Cmd::Clear,
-        key_pat!(Char('c')) => Cmd::Color(ItemPalette::random()),
-        _ => return None
-    })
-}
 command!(|self:ArrangerCommand,state:ArrangerTui|{
     use ArrangerCommand::*;
     match self {
@@ -305,38 +287,17 @@ command!(|self:ArrangerCommand,state:ArrangerTui|{
                 _ => default(cmd)?
             }
         },
-        _ => { todo!() }
+        Undo => { todo!() },
+        Redo => { todo!() },
+        Clear => { todo!() },
+        StopAll => { todo!() },
+        Put(track, scene, phrase) => {
+            let old = state.scenes[scene].clips[track].clone();
+            state.scenes[scene].clips[track] = phrase;
+            Some(Put(track, scene, old))
+        },
     }
 });
-command!(|self:ArrangerSceneCommand,state:ArrangerTui|match self {
-    //Self::Delete(index) => { state.scene_del(index); },
-    Self::SetColor(index, color) => {
-        let old = state.scenes[index].color;
-        state.scenes[index].color = color;
-        Some(Self::SetColor(index, old))
-    },
-    _ => None
-});
-command!(|self: ArrangerTrackCommand, state: ArrangerTui|match self {
-    Self::SetColor(index, color) => {
-        let old = state.tracks[index].color;
-        state.tracks[index].color = color;
-        Some(Self::SetColor(index, old))
-    },
-    _ => None
-});
-command!(|self:ArrangerClipCommand, _state:ArrangerTui|match self {
-    _ => None
-});
-#[derive(Clone, Debug)]
-pub enum ArrangerClipCommand {
-    Play,
-    Get(usize, usize),
-    Set(usize, usize, Option<Arc<RwLock<Phrase>>>),
-    Edit(Option<Arc<RwLock<Phrase>>>),
-    SetLoop(bool),
-    RandomColor,
-}
 
 /// Display mode of arranger
 #[derive(Clone, PartialEq)]
diff --git a/crates/tek/src/tui/arranger_clip.rs b/crates/tek/src/tui/arranger_clip.rs
index b4685fb4..0a314338 100644
--- a/crates/tek/src/tui/arranger_clip.rs
+++ b/crates/tek/src/tui/arranger_clip.rs
@@ -21,3 +21,17 @@ pub fn to_arranger_clip_command (input: &TuiInput, t: usize, len_t: usize, s: us
         _ => return None
     })
 }
+
+command!(|self:ArrangerClipCommand, _state:ArrangerTui|match self {
+    _ => None
+});
+
+#[derive(Clone, Debug)]
+pub enum ArrangerClipCommand {
+    Play,
+    Get(usize, usize),
+    Set(usize, usize, Option<Arc<RwLock<Phrase>>>),
+    Edit(Option<Arc<RwLock<Phrase>>>),
+    SetLoop(bool),
+    RandomColor,
+}
diff --git a/crates/tek/src/tui/arranger_scene.rs b/crates/tek/src/tui/arranger_scene.rs
index 2b4d95a0..f9d0af70 100644
--- a/crates/tek/src/tui/arranger_scene.rs
+++ b/crates/tek/src/tui/arranger_scene.rs
@@ -1,4 +1,44 @@
 use crate::*;
+#[derive(Clone, Debug)]
+pub enum ArrangerSceneCommand {
+    Add,
+    Delete(usize),
+    RandomColor,
+    Play(usize),
+    Swap(usize, usize),
+    SetSize(usize),
+    SetZoom(usize),
+    SetColor(usize, ItemPalette),
+}
+pub fn to_arranger_scene_command (input: &TuiInput, s: usize, len: usize) -> Option<ArrangerCommand> {
+    use KeyCode::{Char, Delete};
+    use ArrangerCommand      as Cmd;
+    use ArrangerSelection    as Select;
+    use ArrangerSceneCommand as Scene;
+    Some(match input.event() {
+        key_pat!(Char('w')) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }),
+        key_pat!(Char('s')) => Cmd::Select(Select::Scene((s + 1).min(len.saturating_sub(1)))),
+        key_pat!(Char('d')) => Cmd::Select(Select::Clip(0, s)),
+        key_pat!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)),
+        key_pat!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)),
+        key_pat!(Char('<')) => Cmd::Scene(Scene::Swap(s, s - 1)),
+        key_pat!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)),
+        key_pat!(Char('q')) => Cmd::Scene(Scene::Play(s)),
+        key_pat!(Char('c')) => Cmd::Scene(Scene::SetColor(s, ItemPalette::random())),
+        key_pat!(Delete)    => Cmd::Scene(Scene::Delete(s)),
+        //key_pat!(Char('c')) => Cmd::Track(Scene::Color(s, ItemPalette::random())),
+        _ => return None
+    })
+}
+command!(|self:ArrangerSceneCommand,state:ArrangerTui|match self {
+    //Self::Delete(index) => { state.scene_del(index); },
+    Self::SetColor(index, color) => {
+        let old = state.scenes[index].color;
+        state.scenes[index].color = color;
+        Some(Self::SetColor(index, old))
+    },
+    _ => None
+});
 #[derive(Default, Debug, Clone)] pub struct ArrangerScene {
     /// Name of scene
     pub(crate) name:  Arc<RwLock<String>>,
@@ -62,37 +102,6 @@ impl ArrangerScene {
         match self.clips().get(index) { Some(Some(clip)) => Some(clip), _ => None }
     }
 }
-#[derive(Clone, Debug)]
-pub enum ArrangerSceneCommand {
-    Add,
-    Delete(usize),
-    RandomColor,
-    Play(usize),
-    Swap(usize, usize),
-    SetSize(usize),
-    SetZoom(usize),
-    SetColor(usize, ItemPalette),
-}
-pub fn to_arranger_scene_command (input: &TuiInput, s: usize, len: usize) -> Option<ArrangerCommand> {
-    use KeyCode::{Char, Delete};
-    use ArrangerCommand      as Cmd;
-    use ArrangerSelection    as Select;
-    use ArrangerSceneCommand as Scene;
-    Some(match input.event() {
-        key_pat!(Char('w')) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }),
-        key_pat!(Char('s')) => Cmd::Select(Select::Scene((s + 1).min(len.saturating_sub(1)))),
-        key_pat!(Char('d')) => Cmd::Select(Select::Clip(0, s)),
-        key_pat!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)),
-        key_pat!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)),
-        key_pat!(Char('<')) => Cmd::Scene(Scene::Swap(s, s - 1)),
-        key_pat!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)),
-        key_pat!(Char('q')) => Cmd::Scene(Scene::Play(s)),
-        key_pat!(Char('c')) => Cmd::Scene(Scene::SetColor(s, ItemPalette::random())),
-        key_pat!(Delete)    => Cmd::Scene(Scene::Delete(s)),
-        //key_pat!(Char('c')) => Cmd::Track(Scene::Color(s, ItemPalette::random())),
-        _ => return None
-    })
-}
 impl ArrangerTui {
     pub fn scenes (&self) -> &Vec<ArrangerScene> {
         &self.scenes
@@ -123,65 +132,3 @@ impl ArrangerTui {
         self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten()
     }
 }
-//impl Command<ArrangerModel> for ArrangerSceneCommand {
-//}
-            //Edit(phrase)   => { state.state.phrase = phrase.clone() },
-            //ToggleViewMode => { state.state.mode.to_next(); },
-            //Delete         => { state.state.delete(); },
-            //Activate       => { state.state.activate(); },
-            //ZoomIn         => { state.state.zoom_in(); },
-            //ZoomOut        => { state.state.zoom_out(); },
-            //MoveBack       => { state.state.move_back(); },
-            //MoveForward    => { state.state.move_forward(); },
-            //RandomColor    => { state.state.randomize_color(); },
-            //Put            => { state.state.phrase_put(); },
-            //Get            => { state.state.phrase_get(); },
-            //AddScene       => { state.state.scene_add(None, None)?; },
-            //AddTrack       => { state.state.track_add(None, None)?; },
-            //ToggleLoop     => { state.state.toggle_loop() },
-    //pub fn zoom_in (&mut self) {
-        //if let ArrangerEditorMode::V(factor) = self.mode {
-            //self.mode = ArrangerEditorMode::V(factor + 1)
-        //}
-    //}
-    //pub fn zoom_out (&mut self) {
-        //if let ArrangerEditorMode::V(factor) = self.mode {
-            //self.mode = ArrangerEditorMode::V(factor.saturating_sub(1))
-        //}
-    //}
-    //pub fn move_back (&mut self) {
-        //match self.selected {
-            //ArrangerEditorFocus::Scene(s) => {
-                //if s > 0 {
-                    //self.scenes.swap(s, s - 1);
-                    //self.selected = ArrangerEditorFocus::Scene(s - 1);
-                //}
-            //},
-            //ArrangerEditorFocus::Track(t) => {
-                //if t > 0 {
-                    //self.tracks.swap(t, t - 1);
-                    //self.selected = ArrangerEditorFocus::Track(t - 1);
-                    //// FIXME: also swap clip order in scenes
-                //}
-            //},
-            //_ => todo!("arrangement: move forward")
-        //}
-    //}
-    //pub fn move_forward (&mut self) {
-        //match self.selected {
-            //ArrangerEditorFocus::Scene(s) => {
-                //if s < self.scenes.len().saturating_sub(1) {
-                    //self.scenes.swap(s, s + 1);
-                    //self.selected = ArrangerEditorFocus::Scene(s + 1);
-                //}
-            //},
-            //ArrangerEditorFocus::Track(t) => {
-                //if t < self.tracks.len().saturating_sub(1) {
-                    //self.tracks.swap(t, t + 1);
-                    //self.selected = ArrangerEditorFocus::Track(t + 1);
-                    //// FIXME: also swap clip order in scenes
-                //}
-            //},
-            //_ => todo!("arrangement: move forward")
-        //}
-    //}
diff --git a/crates/tek/src/tui/arranger_track.rs b/crates/tek/src/tui/arranger_track.rs
index bc81c239..cde88c30 100644
--- a/crates/tek/src/tui/arranger_track.rs
+++ b/crates/tek/src/tui/arranger_track.rs
@@ -1,38 +1,32 @@
 use crate::*;
 use KeyCode::{Char, Delete};
 
-impl ArrangerTui {
-    pub fn tracks (&self) -> &Vec<ArrangerTrack> {
-        &self.tracks
-    }
-    pub fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> {
-        &mut self.tracks
-    }
-    pub fn track_next_name (&self) -> String {
-        format!("T{}", self.tracks().len() + 1)
-    }
-    pub fn track_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
-        -> Usually<&mut ArrangerTrack>
-    {
-        let name = name.map_or_else(||self.track_next_name(), |x|x.to_string());
-        let track = ArrangerTrack {
-            width:  name.len() + 2,
-            name:   Arc::new(name.into()),
-            color:  color.unwrap_or_else(||ItemPalette::random()),
-            player: PhrasePlayerModel::from(&self.clock),
-        };
-        self.tracks_mut().push(track);
-        let index = self.tracks().len() - 1;
-        Ok(&mut self.tracks_mut()[index])
-    }
-    pub fn track_del (&mut self, index: usize) {
-        self.tracks_mut().remove(index);
-        for scene in self.scenes_mut().iter_mut() {
-            scene.clips.remove(index);
-        }
-    }
+pub fn to_arranger_track_command (input: &TuiInput, t: usize, len: usize) -> Option<ArrangerCommand> {
+    use ArrangerCommand::*;
+    use ArrangerSelection as Selected;
+    use ArrangerTrackCommand as Tracks;
+    Some(match input.event() {
+        key_pat!(Char('s')) => Select(Selected::Clip(t, 0)),
+        key_pat!(Char('a')) => Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }),
+        key_pat!(Char('d')) => Select(Selected::Track((t + 1).min(len.saturating_sub(1)))),
+        key_pat!(Char('c')) => Track(Tracks::SetColor(t, ItemPalette::random())),
+        key_pat!(Char(',')) => Track(Tracks::Swap(t, t - 1)),
+        key_pat!(Char('.')) => Track(Tracks::Swap(t, t + 1)),
+        key_pat!(Char('<')) => Track(Tracks::Swap(t, t - 1)),
+        key_pat!(Char('>')) => Track(Tracks::Swap(t, t + 1)),
+        key_pat!(Delete)    => Track(Tracks::Delete(t)),
+        //key_pat!(Char('c')) => Cmd::Track(Track::Color(t, ItemPalette::random())),
+        _ => return None
+    })
 }
-
+command!(|self: ArrangerTrackCommand, state: ArrangerTui|match self {
+    Self::SetColor(index, color) => {
+        let old = state.tracks[index].color;
+        state.tracks[index].color = color;
+        Some(Self::SetColor(index, old))
+    },
+    _ => None
+});
 
 #[derive(Debug)] pub struct ArrangerTrack {
     /// Name of track
@@ -132,21 +126,34 @@ impl<'a> Audio for TracksAudio<'a> {
         Control::Continue
     }
 }
-pub fn to_arranger_track_command (input: &TuiInput, t: usize, len: usize) -> Option<ArrangerCommand> {
-    use ArrangerCommand::*;
-    use ArrangerSelection as Selected;
-    use ArrangerTrackCommand as Tracks;
-    Some(match input.event() {
-        key_pat!(Char('s')) => Select(Selected::Clip(t, 0)),
-        key_pat!(Char('a')) => Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }),
-        key_pat!(Char('d')) => Select(Selected::Track((t + 1).min(len.saturating_sub(1)))),
-        key_pat!(Char('c')) => Track(Tracks::SetColor(t, ItemPalette::random())),
-        key_pat!(Char(',')) => Track(Tracks::Swap(t, t - 1)),
-        key_pat!(Char('.')) => Track(Tracks::Swap(t, t + 1)),
-        key_pat!(Char('<')) => Track(Tracks::Swap(t, t - 1)),
-        key_pat!(Char('>')) => Track(Tracks::Swap(t, t + 1)),
-        key_pat!(Delete)    => Track(Tracks::Delete(t)),
-        //key_pat!(Char('c')) => Cmd::Track(Track::Color(t, ItemPalette::random())),
-        _ => return None
-    })
+impl ArrangerTui {
+    pub fn tracks (&self) -> &Vec<ArrangerTrack> {
+        &self.tracks
+    }
+    pub fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> {
+        &mut self.tracks
+    }
+    pub fn track_next_name (&self) -> String {
+        format!("T{}", self.tracks().len() + 1)
+    }
+    pub fn track_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
+        -> Usually<&mut ArrangerTrack>
+    {
+        let name = name.map_or_else(||self.track_next_name(), |x|x.to_string());
+        let track = ArrangerTrack {
+            width:  name.len() + 2,
+            name:   Arc::new(name.into()),
+            color:  color.unwrap_or_else(||ItemPalette::random()),
+            player: PhrasePlayerModel::from(&self.clock),
+        };
+        self.tracks_mut().push(track);
+        let index = self.tracks().len() - 1;
+        Ok(&mut self.tracks_mut()[index])
+    }
+    pub fn track_del (&mut self, index: usize) {
+        self.tracks_mut().remove(index);
+        for scene in self.scenes_mut().iter_mut() {
+            scene.clips.remove(index);
+        }
+    }
 }