use crate::*; #[derive(Default, Debug)] pub struct Arrangement { /// Project name. pub name: Arc, /// Base color. pub color: ItemTheme, /// Jack client handle pub jack: Jack, /// Source of time pub clock: Clock, /// List of global midi inputs pub midi_ins: Vec, /// List of global midi outputs pub midi_outs: Vec, /// List of global audio inputs pub audio_ins: Vec, /// List of global audio outputs pub audio_outs: Vec, /// Last track number (to avoid duplicate port names) pub track_last: usize, /// List of tracks pub tracks: Vec, /// Scroll offset of tracks pub track_scroll: usize, /// List of scenes pub scenes: Vec, /// Scroll offset of scenes pub scene_scroll: usize, /// Selected UI element pub selection: Selection, /// Contains a render of the project arrangement, redrawn on update. /// TODO rename to "render_cache" or smth pub arranger: Arc>, /// Display size pub size: Measure, /// Contains all clips in arrangement pub pool: Pool, } has!(Jack: |self: Arrangement|self.jack); has!(Clock: |self: Arrangement|self.clock); has!(Selection: |self: Arrangement|self.selection); has!(Vec: |self: Arrangement|self.midi_ins); has!(Vec: |self: Arrangement|self.midi_outs); has!(Vec: |self: Arrangement|self.scenes); has!(Vec: |self: Arrangement|self.tracks); has!(Measure: |self: Arrangement|self.size); impl Arrangement { /// Width of display pub fn w (&self) -> u16 { self.size.w() as u16 } /// Width allocated for sidebar. pub fn w_sidebar (&self, is_editing: bool) -> u16 { self.w() / if is_editing { 16 } else { 8 } as u16 } /// Width taken by all tracks. pub fn w_tracks (&self) -> u16 { self.tracks_with_sizes(&self.selection(), None).last() .map(|(_, _, _, x)|x as u16).unwrap_or(0) } /// Width available to display tracks. pub fn w_tracks_area (&self, is_editing: bool) -> u16 { self.w().saturating_sub(2 * self.w_sidebar(is_editing)) } /// Height of display pub fn h (&self) -> u16 { self.size.h() as u16 } /// Height available to display track headers. pub fn h_tracks_area (&self) -> u16 { 5 // FIXME //self.h().saturating_sub(self.h_inputs() + self.h_outputs()) } /// Height available to display tracks. pub fn h_scenes_area (&self) -> u16 { //15 self.h().saturating_sub( self.h_inputs() + self.h_outputs() + self.h_devices() + 13 // FIXME ) } /// Height taken by all scenes. pub fn h_scenes (&self, is_editing: bool) -> u16 { self.scenes_with_sizes( is_editing, ArrangerView::H_SCENE, ArrangerView::H_EDITOR, self.selection().track(), self.selection().scene(), ) .last() .map(|(_, _, _, y)|y as u16).unwrap_or(0) } /// Height taken by all inputs. pub fn h_inputs (&self) -> u16 { self.midi_ins_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } /// Height taken by all outputs. pub fn h_outputs (&self) -> u16 { self.midi_outs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } /// Height taken by visible device slots. pub fn h_devices (&self) -> u16 { 2 //1 + self.devices_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } /// Get the active track fn get_track (&self) -> Option<&Track> { let index = self.selection().track()?; Has::>::get(self).get(index) } /// Get a mutable reference to the active track fn get_track_mut (&mut self) -> Option<&mut Track> { let index = self.selection().track()?; Has::>::get_mut(self).get_mut(index) } /// Get the active scene fn get_scene (&self) -> Option<&Scene> { let index = self.selection().scene()?; Has::>::get(self).get(index) } /// Get a mutable reference to the active scene fn get_scene_mut (&mut self) -> Option<&mut Scene> { let index = self.selection().scene()?; Has::>::get_mut(self).get_mut(index) } /// Get the active clip fn get_clip (&self) -> Option>> { self.get_scene()?.clips.get(self.selection().track()?)?.clone() } /// Put a clip in a slot pub fn clip_put ( &mut self, track: usize, scene: usize, clip: Option>> ) -> Option>> { let old = self.scenes[scene].clips[track].clone(); self.scenes[scene].clips[track] = clip; old } /// Change the color of a clip, returning the previous one pub fn clip_set_color (&self, track: usize, scene: usize, color: ItemTheme) -> Option { self.scenes[scene].clips[track].as_ref().map(|clip|{ let mut clip = clip.write().unwrap(); let old = clip.color.clone(); clip.color = color.clone(); panic!("{color:?} {old:?}"); old }) } /// Toggle looping for the active clip pub fn toggle_loop (&mut self) { if let Some(clip) = self.get_clip() { clip.write().unwrap().toggle_loop() } } } #[cfg(feature = "sampler")] impl Arrangement { /// Get the first sampler of the active track pub fn sampler (&self) -> Option<&Sampler> { self.get_track()?.sampler(0) } /// Get the first sampler of the active track pub fn sampler_mut (&mut self) -> Option<&mut Sampler> { self.get_track_mut()?.sampler_mut(0) } }