use crate::*; #[derive(Clone, Debug)] pub enum ArrangerCommand { Clear, Export, Import, StopAll, Scene(ArrangerSceneCommand), Track(ArrangerTrackCommand), Clip(ArrangerClipCommand), } pub trait ArrangerApi: HasJack + HasClock { fn name (&self) -> &Arc>; fn tracks (&self) -> &Vec; fn tracks_mut (&mut self) -> &mut Vec; fn scenes (&self) -> &Vec; fn scenes_mut (&mut self) -> &mut Vec; fn track_default_name (&self) -> String { format!("Track {}", self.tracks().len() + 1) } fn track_add ( &mut self, name: Option<&str>, color: Option ) -> Usually<&mut ArrangerTrack> { let name = name.map_or_else(||self.track_default_name(), |x|x.to_string()); let track = ArrangerTrack { width: name.len() + 2, color: color.unwrap_or_else(||ItemColor::random()), player: MIDIPlayer::new(&self.jack(), &self.clock(), name.as_str())?, name: Arc::new(name.into()), }; self.tracks_mut().push(track); let index = self.tracks().len() - 1; Ok(&mut self.tracks_mut()[index]) } fn track_del (&mut self, index: usize) { self.tracks_mut().remove(index); for scene in self.scenes_mut().iter_mut() { scene.clips.remove(index); } } fn scene_default_name (&self) -> String { format!("Scene {}", self.scenes().len() + 1) } fn scene_add ( &mut self, name: Option<&str>, color: Option ) -> Usually<&mut ArrangerScene> { let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string()); let scene = ArrangerScene { name: Arc::new(name.into()), clips: vec![None;self.tracks().len()], color: color.unwrap_or_else(||ItemColor::random()), }; self.scenes_mut().push(scene); let index = self.scenes().len() - 1; Ok(&mut self.scenes_mut()[index]) } fn scene_del (&mut self, index: usize) { self.scenes_mut().remove(index); } } impl Command for ArrangerCommand { fn execute (self, state: &mut ArrangerModel) -> Perhaps { match self { Self::Scene(command) => { return Ok(command.execute(state)?.map(Self::Scene)) }, Self::Track(command) => { return Ok(command.execute(state)?.map(Self::Track)) }, Self::Clip(command) => { return Ok(command.execute(state)?.map(Self::Clip)) }, _ => todo!() } Ok(None) } } //impl Command 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::Vertical(factor) = self.mode { //self.mode = ArrangerEditorMode::Vertical(factor + 1) //} //} //pub fn zoom_out (&mut self) { //if let ArrangerEditorMode::Vertical(factor) = self.mode { //self.mode = ArrangerEditorMode::Vertical(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") //} //}