use crate::*; impl> + Send + Sync> HasScenes for T {} pub trait HasScenes: Has> + Send + Sync { fn scenes (&self) -> &Vec { Has::>::get(self) } fn scenes_mut (&mut self) -> &mut Vec { Has::>::get_mut(self) } /// Generate the default name for a new scene fn scene_default_name (&self) -> Arc { format!("s{:3>}", self.scenes().len() + 1).into() } fn scene_longest_name (&self) -> usize { self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max) } } pub trait HasSceneScroll: HasScenes { fn scene_scroll (&self) -> usize; } impl HasSceneScroll for Arrangement { fn scene_scroll (&self) -> usize { self.scene_scroll } } pub type SceneWith<'a, T: Send + Sync> = (usize, &'a Scene, usize, usize, T); impl AddScene for T {} pub trait AddScene: HasScenes + HasTracks { /// Add multiple scenes fn scenes_add (&mut self, n: usize) -> Usually<()> { let scene_color_1 = ItemColor::random(); let scene_color_2 = ItemColor::random(); for i in 0..n { let _ = self.scene_add(None, Some( scene_color_1.mix(scene_color_2, i as f32 / n as f32).into() ))?; } Ok(()) } /// Add a scene fn scene_add (&mut self, name: Option<&str>, color: Option) -> Usually<(usize, &mut Scene)> { let scene = Scene { name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()), clips: vec![None;self.tracks().len()], color: color.unwrap_or_else(ItemTheme::random), }; self.scenes_mut().push(scene); let index = self.scenes().len() - 1; Ok((index, &mut self.scenes_mut()[index])) } } #[tengri_proc::expose] impl Scene { fn _todo_opt_bool_stub_ (&self) -> Option { todo!() } fn _todo_usize_stub_ (&self) -> usize { todo!() } fn _todo_arc_str_stub_ (&self) -> Arc { todo!() } fn _todo_item_theme_stub (&self) -> ItemTheme { todo!() } } #[tengri_proc::command(Scene)] impl SceneCommand { fn set_name (scene: &mut Scene, mut name: Arc) -> Perhaps { std::mem::swap(&mut scene.name, &mut name); Ok(Some(Self::SetName { name })) } fn set_color (scene: &mut Scene, mut color: ItemTheme) -> Perhaps { std::mem::swap(&mut scene.color, &mut color); Ok(Some(Self::SetColor { color })) } fn set_size (scene: &mut Scene, size: usize) -> Perhaps { todo!() } fn set_zoom (scene: &mut Scene, zoom: usize) -> Perhaps { todo!() } } impl> + Send + Sync> HasScene for T {} pub trait HasScene: Has> + Send + Sync { fn scene (&self) -> Option<&Scene> { Has::>::get(self).as_ref() } fn scene_mut (&mut self) -> &mut Option { Has::>::get_mut(self) } } #[derive(Debug, Default)] pub struct Scene { /// Name of scene pub name: Arc, /// Identifying color of scene pub color: ItemTheme, /// Clips in scene, one per track pub clips: Vec>>>, } impl Scene { /// Returns the pulse length of the longest clip in the scene pub fn pulses (&self) -> usize { self.clips.iter().fold(0, |a, p|{ a.max(p.as_ref().map(|q|q.read().unwrap().length).unwrap_or(0)) }) } /// Returns true if all clips in the scene are /// currently playing on the given collection of tracks. pub fn is_playing (&self, tracks: &[Track]) -> bool { self.clips.iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate() .all(|(track_index, clip)|match clip { Some(c) => tracks .get(track_index) .map(|track|{ if let Some((_, Some(clip))) = track.sequencer().play_clip() { *clip.read().unwrap() == *c.read().unwrap() } else { false } }) .unwrap_or(false), None => true }) } pub fn clip (&self, index: usize) -> Option<&Arc>> { match self.clips.get(index) { Some(Some(clip)) => Some(clip), _ => None } } } //scene_scroll: Fill::y(Fixed::x(1, ScrollbarV { //offset: arrangement.scene_scroll, //length: h_scenes_area as usize, //total: h_scenes as usize, //})),