tek/src/select.rs
okay stopped screaming 60dbd89fc9 wip: 284 errors, later
2026-03-21 23:53:24 +02:00

161 lines
6.3 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::*;
/// Represents the current user selection in the arranger
#[derive(PartialEq, Clone, Copy, Debug, Default)] pub enum Selection {
#[default]
/// Nothing is selected
Nothing,
/// The whole mix is selected
Mix,
/// A MIDI input is selected.
Input(usize),
/// A MIDI output is selected.
Output(usize),
/// A scene is selected.
#[cfg(feature = "scene")] Scene(usize),
/// A track is selected.
#[cfg(feature = "track")] Track(usize),
/// A clip (track × scene) is selected.
#[cfg(feature = "track")] TrackClip { track: usize, scene: usize },
/// A track's MIDI input connection is selected.
#[cfg(feature = "track")] TrackInput { track: usize, port: usize },
/// A track's MIDI output connection is selected.
#[cfg(feature = "track")] TrackOutput { track: usize, port: usize },
/// A track device slot is selected.
#[cfg(feature = "track")] TrackDevice { track: usize, device: usize },
}
impl Selection {
pub fn describe (
&self,
#[cfg(feature = "track")] tracks: &[Track],
#[cfg(feature = "scene")] scenes: &[Scene],
) -> Arc<str> {
use Selection::*;
format!("{}", match self {
Mix => "Everything".to_string(),
#[cfg(feature = "scene")] Scene(s) =>
scenes.get(*s).map(|scene|format!("S{s}: {}", &scene.name)).unwrap_or_else(||"S??".into()),
#[cfg(feature = "track")] 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()
}
#[cfg(feature = "scene")] pub fn scene (&self) -> Option<usize> {
use Selection::*;
match self { Scene(scene) | TrackClip { scene, .. } => Some(*scene), _ => None }
}
#[cfg(feature = "scene")] pub fn select_scene (&self, scene_count: usize) -> Self {
use Selection::*;
match self {
Mix | Track(_) => Scene(0),
Scene(s) => Scene((s + 1) % scene_count),
TrackClip { scene, .. } => Track(*scene),
_ => todo!(),
}
}
#[cfg(feature = "scene")] pub fn select_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!()
}
}
#[cfg(feature = "scene")] pub fn select_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!()
}
}
#[cfg(feature = "track")] pub fn track (&self) -> Option<usize> {
use Selection::*;
if let Track(track)|TrackClip{track,..}|TrackInput{track,..}|TrackOutput{track,..}|TrackDevice{track,..} = self {
Some(*track)
} else {
None
}
}
#[cfg(feature = "track")] pub fn select_track (&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!(),
}
}
#[cfg(feature = "track")] pub fn select_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!()
}
}
#[cfg(feature = "track")] pub fn select_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!()
}
}
}
impl <T: AsRef<Selection>+AsMut<Selection>> HasSelection for T {}
pub trait HasSelection: AsRef<Selection> + AsMut<Selection> {
fn selection (&self) -> &Selection { self.as_ref() }
fn selection_mut (&mut self) -> &mut Selection { self.as_mut() }
/// Get the active track
#[cfg(feature = "track")]
fn selected_track (&self) -> Option<&Track> where Self: HasTracks {
let index = self.selection().track()?;
self.tracks().get(index)
}
/// Get a mutable reference to the active track
#[cfg(feature = "track")]
fn selected_track_mut (&mut self) -> Option<&mut Track> where Self: HasTracks {
let index = self.selection().track()?;
self.tracks_mut().get_mut(index)
}
/// Get the active scene
#[cfg(feature = "scene")]
fn selected_scene (&self) -> Option<&Scene> where Self: HasScenes {
let index = self.selection().scene()?;
self.scenes().get(index)
}
/// Get a mutable reference to the active scene
#[cfg(feature = "scene")]
fn selected_scene_mut (&mut self) -> Option<&mut Scene> where Self: HasScenes {
let index = self.selection().scene()?;
self.scenes_mut().get_mut(index)
}
/// Get the active clip
#[cfg(feature = "clip")]
fn selected_clip (&self) -> Option<Arc<RwLock<MidiClip>>> where Self: HasScenes + HasTracks {
self.selected_scene()?.clips.get(self.selection().track()?)?.clone()
}
}