use crate::*; pub struct Mixer { /// JACK client handle (needs to not be dropped for standalone mode to work). pub jack: Arc>, pub name: String, pub tracks: Vec>, pub selected_track: usize, pub selected_column: usize, } impl Mixer { pub fn new (jack: &Arc>, name: &str) -> Usually { Ok(Self { jack: jack.clone(), name: name.into(), selected_column: 0, selected_track: 1, tracks: vec![], }) } pub fn track_add (&mut self, name: &str, channels: usize) -> Usually<&mut Self> { let track = Track::new(name)?; self.tracks.push(track); Ok(self) } pub fn track (&self) -> Option<&Track> { self.tracks.get(self.selected_track) } } //pub const ACTIONS: [(&'static str, &'static str);2] = [ //("+/-", "Adjust"), //("Ins/Del", "Add/remove track"), //]; /// A sequencer track. #[derive(Debug)] pub struct Track { pub name: String, /// Inputs and outputs of 1st and last device pub ports: JackPorts, /// Device chain pub devices: Vec>, /// Device selector pub device: usize, } impl Track { pub fn new (name: &str) -> Usually { Ok(Self { name: name.to_string(), ports: JackPorts::default(), devices: vec![], device: 0, }) } fn get_device_mut (&self, i: usize) -> Option>>> { self.devices.get(i).map(|d|d.state.write().unwrap()) } pub fn device_mut (&self) -> Option>>> { self.get_device_mut(self.device) } /// Add a device to the end of the chain. pub fn append_device (&mut self, device: JackDevice) -> Usually<&mut JackDevice> { self.devices.push(device); let index = self.devices.len() - 1; Ok(&mut self.devices[index]) } pub fn add_device (&mut self, device: JackDevice) { self.devices.push(device); } //pub fn connect_first_device (&self) -> Usually<()> { //if let (Some(port), Some(device)) = (&self.midi_out, self.devices.get(0)) { //device.client.as_client().connect_ports(&port, &device.midi_ins()?[0])?; //} //Ok(()) //} //pub fn connect_last_device (&self, app: &Track) -> Usually<()> { //Ok(match self.devices.get(self.devices.len().saturating_sub(1)) { //Some(device) => { //app.audio_out(0).map(|left|device.connect_audio_out(0, &left)).transpose()?; //app.audio_out(1).map(|right|device.connect_audio_out(1, &right)).transpose()?; //() //}, //None => () //}) //} } pub struct TrackView<'a, E: Engine> { pub chain: Option<&'a Track>, pub direction: Direction, pub focused: bool, pub entered: bool, } impl<'a> Widget for TrackView<'a, Tui> { type Engine = Tui; fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> { todo!() } fn render (&self, to: &mut TuiOutput) -> Usually<()> { todo!(); //let mut area = to.area(); //if let Some(chain) = self.chain { //match self.direction { //Direction::Down => area.width = area.width.min(40), //Direction::Right => area.width = area.width.min(10), //_ => { unimplemented!() }, //} //to.fill_bg(to.area(), Nord::bg_lo(self.focused, self.entered)); //let mut split = Stack::new(self.direction); //for device in chain.devices.as_slice().iter() { //split = split.add_ref(device); //} //let (area, areas) = split.render_areas(to)?; //if self.focused && self.entered && areas.len() > 0 { //Corners(Style::default().green().not_dim()).draw(to.with_rect(areas[0]))?; //} //Ok(Some(area)) //} else { //let [x, y, width, height] = area; //let label = "No chain selected"; //let x = x + (width - label.len() as u16) / 2; //let y = y + height / 2; //to.blit(&label, x, y, Some(Style::default().dim().bold()))?; //Ok(Some(area)) //} } }