mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-09-18 04:46:43 +02:00
186 lines
6.3 KiB
Rust
186 lines
6.3 KiB
Rust
use crate::*;
|
|
|
|
/// Arranger.
|
|
///
|
|
/// ```
|
|
/// let arranger = tek::Arrangement::default();
|
|
/// ```
|
|
#[derive(Default, Debug)]
|
|
pub struct Arrangement {
|
|
/// JACK client handle.
|
|
pub jack: Jack<'static>,
|
|
/// Project name.
|
|
pub name: Arc<str>,
|
|
/// Base color.
|
|
pub color: ItemTheme,
|
|
/// FIXME a render of the project arrangement, redrawn on update.
|
|
/// TODO rename to "render_cache" or smth
|
|
pub arranger: Arc<RwLock<Buffer>>,
|
|
/// Display size
|
|
pub size: Sizer,
|
|
/// Display size of clips area
|
|
pub size_inner: Sizer,
|
|
/// Selected UI element
|
|
pub selection: Selection,
|
|
/// Source of time
|
|
#[cfg(feature = "clock")] pub clock: Clock,
|
|
/// Allows one MIDI clip to be edited
|
|
#[cfg(feature = "editor")] pub editor: Option<MidiEditor>,
|
|
/// List of global midi inputs
|
|
#[cfg(feature = "port")] pub midi_ins: Vec<MidiInput>,
|
|
/// List of global midi outputs
|
|
#[cfg(feature = "port")] pub midi_outs: Vec<MidiOutput>,
|
|
/// List of global audio inputs
|
|
#[cfg(feature = "port")] pub audio_ins: Vec<AudioInput>,
|
|
/// List of global audio outputs
|
|
#[cfg(feature = "port")] pub audio_outs: Vec<AudioOutput>,
|
|
/// Last track number (to avoid duplicate port names)
|
|
#[cfg(feature = "track")] pub track_last: usize,
|
|
/// List of tracks
|
|
#[cfg(feature = "track")] pub tracks: Vec<Track>,
|
|
/// Scroll offset of tracks
|
|
#[cfg(feature = "track")] pub track_scroll: usize,
|
|
/// List of scenes
|
|
#[cfg(feature = "scene")] pub scenes: Vec<Scene>,
|
|
/// Scroll offset of scenes
|
|
#[cfg(feature = "scene")] pub scene_scroll: usize,
|
|
}
|
|
|
|
impl Arrangement {
|
|
|
|
/// Create a new arrangement.
|
|
pub fn new (
|
|
jack: &Jack<'static>,
|
|
name: Arc<str>,
|
|
clock: Clock,
|
|
tracks: impl Iterator<Item = Track>,
|
|
scenes: impl Iterator<Item = Scene>,
|
|
midi_ins: impl Iterator<Item = MidiInput>,
|
|
midi_outs: impl Iterator<Item = MidiOutput>,
|
|
audio_ins: impl Iterator<Item = AudioInput>,
|
|
audio_outs: impl Iterator<Item = AudioOutput>,
|
|
) -> Self {
|
|
Self {
|
|
jack: jack.clone(),
|
|
color: ItemTheme::random(),
|
|
selection: Selection::TrackClip { track: 0, scene: 0 },
|
|
tracks: tracks.collect(),
|
|
scenes: scenes.collect(),
|
|
midi_ins: midi_ins.collect(),
|
|
midi_outs: midi_outs.collect(),
|
|
audio_ins: audio_ins.collect(),
|
|
audio_outs: audio_outs.collect(),
|
|
size_inner: Sizer(Arc::new(40.into()), Arc::new(25.into())),
|
|
clock,
|
|
name,
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
/// 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 available to display tracks.
|
|
pub fn w_tracks_area (&self, is_editing: bool) -> u16 {
|
|
self.w().saturating_sub(self.w_sidebar(is_editing))
|
|
}
|
|
|
|
/// Height of display
|
|
pub fn h (&self) -> u16 {
|
|
self.size.h() as u16
|
|
}
|
|
|
|
/// 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 first sampler of the active track
|
|
#[cfg(feature = "sampler")]
|
|
impl Arrangement {
|
|
pub fn sampler (&self) -> Option<&Sampler> {
|
|
self.selected_track()?.sampler(0)
|
|
}
|
|
|
|
/// Get the first sampler of the active track
|
|
#[cfg(feature = "sampler")]
|
|
pub fn sampler_mut (&mut self) -> Option<&mut Sampler> {
|
|
self.selected_track_mut()?.sampler_mut(0)
|
|
}
|
|
}
|
|
|
|
impl HasJack<'static> for Arrangement { fn jack (&self) -> &Jack<'static> { &self.jack } }
|
|
impl_has!(Jack<'static>: |self: Arrangement| self.jack);
|
|
impl_has!(Sizer: |self: Arrangement| self.size);
|
|
impl_has!(Clock: |self: Arrangement| self.clock);
|
|
impl_has!(Selection: |self: Arrangement| self.selection);
|
|
impl_as_ref_opt!(MidiEditor: |self: Arrangement| self.editor.as_ref());
|
|
impl_as_mut_opt!(MidiEditor: |self: Arrangement| self.editor.as_mut());
|
|
|
|
/// Define a type alias for iterators of sized items (columns).
|
|
macro_rules! def_sizes_iter {
|
|
($Type:ident => $($Item:ty),+) => {
|
|
pub trait $Type<'a>: Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a {}
|
|
impl<'a, T: Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a> $Type<'a> for T {}
|
|
}
|
|
}
|
|
|
|
mod clip; pub use self::clip::*;
|
|
mod scene; pub use self::scene::*;
|
|
mod select; pub use self::select::*;
|
|
mod port; pub use self::port::*;
|
|
mod track; pub use self::track::*;
|
|
|
|
pub(self) fn swap_value <T: Clone + PartialEq, U> (
|
|
target: &mut T, value: &T, returned: impl Fn(T)->U
|
|
) -> Perhaps<U> {
|
|
if *target == *value {
|
|
Ok(None)
|
|
} else {
|
|
let mut value = value.clone();
|
|
std::mem::swap(target, &mut value);
|
|
Ok(Some(returned(value)))
|
|
}
|
|
}
|
|
|
|
pub(self) fn toggle_bool <U> (
|
|
target: &mut bool, value: &Option<bool>, returned: impl Fn(Option<bool>)->U
|
|
) -> Perhaps<U> {
|
|
let mut value = value.unwrap_or(!*target);
|
|
if value == *target {
|
|
Ok(None)
|
|
} else {
|
|
std::mem::swap(target, &mut value);
|
|
Ok(Some(returned(Some(value))))
|
|
}
|
|
}
|
|
|
|
//pub fn per_track <'a, T: Draw<'_, Tui> + 'a, U: TracksSizes<'a>> (
|
|
//tracks: impl Fn() -> U + Send + Sync + 'a,
|
|
//callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
|
|
//) -> impl Draw<'_, Tui> + 'a {
|
|
//per_track_top(tracks, move|index, track|callback(index, track).full_h().align_y())
|
|
//}
|
|
|
|
//pub fn per_track_top <'a, T: Draw<'_, Tui> + 'a, U: TracksSizes<'a>> (
|
|
//tracks: impl Fn() -> U + Send + Sync + 'a,
|
|
//callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
|
|
//) -> impl Draw<'_, Tui> + 'a {
|
|
//bg(Reset, iter_east(||tracks()
|
|
//.map(move|(index, track, x1, x2): (usize, &'a Track, usize, usize)|{
|
|
//fg_bg(
|
|
//track.color.lightest.term,
|
|
//track.color.base.term,
|
|
//callback(index, track)
|
|
//).exact_w((x2 - x1) as u16)
|
|
//})).align_x())
|
|
//}
|