tek/crates/device/src/arranger/arranger_scenes.rs

139 lines
4.6 KiB
Rust

use crate::*;
impl<T: Has<Vec<Scene>> + Send + Sync> HasScenes for T {}
pub trait HasScenes: Has<Vec<Scene>> + Send + Sync {
fn scenes (&self) -> &Vec<Scene> {
Has::<Vec<Scene>>::get(self)
}
fn scenes_mut (&mut self) -> &mut Vec<Scene> {
Has::<Vec<Scene>>::get_mut(self)
}
/// Generate the default name for a new scene
fn scene_default_name (&self) -> Arc<str> {
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<T: HasScenes + HasTracks> 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<ItemTheme>)
-> 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<bool> { todo!() }
fn _todo_usize_stub_ (&self) -> usize { todo!() }
fn _todo_arc_str_stub_ (&self) -> Arc<str> { todo!() }
fn _todo_item_theme_stub (&self) -> ItemTheme { todo!() }
}
#[tengri_proc::command(Scene)]
impl SceneCommand {
fn set_name (scene: &mut Scene, mut name: Arc<str>) -> Perhaps<Self> {
std::mem::swap(&mut scene.name, &mut name);
Ok(Some(Self::SetName { name }))
}
fn set_color (scene: &mut Scene, mut color: ItemTheme) -> Perhaps<Self> {
std::mem::swap(&mut scene.color, &mut color);
Ok(Some(Self::SetColor { color }))
}
fn set_size (scene: &mut Scene, size: usize) -> Perhaps<Self> {
todo!()
}
fn set_zoom (scene: &mut Scene, zoom: usize) -> Perhaps<Self> {
todo!()
}
}
impl<T: Has<Option<Scene>> + Send + Sync> HasScene for T {}
pub trait HasScene: Has<Option<Scene>> + Send + Sync {
fn scene (&self) -> Option<&Scene> {
Has::<Option<Scene>>::get(self).as_ref()
}
fn scene_mut (&mut self) -> &mut Option<Scene> {
Has::<Option<Scene>>::get_mut(self)
}
}
#[derive(Debug, Default)]
pub struct Scene {
/// Name of scene
pub name: Arc<str>,
/// Identifying color of scene
pub color: ItemTheme,
/// Clips in scene, one per track
pub clips: Vec<Option<Arc<RwLock<MidiClip>>>>,
}
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<RwLock<MidiClip>>> {
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,
//})),