mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
282 lines
9.5 KiB
Rust
282 lines
9.5 KiB
Rust
use crate::*;
|
|
mod view_clock; pub use self::view_clock::*;
|
|
mod view_color; pub use self::view_color::*;
|
|
mod view_memo; pub use self::view_memo::*;
|
|
mod view_meter; pub use self::view_meter::*;
|
|
mod view_track; pub use self::view_track::*;
|
|
mod view_ports; pub use self::view_ports::*;
|
|
mod view_layout; pub use self::view_layout::*;
|
|
pub(crate) use std::fmt::Write;
|
|
pub(crate) use ::tengri::tui::ratatui::prelude::Position;
|
|
pub(crate) trait ScenesColors<'a> = Iterator<Item=SceneWithColor<'a>>;
|
|
pub(crate) type SceneWithColor<'a> = (usize, &'a Scene, usize, usize, Option<ItemPalette>);
|
|
pub(crate) struct ArrangerView<'a> {
|
|
app: &'a Tek,
|
|
|
|
is_editing: bool,
|
|
|
|
width: u16,
|
|
width_mid: u16,
|
|
width_side: u16,
|
|
|
|
inputs_count: usize,
|
|
inputs_height: u16,
|
|
|
|
outputs_count: usize,
|
|
outputs_height: u16,
|
|
|
|
scene_last: usize,
|
|
scene_count: usize,
|
|
scene_scroll: Fill<Fixed<u16, ScrollbarV>>,
|
|
scene_selected: Option<usize>,
|
|
scenes_height: u16,
|
|
|
|
track_scroll: Fill<Fixed<u16, ScrollbarH>>,
|
|
track_count: usize,
|
|
track_selected: Option<usize>,
|
|
tracks_height: u16,
|
|
|
|
show_debug_info: bool,
|
|
}
|
|
|
|
impl<'a> Content<TuiOut> for ArrangerView<'a> {
|
|
fn content (&self) -> impl Render<TuiOut> {
|
|
let ins = |x|Bsp::s(self.inputs(), x);
|
|
let tracks = |x|Bsp::s(self.tracks(), x);
|
|
let outs = |x|Bsp::n(self.outputs(), x);
|
|
let bg = |x|Tui::bg(Color::Reset, x);
|
|
//let track_scroll = |x|Bsp::s(&self.track_scroll, x);
|
|
//let scene_scroll = |x|Bsp::e(&self.scene_scroll, x);
|
|
ins(tracks(outs(bg(self.scenes()))))
|
|
}
|
|
}
|
|
|
|
impl<'a> ArrangerView<'a> {
|
|
pub fn new (app: &'a Tek) -> Self {
|
|
Self {
|
|
app,
|
|
is_editing: app.is_editing(),
|
|
|
|
width: app.w(),
|
|
width_mid: app.w_tracks_area(),
|
|
width_side: app.w_sidebar(),
|
|
|
|
inputs_height: app.h_inputs().saturating_sub(1),
|
|
inputs_count: app.midi_ins.len(),
|
|
|
|
outputs_height: app.h_outputs().saturating_sub(1),
|
|
outputs_count: app.midi_outs.len(),
|
|
|
|
scenes_height: app.h_scenes_area(),
|
|
scene_selected: app.selected().scene(),
|
|
scene_count: app.scenes.len(),
|
|
scene_last: app.scenes.len().saturating_sub(1),
|
|
scene_scroll: Fill::y(Fixed::x(1, ScrollbarV {
|
|
offset: app.scene_scroll,
|
|
length: app.h_scenes_area() as usize,
|
|
total: app.h_scenes() as usize,
|
|
})),
|
|
|
|
tracks_height: app.h_tracks_area(),
|
|
track_count: app.tracks.len(),
|
|
track_selected: app.selected().track(),
|
|
track_scroll: Fill::x(Fixed::y(1, ScrollbarH {
|
|
offset: app.track_scroll,
|
|
length: app.h_tracks_area() as usize,
|
|
total: app.h_scenes() as usize,
|
|
})),
|
|
|
|
show_debug_info: false
|
|
}
|
|
}
|
|
|
|
pub(crate) fn tracks_with_sizes_scrolled (&'a self)
|
|
-> impl TracksSizes<'a>
|
|
{
|
|
let width = self.width_mid;
|
|
self.app.tracks_with_sizes().map_while(move|(t, track, x1, x2)|{
|
|
(width > x2 as u16).then_some((t, track, x1, x2))
|
|
})
|
|
}
|
|
|
|
pub(crate) fn scenes_with_scene_colors (&self)
|
|
-> impl ScenesColors<'_>
|
|
{
|
|
self.app.scenes_with_sizes(self.is_editing, Tek::H_SCENE, Tek::H_EDITOR).map_while(
|
|
move|(s, scene, y1, y2)|if y2 as u16 > self.scenes_height {
|
|
None
|
|
} else { Some((s, scene, y1, y2, if s == 0 {
|
|
None
|
|
} else {
|
|
Some(self.app.scenes()[s-1].color)
|
|
}))
|
|
})
|
|
}
|
|
|
|
pub(crate) fn scenes_with_track_colors (&self)
|
|
-> impl ScenesColors<'_>
|
|
{
|
|
self.app.scenes_with_sizes(self.is_editing, Tek::H_SCENE, Tek::H_EDITOR).map_while(
|
|
move|(s, scene, y1, y2)|if y2 as u16 > self.scenes_height {
|
|
None
|
|
} else {
|
|
Some((s, scene, y1, y2, if s == 0 {
|
|
None
|
|
} else {
|
|
Some(self.app.scenes[s-1].clips[self.track_selected.unwrap_or(0)].as_ref()
|
|
.map(|c|c.read().unwrap().color)
|
|
.unwrap_or(ItemPalette::G[32]))
|
|
}))
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Tek {
|
|
/// Spacing between tracks.
|
|
pub(crate) const TRACK_SPACING: usize = 0;
|
|
/// Default scene height.
|
|
pub(crate) const H_SCENE: usize = 2;
|
|
/// Default editor height.
|
|
pub(crate) const H_EDITOR: usize = 15;
|
|
|
|
/// Width of display
|
|
pub(crate) fn w (&self) -> u16 {
|
|
self.size.w() as u16
|
|
}
|
|
pub(crate) fn w_sidebar (&self) -> u16 {
|
|
self.w() / if self.is_editing() { 16 } else { 8 } as u16
|
|
}
|
|
/// Width taken by all tracks.
|
|
pub(crate) fn w_tracks (&self) -> u16 {
|
|
self.tracks_with_sizes().last().map(|(_, _, _, x)|x as u16).unwrap_or(0)
|
|
}
|
|
/// Width available to display tracks.
|
|
pub(crate) fn w_tracks_area (&self) -> u16 {
|
|
self.w().saturating_sub(2 * self.w_sidebar())
|
|
}
|
|
/// Height of display
|
|
pub(crate) fn h (&self) -> u16 {
|
|
self.size.h() as u16
|
|
}
|
|
/// Height available to display track headers.
|
|
pub(crate) fn h_tracks_area (&self) -> u16 {
|
|
5
|
|
//self.h().saturating_sub(self.h_inputs() + self.h_outputs())
|
|
}
|
|
/// Height available to display tracks.
|
|
pub(crate) fn h_scenes_area (&self) -> u16 {
|
|
//15
|
|
self.h().saturating_sub(self.h_inputs() + self.h_outputs() + 11)
|
|
}
|
|
/// Height taken by all inputs.
|
|
pub(crate) fn h_inputs (&self) -> u16 {
|
|
1 + self.inputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0)
|
|
}
|
|
/// Height taken by all outputs.
|
|
pub(crate) fn h_outputs (&self) -> u16 {
|
|
1 + self.outputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0)
|
|
}
|
|
/// Height taken by all scenes.
|
|
pub(crate) fn h_scenes (&self) -> u16 {
|
|
self.scenes_with_sizes(self.is_editing(), Self::H_SCENE, Self::H_EDITOR).last()
|
|
.map(|(_, _, _, y)|y as u16).unwrap_or(0)
|
|
}
|
|
|
|
pub(crate) fn inputs_with_sizes (&self)
|
|
-> impl PortsSizes<'_>
|
|
{
|
|
let mut y = 0;
|
|
self.midi_ins.iter().enumerate().map(move|(i, input)|{
|
|
let height = 1 + input.conn().len();
|
|
let data = (i, input.name(), input.conn(), y, y + height);
|
|
y += height;
|
|
data
|
|
})
|
|
}
|
|
|
|
pub(crate) fn outputs_with_sizes (&self)
|
|
-> impl PortsSizes<'_>
|
|
{
|
|
let mut y = 0;
|
|
self.midi_outs.iter().enumerate().map(move|(i, output)|{
|
|
let height = 1 + output.conn().len();
|
|
let data = (i, output.name(), output.conn(), y, y + height);
|
|
y += height;
|
|
data
|
|
})
|
|
}
|
|
|
|
pub(crate) fn tracks_with_sizes (&self)
|
|
-> impl TracksSizes<'_>
|
|
{
|
|
let mut x = 0;
|
|
let editing = self.is_editing();
|
|
let active = match self.selected() {
|
|
Selection::Track(t) if editing => Some(t),
|
|
Selection::Clip(t, _) if editing => Some(t),
|
|
_ => None
|
|
};
|
|
let bigger = self.editor_w();
|
|
self.tracks().iter().enumerate().map(move |(index, track)|{
|
|
let width = if Some(index) == active.copied() { bigger } else { track.width.max(8) };
|
|
let data = (index, track, x, x + width);
|
|
x += width + Tek::TRACK_SPACING;
|
|
data
|
|
})
|
|
}
|
|
|
|
pub(crate) fn scenes_with_sizes (&self, editing: bool, height: usize, larger: usize)
|
|
-> impl ScenesSizes<'_>
|
|
{
|
|
let (selected_track, selected_scene) = match self.selected() {
|
|
Selection::Track(t) => (Some(*t), None),
|
|
Selection::Scene(s) => (None, Some(*s)),
|
|
Selection::Clip(t, s) => (Some(*t), Some(*s)),
|
|
_ => (None, None)
|
|
};
|
|
let mut y = 0;
|
|
self.scenes().iter().enumerate().map(move|(s, scene)|{
|
|
let active = editing && selected_track.is_some() && selected_scene == Some(s);
|
|
let height = if active { larger } else { height };
|
|
let data = (s, scene, y, y + height);
|
|
y += height;
|
|
data
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
/// Define a type alias for iterators of sized items (columns).
|
|
macro_rules! def_sizes_iter {
|
|
($Type:ident => $($Item:ty),+) => {
|
|
pub(crate) trait $Type<'a> =
|
|
Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a;}}
|
|
|
|
def_sizes_iter!(ScenesSizes => Scene);
|
|
def_sizes_iter!(TracksSizes => Track);
|
|
def_sizes_iter!(InputsSizes => JackMidiIn);
|
|
def_sizes_iter!(OutputsSizes => JackMidiOut);
|
|
def_sizes_iter!(PortsSizes => Arc<str>, [PortConnect]);
|
|
|
|
#[cfg(test)] #[test] fn test_view_iter () {
|
|
let mut tek = Tek::default();
|
|
tek.editor = Some(Default::default());
|
|
let _: Vec<_> = tek.inputs_with_sizes().collect();
|
|
let _: Vec<_> = tek.outputs_with_sizes().collect();
|
|
let _: Vec<_> = tek.tracks_with_sizes().collect();
|
|
let _: Vec<_> = tek.scenes_with_sizes(true, 10, 10).collect();
|
|
//let _: Vec<_> = tek.scenes_with_colors(true, 10).collect();
|
|
//let _: Vec<_> = tek.scenes_with_track_colors(true, 10, 10).collect();
|
|
}
|
|
#[cfg(test)] #[test] fn test_view_sizes () {
|
|
let app = Tek::default();
|
|
let _ = app.w();
|
|
let _ = app.w_sidebar();
|
|
let _ = app.w_tracks_area();
|
|
let _ = app.h();
|
|
let _ = app.h_tracks_area();
|
|
let _ = app.h_inputs();
|
|
let _ = app.h_outputs();
|
|
let _ = app.h_scenes();
|
|
}
|