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

187 lines
5.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::*;
impl<T: Has<Selection>> HasSelection for T {}
pub trait HasSelection: Has<Selection> {
fn selection (&self) -> &Selection {
self.get()
}
fn selection_mut (&mut self) -> &mut Selection {
self.get_mut()
}
}
impl Has<Option<Track>> for Arrangement {
fn get (&self) -> &Option<Track> {
Has::<Option<Selection>>::get(self)
.and_then(|selection|selection.track())
.and_then(|index|Has::<Vec<Track>>::get(self).get(index))
}
fn get_mut (&mut self) -> &mut Option<Track> {
Has::<Option<Selection>>::get(self)
.and_then(|selection|selection.track())
.and_then(|index|Has::<Vec<Track>>::get_mut(self).get_mut(index))
}
}
impl Has<Option<Scene>> for Arrangement {
fn get (&self) -> &Option<Scene> {
Has::<Option<Selection>>::get(self)
.and_then(|selection|selection.track())
.and_then(|index|Has::<Vec<Scene>>::get(self).get(index))
}
fn get_mut (&mut self) -> &mut Option<Scene> {
Has::<Option<Selection>>::get(self)
.and_then(|selection|selection.track())
.and_then(|index|Has::<Vec<Scene>>::get_mut(self).get_mut(index))
}
}
/// Represents the current user selection in the arranger
#[derive(PartialEq, Clone, Copy, Debug, Default)]
pub enum Selection {
/// The whole mix is selected
#[default] Mix,
/// A MIDI input is selected.
Input(usize),
/// A MIDI output is selected.
Output(usize),
/// A scene is selected.
Scene(usize),
/// A track is selected.
Track(usize),
/// A clip (track × scene) is selected.
TrackClip { track: usize, scene: usize },
/// A track's MIDI input connection is selected.
TrackInput { track: usize, port: usize },
/// A track's MIDI output connection is selected.
TrackOutput { track: usize, port: usize },
/// A track device slot is selected.
TrackDevice { track: usize, device: usize },
}
/// Focus identification methods
impl Selection {
pub fn is_mix (&self) -> bool {
matches!(self, Self::Mix)
}
pub fn is_track (&self) -> bool {
matches!(self, Self::Track(_))
}
pub fn is_scene (&self) -> bool {
matches!(self, Self::Scene(_))
}
pub fn is_clip (&self) -> bool {
matches!(self, Self::TrackClip {..})
}
pub fn track (&self) -> Option<usize> {
use Selection::*;
match self {
Track(track)
| TrackClip { track, .. }
| TrackInput { track, .. }
| TrackOutput { track, .. }
| TrackDevice { track, .. } => Some(*track),
_ => None
}
}
pub fn track_header (&self, track_count: usize) -> Self {
use Selection::*;
match self {
Mix => Track(0),
Scene(_) => Mix,
Track(t) => Track((t + 1) % track_count),
TrackClip { track, .. } => Track(*track),
_ => todo!(),
}
}
pub fn track_next (&self, len: usize) -> Self {
use Selection::*;
match self {
Mix => Track(0),
Scene(s) => TrackClip { track: 0, scene: *s },
Track(t) => if t + 1 < len {
Track(t + 1)
} else {
Mix
},
TrackClip {track, scene} => if track + 1 < len {
TrackClip { track: track + 1, scene: *scene }
} else {
Scene(*scene)
},
_ => todo!()
}
}
pub fn track_prev (&self) -> Self {
use Selection::*;
match self {
Mix => Mix,
Scene(s) => Scene(*s),
Track(0) => Mix,
Track(t) => Track(t - 1),
TrackClip { track: 0, scene } => Scene(*scene),
TrackClip { track: t, scene } => TrackClip { track: t - 1, scene: *scene },
_ => todo!()
}
}
pub fn scene (&self) -> Option<usize> {
use Selection::*;
match self {
Scene(scene) | TrackClip { scene, .. } => Some(*scene),
_ => None
}
}
pub fn scene_next (&self, len: usize) -> Self {
use Selection::*;
match self {
Mix => Scene(0),
Track(t) => TrackClip { track: *t, scene: 0 },
Scene(s) => if s + 1 < len {
Scene(s + 1)
} else {
Mix
},
TrackClip { track, scene } => if scene + 1 < len {
TrackClip { track: *track, scene: scene + 1 }
} else {
Track(*track)
},
_ => todo!()
}
}
pub fn scene_prev (&self) -> Self {
use Selection::*;
match self {
Mix | Scene(0) => Mix,
Scene(s) => Scene(s - 1),
Track(t) => Track(*t),
TrackClip { track, scene: 0 } => Track(*track),
TrackClip { track, scene } => TrackClip { track: *track, scene: scene - 1 },
_ => todo!()
}
}
pub fn describe (&self, tracks: &[Track], scenes: &[Scene]) -> Arc<str> {
use Selection::*;
format!("{}", match self {
Mix => "Everything".to_string(),
Scene(s) => scenes.get(*s)
.map(|scene|format!("S{s}: {}", &scene.name))
.unwrap_or_else(||"S??".into()),
Track(t) => tracks.get(*t)
.map(|track|format!("T{t}: {}", &track.name))
.unwrap_or_else(||"T??".into()),
TrackClip { track, scene } => match (tracks.get(*track), scenes.get(*scene)) {
(Some(_), Some(s)) => match s.clip(*track) {
Some(clip) => format!("T{track} S{scene} C{}", &clip.read().unwrap().name),
None => format!("T{track} S{scene}: Empty")
},
_ => format!("T{track} S{scene}: Empty"),
},
_ => todo!()
}).into()
}
}
impl Arrangement {
}