//! Clip launcher and arrangement editor. use crate::*; /// Represents the tracks and scenes of the composition. pub struct Arranger { /// Name of arranger pub name: Arc>, /// Collection of tracks. pub tracks: Vec>, /// Collection of scenes. pub scenes: Vec, /// Currently selected element. pub selected: ArrangerFocus, /// Display mode of arranger pub mode: ArrangerViewMode, /// Slot for modal dialog displayed on top of app. pub modal: Option>>, /// Whether the arranger is currently focused pub focused: bool } impl Arranger { pub fn new (name: &str) -> Self { Self { name: Arc::new(RwLock::new(name.into())), mode: ArrangerViewMode::VerticalCompact2, selected: ArrangerFocus::Clip(0, 0), scenes: vec![], tracks: vec![], modal: None, focused: false } } pub fn activate (&mut self) { match self.selected { ArrangerFocus::Scene(s) => { for (track_index, track) in self.tracks.iter_mut().enumerate() { track.sequence = self.scenes[s].clips[track_index]; track.reset = true; } }, ArrangerFocus::Clip(t, s) => { self.tracks[t].sequence = self.scenes[s].clips[t]; self.tracks[t].reset = true; }, _ => {} } } pub fn sequencer (&self) -> Option<&Sequencer> { self.selected.track() .map(|track|self.tracks.get(track)) .flatten() } pub fn sequencer_mut (&mut self) -> Option<&mut Sequencer> { self.selected.track() .map(|track|self.tracks.get_mut(track)) .flatten() } pub fn show_phrase (&mut self) -> Usually<()> { //unimplemented!() //let phrase = self.phrase(); //self.sequencer.show(phrase) Ok(()) } pub fn is_first_row (&self) -> bool { let selected = self.selected; selected.is_mix() || selected.is_track() || match selected { ArrangerFocus::Clip(_, s) => s == 0, _ => false } } pub fn is_last_row (&self) -> bool { let selected = self.selected; match selected { ArrangerFocus::Scene(s) => s == self.scenes.len() - 1, ArrangerFocus::Clip(_, s) => s == self.scenes.len() - 1, _ => false } } } /// Display mode of arranger pub enum ArrangerViewMode { VerticalExpanded, VerticalCompact1, VerticalCompact2, Horizontal, } /// Arranger display mode can be cycled impl ArrangerViewMode { /// Cycle arranger display mode pub fn to_next (&mut self) { *self = match self { Self::VerticalExpanded => Self::VerticalCompact1, Self::VerticalCompact1 => Self::VerticalCompact2, Self::VerticalCompact2 => Self::Horizontal, Self::Horizontal => Self::VerticalExpanded, } } } impl Widget for Arranger { type Engine = Tui; fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { todo!() } fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { let area = (|to|match self.mode { ArrangerViewMode::Horizontal => super::arranger_view_h::draw(self, to), ArrangerViewMode::VerticalCompact1 => super::arranger_view_v::draw_compact_1(self, to), ArrangerViewMode::VerticalCompact2 => super::arranger_view_v::draw_compact_2(self, to), ArrangerViewMode::VerticalExpanded => super::arranger_view_v::draw_expanded(self, to), })(&mut to.alter_area(|[x, y, w, h]|[ x + 1, y + 1, w.saturating_sub(2), h.saturating_sub(2), ]))?.unwrap(); Lozenge(Style::default().fg(Nord::BG2)) .draw(&mut to.alter_area(|[x, y, w, h]|[ x.saturating_sub(1), y.saturating_sub(1), w + 2, h + 2, ])) } } impl Focusable for Arranger { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } }