mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
somewhat more like it
This commit is contained in:
parent
f6ab777c82
commit
d3d1670af2
2 changed files with 602 additions and 605 deletions
|
|
@ -4,7 +4,6 @@ mod arranger_command; pub use self::arranger_command::*;
|
||||||
mod arranger_scene; pub use self::arranger_scene::*;
|
mod arranger_scene; pub use self::arranger_scene::*;
|
||||||
mod arranger_select; pub use self::arranger_select::*;
|
mod arranger_select; pub use self::arranger_select::*;
|
||||||
mod arranger_track; pub use self::arranger_track::*;
|
mod arranger_track; pub use self::arranger_track::*;
|
||||||
mod arranger_tui; pub use self::arranger_tui::*;
|
|
||||||
mod arranger_h;
|
mod arranger_h;
|
||||||
|
|
||||||
/// Root view for standalone `tek_arranger`
|
/// Root view for standalone `tek_arranger`
|
||||||
|
|
@ -108,3 +107,605 @@ impl Arranger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub(crate) const HEADER_H: u16 = 0; // 5
|
||||||
|
pub(crate) const SCENES_W_OFFSET: u16 = 0;
|
||||||
|
render!(TuiOut: (self: Arranger) => {
|
||||||
|
let scenes_w = 16;
|
||||||
|
let row = move|h, header, cells|Fixed::y(h, Bsp::e(
|
||||||
|
Fixed::x(scenes_w, header),
|
||||||
|
Fixed::y(h, Fill::x(Align::x(cells)))
|
||||||
|
));
|
||||||
|
//let row = move|h, header, cells|Align::w(Bsp::e(
|
||||||
|
//Align::w(Fixed::xy(scenes_w, h, header)),
|
||||||
|
//Fixed::xy(self.tracks.len() as u16*12, h, cells)
|
||||||
|
//));
|
||||||
|
let h = self.size.h() as u16;
|
||||||
|
let toolbar = |x|Bsp::s(self.toolbar_view(), x);
|
||||||
|
let pool = |x|Bsp::w(self.pool_view(), x);
|
||||||
|
let editing = |x|Bsp::n(Bsp::e(self.editor.clip_status(), self.editor.edit_status()), x);
|
||||||
|
let outputs = |x|Bsp::s(row(2, self.output_row_header(), self.output_row_cells()), Fill::y(x));
|
||||||
|
let playing = |x|Bsp::s(row(2, self.elapsed_row_header(), self.elapsed_row_cells()), Fill::y(x));
|
||||||
|
let next = |x|Bsp::s(row(2, self.next_row_header(), self.next_row_cells()), Fill::y(x));
|
||||||
|
let tracks = |x|Bsp::s(row(3, self.track_row_header(), self.track_row_cells()), Fill::y(x));
|
||||||
|
let scenes = |x|Bsp::s(row(h.saturating_sub(13), self.scene_row_headers(), self.scene_row_cells()), x);
|
||||||
|
let inputs = |x|Bsp::n(row(2, self.input_row_header(), self.input_row_cells()), Fill::y(x));
|
||||||
|
self.size.of(toolbar(pool(editing(inputs(outputs(playing(next(tracks(scenes(Fill::xy("")))))))))))
|
||||||
|
//let enclosed = |x|Outer(Style::default().fg(Color::Rgb(72,72,72))).enclose(x);
|
||||||
|
//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
|
//Bsp::s(arrrrrr, enclosed(&self.editor))
|
||||||
|
});
|
||||||
|
impl Arranger {
|
||||||
|
pub const LEFT_SEP: char = '▎';
|
||||||
|
pub const TRACK_MIN_WIDTH: usize = 4;
|
||||||
|
|
||||||
|
pub fn scenes_with_heights (&self, h: usize) -> impl Iterator<Item = (usize, &ArrangerScene, usize, usize)> {
|
||||||
|
let mut y = 0;
|
||||||
|
let editing = self.editing;
|
||||||
|
let (selected_track, selected_scene) = match self.selected {
|
||||||
|
ArrangerSelection::Clip(t, s) => (Some(t), Some(s)),
|
||||||
|
_ => (None, None)
|
||||||
|
};
|
||||||
|
self.scenes.iter().enumerate().map(move|(s, scene)|{
|
||||||
|
let active = editing && selected_track.is_some() && selected_scene == Some(s);
|
||||||
|
let height = if active { 15 } else { h };
|
||||||
|
let data = (s, scene, y, y + height);
|
||||||
|
y += height;
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn tracks_with_widths (&self)
|
||||||
|
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
||||||
|
{
|
||||||
|
let active = match self.selected {
|
||||||
|
ArrangerSelection::Track(t) => Some(t),
|
||||||
|
ArrangerSelection::Clip(t, _) => Some(t),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
Self::tracks_with_widths_static(self.tracks.as_slice(), active)
|
||||||
|
}
|
||||||
|
fn tracks_with_widths_static (tracks: &[ArrangerTrack], active: Option<usize>)
|
||||||
|
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
||||||
|
{
|
||||||
|
let mut x = 0;
|
||||||
|
tracks.iter().enumerate().map(move |(index, track)|{
|
||||||
|
let width = if Some(index) == active { 40 } else { track.width };
|
||||||
|
let data = (index, track, x, x + width);
|
||||||
|
x += width;
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
let fg = TuiTheme::g(192);
|
||||||
|
let bg = TuiTheme::g(48);
|
||||||
|
(move||Tui::bold(true, Tui::fg_bg(fg, bg, "[ ] Out 1: NI")).boxed()).into()
|
||||||
|
}
|
||||||
|
fn output_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
//let scenes_w = 16;//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
|
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
|
let w = (x2 - x1) as u16;
|
||||||
|
let color: ItemPalette = track.color().dark.into();
|
||||||
|
let cell = Bsp::s(format!(" M S "), phat_hi(color.dark.rgb, color.darker.rgb));
|
||||||
|
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, cell)))
|
||||||
|
})).boxed()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elapsed_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(||Tui::bold(true, Tui::fg(TuiTheme::g(128), "Playing")).boxed()).into()
|
||||||
|
}
|
||||||
|
fn elapsed_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
|
//let color = track.color();
|
||||||
|
let color: ItemPalette = track.color().dark.into();
|
||||||
|
let timebase = self.clock().timebase();
|
||||||
|
let value = Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
||||||
|
if let Some((_, Some(clip))) = track.player.play_clip().as_ref() {
|
||||||
|
let length = clip.read().unwrap().length;
|
||||||
|
let elapsed = track.player.pulses_since_start().unwrap() as usize;
|
||||||
|
format!("+{:>}", timebase.format_beats_1_short((elapsed % length) as f64))
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
});
|
||||||
|
let cell = Bsp::s(value, phat_hi(color.dark.rgb, color.darker.rgb));
|
||||||
|
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
||||||
|
})).boxed()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(||Tui::bold(true, Tui::fg(TuiTheme::g(128), "Next")).boxed()).into()
|
||||||
|
}
|
||||||
|
fn next_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
|
let color: ItemPalette = track.color();
|
||||||
|
let color: ItemPalette = track.color().dark.into();
|
||||||
|
let cell = Self::cell_until_next(track, &self.clock().playhead);
|
||||||
|
let cell = Self::cell(color, Tui::bold(true, cell));
|
||||||
|
let cell = Tui::fg_bg(color.lightest.rgb, color.base.rgb, cell);
|
||||||
|
let cell = Bsp::s(cell, phat_hi(color.dark.rgb, color.darker.rgb));
|
||||||
|
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
||||||
|
})).boxed()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn track_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(||Tui::bold(true, Tui::fg(TuiTheme::g(128), "Track")).boxed()).into()
|
||||||
|
}
|
||||||
|
fn track_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
let iter = ||self.tracks_with_widths();
|
||||||
|
(move||Fixed::y(2, Map::new(iter, move|(_, track, x1, x2), i| {
|
||||||
|
let color = track.color();
|
||||||
|
let name = Push::x(1, &track.name);
|
||||||
|
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16,
|
||||||
|
Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
||||||
|
phat_cell(color, color.darkest.rgb.into(),
|
||||||
|
Tui::bold(true, name))))) })).boxed()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(||Fill::x(Tui::bold(true, Tui::fg_bg(TuiTheme::g(0), TuiTheme::g(200), "[ ] In 1: Korg"))).boxed()).into()
|
||||||
|
}
|
||||||
|
fn input_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
|
let w = (x2 - x1) as u16;
|
||||||
|
let cell = Bsp::s("[Rec]", "[Mon]");
|
||||||
|
let color: ItemPalette = track.color().dark.into();
|
||||||
|
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, cell)))
|
||||||
|
})).boxed()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scene_row_headers <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
(||{
|
||||||
|
let scenes_w = 16;//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
|
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
||||||
|
let selected_scene = match self.selected {
|
||||||
|
ArrangerSelection::Scene(s) => Some(s),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
Tui::bg(Color::Rgb(0,0,0), Fill::y(Map::new(
|
||||||
|
||self.scenes_with_heights(2),
|
||||||
|
move|(_, scene, y1, y2), i| {
|
||||||
|
let h = (y2 - y1) as u16;
|
||||||
|
let name = format!("🭬{}", &scene.name);
|
||||||
|
let color = scene.color();
|
||||||
|
let cell = phat_sel_3(
|
||||||
|
selected_scene == Some(i),
|
||||||
|
Push::x(1, Tui::bold(true, name.clone())),
|
||||||
|
Push::x(1, Tui::bold(true, name)),
|
||||||
|
if selected_scene.map(|s|s + 1) == Some(i) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(last_color.read().unwrap().base.rgb)
|
||||||
|
},
|
||||||
|
if selected_scene == Some(i) {
|
||||||
|
color.light.rgb
|
||||||
|
} else {
|
||||||
|
color.base.rgb
|
||||||
|
},
|
||||||
|
Color::Rgb(0, 0, 0)
|
||||||
|
);
|
||||||
|
*last_color.write().unwrap() = color;
|
||||||
|
map_south(y1 as u16, h + 1, Fixed::y(h + 1, cell))
|
||||||
|
}
|
||||||
|
))).boxed()
|
||||||
|
}).into()
|
||||||
|
}
|
||||||
|
fn scene_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
|
let editing = self.editing;
|
||||||
|
let (selected_track, selected_scene) = match self.selected {
|
||||||
|
ArrangerSelection::Clip(t, s) => (Some(t), Some(s)),
|
||||||
|
_ => (None, None)
|
||||||
|
};
|
||||||
|
let tracks = move||self.tracks_with_widths();
|
||||||
|
let scenes = ||self.scenes_with_heights(2);
|
||||||
|
(move||Fixed::y(2, Map::new(tracks, move|(_, track, x1, x2), t| {
|
||||||
|
let w = (x2 - x1) as u16;
|
||||||
|
let cell = Bsp::s("[Rec]", "[Mon]");
|
||||||
|
let color: ItemPalette = track.color().dark.into();
|
||||||
|
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
||||||
|
let cells = Map::new(scenes, move|(_, scene, y1, y2), s| {
|
||||||
|
let h = (y2 - y1) as u16;
|
||||||
|
let color = scene.color();
|
||||||
|
let name = "⏹ ";
|
||||||
|
let last = last_color.read().unwrap().clone();
|
||||||
|
//let cell = phat_sel_3(
|
||||||
|
//selected_track == Some(i) && selected_scene == Some(j),
|
||||||
|
//Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
||||||
|
//Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
||||||
|
//if selected_track == Some(i) && selected_scene.map(|s|s+1) == Some(j) {
|
||||||
|
//None
|
||||||
|
//} else {
|
||||||
|
//Some(TuiTheme::g(32).into())
|
||||||
|
//},
|
||||||
|
//TuiTheme::g(32).into(),
|
||||||
|
//TuiTheme::g(32).into(),
|
||||||
|
//);
|
||||||
|
let active = editing && selected_track == Some(t) && selected_scene == Some(s);
|
||||||
|
let editor = Thunk::new(||&self.editor);
|
||||||
|
let cell = Thunk::new(move||phat_sel_3(
|
||||||
|
selected_track == Some(t) && selected_scene == Some(s),
|
||||||
|
Tui::fg(TuiTheme::g(64), Push::x(1, Tui::bold(true, name.to_string()))),
|
||||||
|
Tui::fg(TuiTheme::g(64), Push::x(1, Tui::bold(true, name.to_string()))),
|
||||||
|
if selected_track == Some(t) && selected_scene.map(|s|s+1) == Some(s) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(TuiTheme::g(32).into())
|
||||||
|
},
|
||||||
|
TuiTheme::g(32).into(),
|
||||||
|
TuiTheme::g(32).into(),
|
||||||
|
));
|
||||||
|
let cell = Either(active, editor, cell);
|
||||||
|
map_south(
|
||||||
|
y1 as u16,
|
||||||
|
h + 1,
|
||||||
|
Fill::x(cell)
|
||||||
|
)
|
||||||
|
});
|
||||||
|
map_east(
|
||||||
|
x1 as u16,
|
||||||
|
w,
|
||||||
|
Fixed::x(w, Tui::bg(Color::Rgb(0,0,0), Fill::y(cells)).boxed())
|
||||||
|
)
|
||||||
|
})).boxed()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn track_column_separators <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
||||||
|
let scenes_w = 16;//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
|
let fg = Color::Rgb(64,64,64);
|
||||||
|
Map::new(move||self.tracks_with_widths(), move|(_n, _track, x1, x2), _i|{
|
||||||
|
Push::x(scenes_w, map_east(x1 as u16, (x2 - x1) as u16,
|
||||||
|
Fixed::x((x2 - x1) as u16, Tui::fg(fg, RepeatV(&"·")))))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// name and width of track
|
||||||
|
fn cell_name (track: &ArrangerTrack, _w: usize) -> impl Content<TuiOut> {
|
||||||
|
Tui::bold(true, Tui::fg(track.color.lightest.rgb, track.name().clone()))
|
||||||
|
}
|
||||||
|
/// beats until switchover
|
||||||
|
fn cell_until_next (track: &ArrangerTrack, current: &Arc<Moment>)
|
||||||
|
-> Option<impl Content<TuiOut>>
|
||||||
|
{
|
||||||
|
let timebase = ¤t.timebase;
|
||||||
|
let mut result = String::new();
|
||||||
|
if let Some((t, _)) = track.player.next_clip().as_ref() {
|
||||||
|
let target = t.pulse.get();
|
||||||
|
let current = current.pulse.get();
|
||||||
|
if target > current {
|
||||||
|
result = format!("-{:>}", timebase.format_beats_0_short(target - current))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scene_rows (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
let scenes_w = 16.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
|
Map::new(||self.scenes_with_heights(1), move|(_, scene, y1, y2), i| {
|
||||||
|
let h = (y2 - y1) as u16;
|
||||||
|
let color = scene.color();
|
||||||
|
let cell = Self::cell(color, scene.name.clone());
|
||||||
|
let cell = Fixed::y(h, Fixed::x(scenes_w, cell));
|
||||||
|
map_south(y1 as u16, 1, cell)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn scene_heights (scenes: &[ArrangerScene], factor: usize) -> Vec<(usize, usize)> {
|
||||||
|
let mut total = 0;
|
||||||
|
if factor == 0 {
|
||||||
|
scenes.iter().map(|scene|{
|
||||||
|
let pulses = scene.pulses().max(PPQ);
|
||||||
|
total += pulses;
|
||||||
|
(pulses, total - pulses)
|
||||||
|
}).collect()
|
||||||
|
} else {
|
||||||
|
(0..=scenes.len()).map(|i|{
|
||||||
|
(factor*PPQ, factor*PPQ*i)
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cell_scene <'a> (
|
||||||
|
tracks: &'a [ArrangerTrack], scene: &'a ArrangerScene, pulses: usize
|
||||||
|
) -> impl Content<TuiOut> + use<'a> {
|
||||||
|
let height = 1.max((pulses / PPQ) as u16);
|
||||||
|
let playing = scene.is_playing(tracks);
|
||||||
|
let icon = Tui::bg(
|
||||||
|
scene.color.base.rgb, if playing { "▶ " } else { " " }
|
||||||
|
);
|
||||||
|
let name = Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
||||||
|
Expand::x(1, Tui::bold(true, scene.name.clone()))
|
||||||
|
);
|
||||||
|
let clips = Map::new(||Arranger::tracks_with_widths_static(tracks, None), move|(index, track, x1, x2), _|
|
||||||
|
Push::x((x2 - x1) as u16, Self::cell_clip(scene, index, track, (x2 - x1) as u16, height))
|
||||||
|
);
|
||||||
|
Fixed::y(height, Bsp::e(icon, Bsp::e(name, clips)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cell_clip <'a> (
|
||||||
|
scene: &'a ArrangerScene, index: usize, track: &'a ArrangerTrack, w: u16, h: u16
|
||||||
|
) -> impl Content<TuiOut> + use<'a> {
|
||||||
|
scene.clips.get(index).map(|clip|clip.as_ref().map(|clip|{
|
||||||
|
let clip = clip.read().unwrap();
|
||||||
|
let mut bg = TuiTheme::border_bg();
|
||||||
|
let name = clip.name.to_string();
|
||||||
|
let max_w = name.len().min((w as usize).saturating_sub(2));
|
||||||
|
let color = clip.color;
|
||||||
|
bg = color.dark.rgb;
|
||||||
|
if let Some((_, Some(ref playing))) = track.player.play_clip() {
|
||||||
|
if *playing.read().unwrap() == *clip {
|
||||||
|
bg = color.light.rgb
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Fixed::xy(w, h, &Tui::bg(bg, Push::x(1, Fixed::x(w, &name.as_str()[0..max_w]))));
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn toolbar_view (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
Fill::x(Fixed::y(2, Align::x(TransportView::new(true, &self.clock))))
|
||||||
|
}
|
||||||
|
fn pool_view (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
let w = self.size.w();
|
||||||
|
let clip_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
||||||
|
let pool_w = if self.pool.visible { clip_w } else { 0 };
|
||||||
|
let pool = Pull::y(1, Fill::y(Align::e(PoolView(self.pool.visible, &self.pool))));
|
||||||
|
Fixed::x(pool_w, Align::e(Fill::y(PoolView(self.compact, &self.pool))))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
||||||
|
let mut widths = vec![];
|
||||||
|
let mut total = 0;
|
||||||
|
for track in tracks.iter() {
|
||||||
|
let width = track.width;
|
||||||
|
widths.push((width, total));
|
||||||
|
total += width;
|
||||||
|
}
|
||||||
|
widths.push((0, total));
|
||||||
|
widths
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scene_row_sep <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
||||||
|
let fg = Color::Rgb(255,255,255);
|
||||||
|
Map::new(move||self.scenes_with_heights(1), |_, _|"")
|
||||||
|
//Map(||rows.iter(), |(_n, _scene, y1, _y2), _i| {
|
||||||
|
//let y = to.area().y() + (y / PPQ) as u16 + 1;
|
||||||
|
//if y >= to.buffer.area.height { break }
|
||||||
|
//for x in to.area().x()..to.area().x2().saturating_sub(2) {
|
||||||
|
////if x < to.buffer.area.x && y < to.buffer.area.y {
|
||||||
|
//if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) {
|
||||||
|
//cell.modifier = Modifier::UNDERLINED;
|
||||||
|
//cell.underline_color = fg;
|
||||||
|
//}
|
||||||
|
////}
|
||||||
|
//}
|
||||||
|
//})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cursor (&self) -> impl Content<TuiOut> + '_ {
|
||||||
|
let color = self.color;
|
||||||
|
let bg = color.lighter.rgb;//Color::Rgb(0, 255, 0);
|
||||||
|
let selected = self.selected();
|
||||||
|
let cols = Arranger::track_widths(&self.tracks);
|
||||||
|
let rows = Arranger::scene_heights(&self.scenes, 1);
|
||||||
|
let scenes_w = 16.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
||||||
|
let focused = true;
|
||||||
|
let reticle = Reticle(Style {
|
||||||
|
fg: Some(self.color.lighter.rgb),
|
||||||
|
bg: None,
|
||||||
|
underline_color: None,
|
||||||
|
add_modifier: Modifier::empty(),
|
||||||
|
sub_modifier: Modifier::DIM
|
||||||
|
});
|
||||||
|
RenderThunk::new(move|to: &mut TuiOut|{
|
||||||
|
let area = to.area();
|
||||||
|
let [x, y, w, h] = area.xywh();
|
||||||
|
let mut track_area: Option<[u16;4]> = match selected {
|
||||||
|
ArrangerSelection::Track(t) | ArrangerSelection::Clip(t, _) => Some([
|
||||||
|
x + scenes_w + cols[t].1 as u16, y,
|
||||||
|
cols[t].0 as u16, h,
|
||||||
|
]),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
let mut scene_area: Option<[u16;4]> = match selected {
|
||||||
|
ArrangerSelection::Scene(s) | ArrangerSelection::Clip(_, s) => Some([
|
||||||
|
x, y + HEADER_H + (rows[s].1 / PPQ) as u16,
|
||||||
|
w, (rows[s].0 / PPQ) as u16
|
||||||
|
]),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
let mut clip_area: Option<[u16;4]> = match selected {
|
||||||
|
ArrangerSelection::Clip(t, s) => Some([
|
||||||
|
(scenes_w + x + cols[t].1 as u16).saturating_sub(1),
|
||||||
|
HEADER_H + y + (rows[s].1/PPQ) as u16,
|
||||||
|
cols[t].0 as u16 + 2,
|
||||||
|
(rows[s].0 / PPQ) as u16
|
||||||
|
]),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
if let Some([x, y, width, height]) = track_area {
|
||||||
|
to.fill_fg([x, y, 1, height], bg);
|
||||||
|
to.fill_fg([x + width, y, 1, height], bg);
|
||||||
|
}
|
||||||
|
if let Some([_, y, _, height]) = scene_area {
|
||||||
|
to.fill_ul([x, y - 1, w, 1], bg);
|
||||||
|
to.fill_ul([x, y + height - 1, w, 1], bg);
|
||||||
|
}
|
||||||
|
if focused {
|
||||||
|
to.place(if let Some(clip_area) = clip_area {
|
||||||
|
clip_area
|
||||||
|
} else if let Some(track_area) = track_area {
|
||||||
|
track_area.clip_h(HEADER_H)
|
||||||
|
} else if let Some(scene_area) = scene_area {
|
||||||
|
scene_area.clip_w(scenes_w)
|
||||||
|
} else {
|
||||||
|
area.clip_w(scenes_w).clip_h(HEADER_H)
|
||||||
|
}, &reticle)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A 1-row cell.
|
||||||
|
fn cell <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
||||||
|
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Fixed::y(1, field))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A phat line
|
||||||
|
fn phat_lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||||
|
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▄")))
|
||||||
|
}
|
||||||
|
/// A phat line
|
||||||
|
fn phat_hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||||
|
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▀")))
|
||||||
|
}
|
||||||
|
/// A cell that is 3-row on its own, but stacks, giving (N+1)*2 rows per N cells.
|
||||||
|
fn phat_cell <T: Content<TuiOut>> (
|
||||||
|
color: ItemPalette, last: ItemPalette, field: T
|
||||||
|
) -> impl Content<TuiOut> {
|
||||||
|
Bsp::s(phat_lo(color.base.rgb, last.base.rgb),
|
||||||
|
Bsp::n(phat_hi(color.base.rgb, last.base.rgb),
|
||||||
|
Fixed::y(1, Fill::x(Tui::fg_bg(color.lightest.rgb, color.base.rgb, field))),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn phat_cell_3 <T: Content<TuiOut>> (
|
||||||
|
field: T, top: Color, middle: Color, bottom: Color
|
||||||
|
) -> impl Content<TuiOut> {
|
||||||
|
Bsp::s(phat_lo(middle, top),
|
||||||
|
Bsp::n(phat_hi(middle, bottom),
|
||||||
|
Fill::y(Fill::x(Tui::bg(middle, field))),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn phat_sel_3 <T: Content<TuiOut>> (
|
||||||
|
selected: bool, field_1: T, field_2: T, top: Option<Color>, middle: Color, bottom: Color
|
||||||
|
) -> impl Content<TuiOut> {
|
||||||
|
let border = Style::default().fg(Color::Rgb(255,255,255)).bg(middle);
|
||||||
|
Either(selected,
|
||||||
|
Tui::bg(middle, Outer(border).enclose( Align::w(Bsp::s("", Bsp::s(field_1, ""))))),
|
||||||
|
Bsp::s(
|
||||||
|
Fixed::y(1, top.map(|top|phat_lo(middle, top))),
|
||||||
|
Bsp::n(phat_hi(middle, bottom),
|
||||||
|
Fixed::y(1, Fill::x(Tui::bg(middle, field_2))),
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
//pub struct ArrangerVCursor {
|
||||||
|
//cols: Vec<(usize, usize)>,
|
||||||
|
//rows: Vec<(usize, usize)>,
|
||||||
|
//color: ItemPalette,
|
||||||
|
//reticle: Reticle,
|
||||||
|
//selected: ArrangerSelection,
|
||||||
|
//scenes_w: u16,
|
||||||
|
//}
|
||||||
|
|
||||||
|
//from!(|args:(&Arranger, usize)|ArrangerVCursor = Self {
|
||||||
|
//cols: Arranger::track_widths(&args.0.tracks),
|
||||||
|
//rows: Arranger::scene_heights(&args.0.scenes, args.1),
|
||||||
|
//selected: args.0.selected(),
|
||||||
|
//scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&args.0.scenes) as u16,
|
||||||
|
//color: args.0.color,
|
||||||
|
//reticle: Reticle(Style {
|
||||||
|
//fg: Some(args.0.color.lighter.rgb),
|
||||||
|
//bg: None,
|
||||||
|
//underline_color: None,
|
||||||
|
//add_modifier: Modifier::empty(),
|
||||||
|
//sub_modifier: Modifier::DIM
|
||||||
|
//}),
|
||||||
|
//});
|
||||||
|
//impl Content<TuiOut> for ArrangerVCursor {
|
||||||
|
//fn render (&self, to: &mut TuiOut) {
|
||||||
|
//let area = to.area();
|
||||||
|
//let focused = true;
|
||||||
|
//let selected = self.selected;
|
||||||
|
//let get_track_area = |t: usize| [
|
||||||
|
//self.scenes_w + area.x() + self.cols[t].1 as u16, area.y(),
|
||||||
|
//self.cols[t].0 as u16, area.h(),
|
||||||
|
//];
|
||||||
|
//let get_scene_area = |s: usize| [
|
||||||
|
//area.x(), HEADER_H + area.y() + (self.rows[s].1 / PPQ) as u16,
|
||||||
|
//area.w(), (self.rows[s].0 / PPQ) as u16
|
||||||
|
//];
|
||||||
|
//let get_clip_area = |t: usize, s: usize| [
|
||||||
|
//(self.scenes_w + area.x() + self.cols[t].1 as u16).saturating_sub(1),
|
||||||
|
//HEADER_H + area.y() + (self.rows[s].1/PPQ) as u16,
|
||||||
|
//self.cols[t].0 as u16 + 2,
|
||||||
|
//(self.rows[s].0 / PPQ) as u16
|
||||||
|
//];
|
||||||
|
//let mut track_area: Option<[u16;4]> = None;
|
||||||
|
//let mut scene_area: Option<[u16;4]> = None;
|
||||||
|
//let mut clip_area: Option<[u16;4]> = None;
|
||||||
|
//let area = match selected {
|
||||||
|
//ArrangerSelection::Mix => area,
|
||||||
|
//ArrangerSelection::Track(t) => {
|
||||||
|
//track_area = Some(get_track_area(t));
|
||||||
|
//area
|
||||||
|
//},
|
||||||
|
//ArrangerSelection::Scene(s) => {
|
||||||
|
//scene_area = Some(get_scene_area(s));
|
||||||
|
//area
|
||||||
|
//},
|
||||||
|
//ArrangerSelection::Clip(t, s) => {
|
||||||
|
//track_area = Some(get_track_area(t));
|
||||||
|
//scene_area = Some(get_scene_area(s));
|
||||||
|
//clip_area = Some(get_clip_area(t, s));
|
||||||
|
//area
|
||||||
|
//},
|
||||||
|
//};
|
||||||
|
//let bg = self.color.lighter.rgb;//Color::Rgb(0, 255, 0);
|
||||||
|
//if let Some([x, y, width, height]) = track_area {
|
||||||
|
//to.fill_fg([x, y, 1, height], bg);
|
||||||
|
//to.fill_fg([x + width, y, 1, height], bg);
|
||||||
|
//}
|
||||||
|
//if let Some([_, y, _, height]) = scene_area {
|
||||||
|
//to.fill_ul([area.x(), y - 1, area.w(), 1], bg);
|
||||||
|
//to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
|
||||||
|
//}
|
||||||
|
//if focused {
|
||||||
|
//to.place(if let Some(clip_area) = clip_area {
|
||||||
|
//clip_area
|
||||||
|
//} else if let Some(track_area) = track_area {
|
||||||
|
//track_area.clip_h(HEADER_H)
|
||||||
|
//} else if let Some(scene_area) = scene_area {
|
||||||
|
//scene_area.clip_w(self.scenes_w)
|
||||||
|
//} else {
|
||||||
|
//area.clip_w(self.scenes_w).clip_h(HEADER_H)
|
||||||
|
//}, &self.reticle)
|
||||||
|
//};
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//impl Arranger {
|
||||||
|
//fn render_mode (state: &Self) -> impl Content<TuiOut> + use<'_> {
|
||||||
|
//match state.mode {
|
||||||
|
//ArrangerMode::H => todo!("horizontal arranger"),
|
||||||
|
//ArrangerMode::V(factor) => Self::render_mode_v(state, factor),
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//render!(TuiOut: (self: Arranger) => {
|
||||||
|
//let pool_w = if self.pool.visible { self.splits[1] } else { 0 };
|
||||||
|
//let color = self.color;
|
||||||
|
//let layout = Bsp::a(Fill::xy(ArrangerStatus::from(self)),
|
||||||
|
//Bsp::n(Fixed::x(pool_w, PoolView(self.pool.visible, &self.pool)),
|
||||||
|
//Bsp::n(TransportView::new(true, &self.clock),
|
||||||
|
//Bsp::s(Fixed::y(1, MidiEditStatus(&self.editor)),
|
||||||
|
//Bsp::n(Fill::x(Fixed::y(20,
|
||||||
|
//Bsp::a(Fill::xy(Tui::bg(color.darkest.rgb, "background")),
|
||||||
|
//Bsp::a(
|
||||||
|
//Fill::xy(Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb))),
|
||||||
|
//Self::render_mode(self))))), Fill::y(&"fixme: self.editor"))))));
|
||||||
|
//self.size.of(layout)
|
||||||
|
//});
|
||||||
|
//Align::n(Fill::xy(lay!(
|
||||||
|
//Align::n(Fill::xy(Tui::bg(self.color.darkest.rgb, " "))),
|
||||||
|
//Align::n(Fill::xy(ArrangerVRowSep::from((self, 1)))),
|
||||||
|
//Align::n(Fill::xy(ArrangerVColSep::from(self))),
|
||||||
|
//Align::n(Fill::xy(ArrangerVClips::new(self, 1))),
|
||||||
|
//Align::n(Fill::xy(ArrangerVCursor::from((self, 1))))))))))))))));
|
||||||
|
//Align::n(Fill::xy(":")))))))))))));
|
||||||
|
//"todo:"))))))));
|
||||||
|
//Bsp::s(
|
||||||
|
//Align::n(Fixed::y(1, Fill::x(ArrangerVIns::from(self)))),
|
||||||
|
//Bsp::s(
|
||||||
|
//Fixed::y(20, Align::n(ArrangerVClips::new(self, 1))),
|
||||||
|
//Fill::x(Fixed::y(1, ArrangerVOuts::from(self)))))))))))));
|
||||||
|
//Bsp::s(
|
||||||
|
//Bsp::s(
|
||||||
|
//Bsp::s(
|
||||||
|
//Fill::xy(ArrangerVClips::new(self, 1)),
|
||||||
|
//Fill::x(ArrangerVOuts::from(self)))))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,604 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
pub(crate) const HEADER_H: u16 = 0; // 5
|
|
||||||
pub(crate) const SCENES_W_OFFSET: u16 = 0;
|
|
||||||
render!(TuiOut: (self: Arranger) => {
|
|
||||||
let scenes_w = 16;
|
|
||||||
let row = move|h, header, cells|Align::w(Bsp::e(
|
|
||||||
Align::w(Fixed::xy(scenes_w, h, header)),
|
|
||||||
Fixed::xy(self.tracks.len() as u16*12, h, cells)
|
|
||||||
));
|
|
||||||
let toolbar = |x|Bsp::s(self.toolbar_view(), x);
|
|
||||||
let pool = |x|Bsp::w(self.pool_view(), x);
|
|
||||||
let editing = |x|Bsp::n(Bsp::e(self.editor.clip_status(), self.editor.edit_status()), x);
|
|
||||||
let outputs = |x|Bsp::s(row(2, self.output_row_header(), self.output_row_cells()), Fill::y(x));
|
|
||||||
let playing = |x|Bsp::s(row(2, self.elapsed_row_header(), self.elapsed_row_cells()), Fill::y(x));
|
|
||||||
let next = |x|Bsp::s(row(2, self.next_row_header(), self.next_row_cells()), Fill::y(x));
|
|
||||||
let tracks = |x|Bsp::s(row(3, self.track_row_header(), self.track_row_cells()), Fill::y(x));
|
|
||||||
let scenes = |x|Bsp::s(row((self.size.h() as u16).saturating_sub(13),
|
|
||||||
self.scene_row_headers(),
|
|
||||||
self.scene_row_cells()), x);
|
|
||||||
let inputs = |x|Bsp::n(
|
|
||||||
row(2, self.input_row_header(), self.input_row_cells()),
|
|
||||||
Fill::y(x));
|
|
||||||
self.size.of(
|
|
||||||
toolbar(pool(editing(inputs(outputs(playing(next(tracks(scenes(Fill::xy("")))))))))))
|
|
||||||
|
|
||||||
//let enclosed = |x|Outer(Style::default().fg(Color::Rgb(72,72,72))).enclose(x);
|
|
||||||
//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
|
||||||
//Bsp::s(arrrrrr, enclosed(&self.editor))
|
|
||||||
});
|
|
||||||
impl Arranger {
|
|
||||||
pub const LEFT_SEP: char = '▎';
|
|
||||||
pub const TRACK_MIN_WIDTH: usize = 4;
|
|
||||||
|
|
||||||
pub fn scenes_with_heights (&self, h: usize) -> impl Iterator<Item = (usize, &ArrangerScene, usize, usize)> {
|
|
||||||
let mut y = 0;
|
|
||||||
let editing = self.editing;
|
|
||||||
let (selected_track, selected_scene) = match self.selected {
|
|
||||||
ArrangerSelection::Clip(t, s) => (Some(t), Some(s)),
|
|
||||||
_ => (None, None)
|
|
||||||
};
|
|
||||||
self.scenes.iter().enumerate().map(move|(s, scene)|{
|
|
||||||
let active = editing && selected_track.is_some() && selected_scene == Some(s);
|
|
||||||
let height = if active { 15 } else { h };
|
|
||||||
let data = (s, scene, y, y + height);
|
|
||||||
y += height;
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn tracks_with_widths (&self)
|
|
||||||
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
|
||||||
{
|
|
||||||
let active = match self.selected {
|
|
||||||
ArrangerSelection::Track(t) => Some(t),
|
|
||||||
ArrangerSelection::Clip(t, _) => Some(t),
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
Self::tracks_with_widths_static(self.tracks.as_slice(), active)
|
|
||||||
}
|
|
||||||
fn tracks_with_widths_static (tracks: &[ArrangerTrack], active: Option<usize>)
|
|
||||||
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
|
||||||
{
|
|
||||||
let mut x = 0;
|
|
||||||
tracks.iter().enumerate().map(move |(index, track)|{
|
|
||||||
let width = if Some(index) == active { 40 } else { track.width };
|
|
||||||
let data = (index, track, x, x + width);
|
|
||||||
x += width;
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
let fg = TuiTheme::g(192);
|
|
||||||
let bg = TuiTheme::g(48);
|
|
||||||
(move||Tui::bold(true, Tui::fg_bg(fg, bg, "[ ] Out 1: NI")).boxed()).into()
|
|
||||||
}
|
|
||||||
fn output_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
//let scenes_w = 16;//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
|
||||||
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
|
||||||
let w = (x2 - x1) as u16;
|
|
||||||
let color: ItemPalette = track.color().dark.into();
|
|
||||||
let cell = Bsp::s(format!(" M S "), phat_hi(color.dark.rgb, color.darker.rgb));
|
|
||||||
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, cell)))
|
|
||||||
})).boxed()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn elapsed_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(||Tui::bold(true, Tui::fg(TuiTheme::g(128), "Playing")).boxed()).into()
|
|
||||||
}
|
|
||||||
fn elapsed_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
|
||||||
//let color = track.color();
|
|
||||||
let color: ItemPalette = track.color().dark.into();
|
|
||||||
let timebase = self.clock().timebase();
|
|
||||||
let value = Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
|
||||||
if let Some((_, Some(clip))) = track.player.play_clip().as_ref() {
|
|
||||||
let length = clip.read().unwrap().length;
|
|
||||||
let elapsed = track.player.pulses_since_start().unwrap() as usize;
|
|
||||||
format!("+{:>}", timebase.format_beats_1_short((elapsed % length) as f64))
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
});
|
|
||||||
let cell = Bsp::s(value, phat_hi(color.dark.rgb, color.darker.rgb));
|
|
||||||
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
|
||||||
})).boxed()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(||Tui::bold(true, Tui::fg(TuiTheme::g(128), "Next")).boxed()).into()
|
|
||||||
}
|
|
||||||
fn next_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
|
||||||
let color: ItemPalette = track.color();
|
|
||||||
let color: ItemPalette = track.color().dark.into();
|
|
||||||
let cell = Self::cell_until_next(track, &self.clock().playhead);
|
|
||||||
let cell = Self::cell(color, Tui::bold(true, cell));
|
|
||||||
let cell = Tui::fg_bg(color.lightest.rgb, color.base.rgb, cell);
|
|
||||||
let cell = Bsp::s(cell, phat_hi(color.dark.rgb, color.darker.rgb));
|
|
||||||
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
|
||||||
})).boxed()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn track_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(||Tui::bold(true, Tui::fg(TuiTheme::g(128), "Track")).boxed()).into()
|
|
||||||
}
|
|
||||||
fn track_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
let iter = ||self.tracks_with_widths();
|
|
||||||
(move||Fixed::y(2, Map::new(iter, move|(_, track, x1, x2), i| {
|
|
||||||
let color = track.color();
|
|
||||||
let name = Push::x(1, &track.name);
|
|
||||||
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16,
|
|
||||||
Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
|
||||||
phat_cell(color, color.darkest.rgb.into(),
|
|
||||||
Tui::bold(true, name))))) })).boxed()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(||Fill::x(Tui::bold(true, Tui::fg_bg(TuiTheme::g(0), TuiTheme::g(200), "[ ] In 1: Korg"))).boxed()).into()
|
|
||||||
}
|
|
||||||
fn input_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
|
||||||
let w = (x2 - x1) as u16;
|
|
||||||
let cell = Bsp::s("[Rec]", "[Mon]");
|
|
||||||
let color: ItemPalette = track.color().dark.into();
|
|
||||||
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, cell)))
|
|
||||||
})).boxed()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scene_row_headers <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
(||{
|
|
||||||
let scenes_w = 16;//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
|
||||||
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
|
||||||
let selected_scene = match self.selected {
|
|
||||||
ArrangerSelection::Scene(s) => Some(s),
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
Tui::bg(Color::Rgb(0,0,0), Fill::y(Map::new(
|
|
||||||
||self.scenes_with_heights(2),
|
|
||||||
move|(_, scene, y1, y2), i| {
|
|
||||||
let h = (y2 - y1) as u16;
|
|
||||||
let name = format!("🭬{}", &scene.name);
|
|
||||||
let color = scene.color();
|
|
||||||
let cell = phat_sel_3(
|
|
||||||
selected_scene == Some(i),
|
|
||||||
Push::x(1, Tui::bold(true, name.clone())),
|
|
||||||
Push::x(1, Tui::bold(true, name)),
|
|
||||||
if selected_scene.map(|s|s + 1) == Some(i) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(last_color.read().unwrap().base.rgb)
|
|
||||||
},
|
|
||||||
if selected_scene == Some(i) {
|
|
||||||
color.light.rgb
|
|
||||||
} else {
|
|
||||||
color.base.rgb
|
|
||||||
},
|
|
||||||
Color::Rgb(0, 0, 0)
|
|
||||||
);
|
|
||||||
*last_color.write().unwrap() = color;
|
|
||||||
map_south(y1 as u16, h + 1, Fixed::y(h + 1, cell))
|
|
||||||
}
|
|
||||||
))).boxed()
|
|
||||||
}).into()
|
|
||||||
}
|
|
||||||
fn scene_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
|
||||||
let editing = self.editing;
|
|
||||||
let (selected_track, selected_scene) = match self.selected {
|
|
||||||
ArrangerSelection::Clip(t, s) => (Some(t), Some(s)),
|
|
||||||
_ => (None, None)
|
|
||||||
};
|
|
||||||
let tracks = move||self.tracks_with_widths();
|
|
||||||
let scenes = ||self.scenes_with_heights(2);
|
|
||||||
(move||Fixed::y(2, Map::new(tracks, move|(_, track, x1, x2), t| {
|
|
||||||
let w = (x2 - x1) as u16;
|
|
||||||
let cell = Bsp::s("[Rec]", "[Mon]");
|
|
||||||
let color: ItemPalette = track.color().dark.into();
|
|
||||||
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
|
||||||
let cells = Map::new(scenes, move|(_, scene, y1, y2), s| {
|
|
||||||
let h = (y2 - y1) as u16;
|
|
||||||
let color = scene.color();
|
|
||||||
let name = "⏹ ";
|
|
||||||
let last = last_color.read().unwrap().clone();
|
|
||||||
//let cell = phat_sel_3(
|
|
||||||
//selected_track == Some(i) && selected_scene == Some(j),
|
|
||||||
//Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
|
||||||
//Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
|
||||||
//if selected_track == Some(i) && selected_scene.map(|s|s+1) == Some(j) {
|
|
||||||
//None
|
|
||||||
//} else {
|
|
||||||
//Some(TuiTheme::g(32).into())
|
|
||||||
//},
|
|
||||||
//TuiTheme::g(32).into(),
|
|
||||||
//TuiTheme::g(32).into(),
|
|
||||||
//);
|
|
||||||
let active = editing && selected_track == Some(t) && selected_scene == Some(s);
|
|
||||||
let editor = Thunk::new(||&self.editor);
|
|
||||||
let cell = Thunk::new(move||phat_sel_3(
|
|
||||||
selected_track == Some(t) && selected_scene == Some(s),
|
|
||||||
Tui::fg(TuiTheme::g(64), Push::x(1, Tui::bold(true, name.to_string()))),
|
|
||||||
Tui::fg(TuiTheme::g(64), Push::x(1, Tui::bold(true, name.to_string()))),
|
|
||||||
if selected_track == Some(t) && selected_scene.map(|s|s+1) == Some(s) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(TuiTheme::g(32).into())
|
|
||||||
},
|
|
||||||
TuiTheme::g(32).into(),
|
|
||||||
TuiTheme::g(32).into(),
|
|
||||||
));
|
|
||||||
let cell = Either(active, editor, cell);
|
|
||||||
map_south(
|
|
||||||
y1 as u16,
|
|
||||||
h + 1,
|
|
||||||
Fill::x(cell)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
map_east(
|
|
||||||
x1 as u16,
|
|
||||||
w,
|
|
||||||
Fixed::x(w, Tui::bg(Color::Rgb(0,0,0), Fill::y(cells)).boxed())
|
|
||||||
)
|
|
||||||
})).boxed()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn track_column_separators <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
|
||||||
let scenes_w = 16;//.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
|
||||||
let fg = Color::Rgb(64,64,64);
|
|
||||||
Map::new(move||self.tracks_with_widths(), move|(_n, _track, x1, x2), _i|{
|
|
||||||
Push::x(scenes_w, map_east(x1 as u16, (x2 - x1) as u16,
|
|
||||||
Fixed::x((x2 - x1) as u16, Tui::fg(fg, RepeatV(&"·")))))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/// name and width of track
|
|
||||||
fn cell_name (track: &ArrangerTrack, _w: usize) -> impl Content<TuiOut> {
|
|
||||||
Tui::bold(true, Tui::fg(track.color.lightest.rgb, track.name().clone()))
|
|
||||||
}
|
|
||||||
/// beats until switchover
|
|
||||||
fn cell_until_next (track: &ArrangerTrack, current: &Arc<Moment>)
|
|
||||||
-> Option<impl Content<TuiOut>>
|
|
||||||
{
|
|
||||||
let timebase = ¤t.timebase;
|
|
||||||
let mut result = String::new();
|
|
||||||
if let Some((t, _)) = track.player.next_clip().as_ref() {
|
|
||||||
let target = t.pulse.get();
|
|
||||||
let current = current.pulse.get();
|
|
||||||
if target > current {
|
|
||||||
result = format!("-{:>}", timebase.format_beats_0_short(target - current))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scene_rows (&self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
let scenes_w = 16.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
|
||||||
Map::new(||self.scenes_with_heights(1), move|(_, scene, y1, y2), i| {
|
|
||||||
let h = (y2 - y1) as u16;
|
|
||||||
let color = scene.color();
|
|
||||||
let cell = Self::cell(color, scene.name.clone());
|
|
||||||
let cell = Fixed::y(h, Fixed::x(scenes_w, cell));
|
|
||||||
map_south(y1 as u16, 1, cell)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn scene_heights (scenes: &[ArrangerScene], factor: usize) -> Vec<(usize, usize)> {
|
|
||||||
let mut total = 0;
|
|
||||||
if factor == 0 {
|
|
||||||
scenes.iter().map(|scene|{
|
|
||||||
let pulses = scene.pulses().max(PPQ);
|
|
||||||
total += pulses;
|
|
||||||
(pulses, total - pulses)
|
|
||||||
}).collect()
|
|
||||||
} else {
|
|
||||||
(0..=scenes.len()).map(|i|{
|
|
||||||
(factor*PPQ, factor*PPQ*i)
|
|
||||||
}).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cell_scene <'a> (
|
|
||||||
tracks: &'a [ArrangerTrack], scene: &'a ArrangerScene, pulses: usize
|
|
||||||
) -> impl Content<TuiOut> + use<'a> {
|
|
||||||
let height = 1.max((pulses / PPQ) as u16);
|
|
||||||
let playing = scene.is_playing(tracks);
|
|
||||||
let icon = Tui::bg(
|
|
||||||
scene.color.base.rgb, if playing { "▶ " } else { " " }
|
|
||||||
);
|
|
||||||
let name = Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
|
||||||
Expand::x(1, Tui::bold(true, scene.name.clone()))
|
|
||||||
);
|
|
||||||
let clips = Map::new(||Arranger::tracks_with_widths_static(tracks, None), move|(index, track, x1, x2), _|
|
|
||||||
Push::x((x2 - x1) as u16, Self::cell_clip(scene, index, track, (x2 - x1) as u16, height))
|
|
||||||
);
|
|
||||||
Fixed::y(height, Bsp::e(icon, Bsp::e(name, clips)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cell_clip <'a> (
|
|
||||||
scene: &'a ArrangerScene, index: usize, track: &'a ArrangerTrack, w: u16, h: u16
|
|
||||||
) -> impl Content<TuiOut> + use<'a> {
|
|
||||||
scene.clips.get(index).map(|clip|clip.as_ref().map(|clip|{
|
|
||||||
let clip = clip.read().unwrap();
|
|
||||||
let mut bg = TuiTheme::border_bg();
|
|
||||||
let name = clip.name.to_string();
|
|
||||||
let max_w = name.len().min((w as usize).saturating_sub(2));
|
|
||||||
let color = clip.color;
|
|
||||||
bg = color.dark.rgb;
|
|
||||||
if let Some((_, Some(ref playing))) = track.player.play_clip() {
|
|
||||||
if *playing.read().unwrap() == *clip {
|
|
||||||
bg = color.light.rgb
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Fixed::xy(w, h, &Tui::bg(bg, Push::x(1, Fixed::x(w, &name.as_str()[0..max_w]))));
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
fn toolbar_view (&self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
Fill::x(Fixed::y(2, Align::x(TransportView::new(true, &self.clock))))
|
|
||||||
}
|
|
||||||
fn pool_view (&self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
let w = self.size.w();
|
|
||||||
let clip_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
|
||||||
let pool_w = if self.pool.visible { clip_w } else { 0 };
|
|
||||||
let pool = Pull::y(1, Fill::y(Align::e(PoolView(self.pool.visible, &self.pool))));
|
|
||||||
Fixed::x(pool_w, Align::e(Fill::y(PoolView(self.compact, &self.pool))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
|
||||||
let mut widths = vec![];
|
|
||||||
let mut total = 0;
|
|
||||||
for track in tracks.iter() {
|
|
||||||
let width = track.width;
|
|
||||||
widths.push((width, total));
|
|
||||||
total += width;
|
|
||||||
}
|
|
||||||
widths.push((0, total));
|
|
||||||
widths
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scene_row_sep <'a> (&'a self) -> impl Content<TuiOut> + 'a {
|
|
||||||
let fg = Color::Rgb(255,255,255);
|
|
||||||
Map::new(move||self.scenes_with_heights(1), |_, _|"")
|
|
||||||
//Map(||rows.iter(), |(_n, _scene, y1, _y2), _i| {
|
|
||||||
//let y = to.area().y() + (y / PPQ) as u16 + 1;
|
|
||||||
//if y >= to.buffer.area.height { break }
|
|
||||||
//for x in to.area().x()..to.area().x2().saturating_sub(2) {
|
|
||||||
////if x < to.buffer.area.x && y < to.buffer.area.y {
|
|
||||||
//if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) {
|
|
||||||
//cell.modifier = Modifier::UNDERLINED;
|
|
||||||
//cell.underline_color = fg;
|
|
||||||
//}
|
|
||||||
////}
|
|
||||||
//}
|
|
||||||
//})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cursor (&self) -> impl Content<TuiOut> + '_ {
|
|
||||||
let color = self.color;
|
|
||||||
let bg = color.lighter.rgb;//Color::Rgb(0, 255, 0);
|
|
||||||
let selected = self.selected();
|
|
||||||
let cols = Arranger::track_widths(&self.tracks);
|
|
||||||
let rows = Arranger::scene_heights(&self.scenes, 1);
|
|
||||||
let scenes_w = 16.max(SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16);
|
|
||||||
let focused = true;
|
|
||||||
let reticle = Reticle(Style {
|
|
||||||
fg: Some(self.color.lighter.rgb),
|
|
||||||
bg: None,
|
|
||||||
underline_color: None,
|
|
||||||
add_modifier: Modifier::empty(),
|
|
||||||
sub_modifier: Modifier::DIM
|
|
||||||
});
|
|
||||||
RenderThunk::new(move|to: &mut TuiOut|{
|
|
||||||
let area = to.area();
|
|
||||||
let [x, y, w, h] = area.xywh();
|
|
||||||
let mut track_area: Option<[u16;4]> = match selected {
|
|
||||||
ArrangerSelection::Track(t) | ArrangerSelection::Clip(t, _) => Some([
|
|
||||||
x + scenes_w + cols[t].1 as u16, y,
|
|
||||||
cols[t].0 as u16, h,
|
|
||||||
]),
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
let mut scene_area: Option<[u16;4]> = match selected {
|
|
||||||
ArrangerSelection::Scene(s) | ArrangerSelection::Clip(_, s) => Some([
|
|
||||||
x, y + HEADER_H + (rows[s].1 / PPQ) as u16,
|
|
||||||
w, (rows[s].0 / PPQ) as u16
|
|
||||||
]),
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
let mut clip_area: Option<[u16;4]> = match selected {
|
|
||||||
ArrangerSelection::Clip(t, s) => Some([
|
|
||||||
(scenes_w + x + cols[t].1 as u16).saturating_sub(1),
|
|
||||||
HEADER_H + y + (rows[s].1/PPQ) as u16,
|
|
||||||
cols[t].0 as u16 + 2,
|
|
||||||
(rows[s].0 / PPQ) as u16
|
|
||||||
]),
|
|
||||||
_ => None
|
|
||||||
};
|
|
||||||
if let Some([x, y, width, height]) = track_area {
|
|
||||||
to.fill_fg([x, y, 1, height], bg);
|
|
||||||
to.fill_fg([x + width, y, 1, height], bg);
|
|
||||||
}
|
|
||||||
if let Some([_, y, _, height]) = scene_area {
|
|
||||||
to.fill_ul([x, y - 1, w, 1], bg);
|
|
||||||
to.fill_ul([x, y + height - 1, w, 1], bg);
|
|
||||||
}
|
|
||||||
if focused {
|
|
||||||
to.place(if let Some(clip_area) = clip_area {
|
|
||||||
clip_area
|
|
||||||
} else if let Some(track_area) = track_area {
|
|
||||||
track_area.clip_h(HEADER_H)
|
|
||||||
} else if let Some(scene_area) = scene_area {
|
|
||||||
scene_area.clip_w(scenes_w)
|
|
||||||
} else {
|
|
||||||
area.clip_w(scenes_w).clip_h(HEADER_H)
|
|
||||||
}, &reticle)
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A 1-row cell.
|
|
||||||
fn cell <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
|
||||||
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Fixed::y(1, field))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A phat line
|
|
||||||
fn phat_lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
|
||||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▄")))
|
|
||||||
}
|
|
||||||
/// A phat line
|
|
||||||
fn phat_hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
|
||||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▀")))
|
|
||||||
}
|
|
||||||
/// A cell that is 3-row on its own, but stacks, giving (N+1)*2 rows per N cells.
|
|
||||||
fn phat_cell <T: Content<TuiOut>> (
|
|
||||||
color: ItemPalette, last: ItemPalette, field: T
|
|
||||||
) -> impl Content<TuiOut> {
|
|
||||||
Bsp::s(phat_lo(color.base.rgb, last.base.rgb),
|
|
||||||
Bsp::n(phat_hi(color.base.rgb, last.base.rgb),
|
|
||||||
Fixed::y(1, Fill::x(Tui::fg_bg(color.lightest.rgb, color.base.rgb, field))),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
fn phat_cell_3 <T: Content<TuiOut>> (
|
|
||||||
field: T, top: Color, middle: Color, bottom: Color
|
|
||||||
) -> impl Content<TuiOut> {
|
|
||||||
Bsp::s(phat_lo(middle, top),
|
|
||||||
Bsp::n(phat_hi(middle, bottom),
|
|
||||||
Fill::y(Fill::x(Tui::bg(middle, field))),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
fn phat_sel_3 <T: Content<TuiOut>> (
|
|
||||||
selected: bool, field_1: T, field_2: T, top: Option<Color>, middle: Color, bottom: Color
|
|
||||||
) -> impl Content<TuiOut> {
|
|
||||||
let border = Style::default().fg(Color::Rgb(255,255,255)).bg(middle);
|
|
||||||
Either(selected,
|
|
||||||
Tui::bg(middle, Outer(border).enclose( Align::w(Bsp::s("", Bsp::s(field_1, ""))))),
|
|
||||||
Bsp::s(
|
|
||||||
Fixed::y(1, top.map(|top|phat_lo(middle, top))),
|
|
||||||
Bsp::n(phat_hi(middle, bottom),
|
|
||||||
Fixed::y(1, Fill::x(Tui::bg(middle, field_2))),
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
//pub struct ArrangerVCursor {
|
|
||||||
//cols: Vec<(usize, usize)>,
|
|
||||||
//rows: Vec<(usize, usize)>,
|
|
||||||
//color: ItemPalette,
|
|
||||||
//reticle: Reticle,
|
|
||||||
//selected: ArrangerSelection,
|
|
||||||
//scenes_w: u16,
|
|
||||||
//}
|
|
||||||
|
|
||||||
//from!(|args:(&Arranger, usize)|ArrangerVCursor = Self {
|
|
||||||
//cols: Arranger::track_widths(&args.0.tracks),
|
|
||||||
//rows: Arranger::scene_heights(&args.0.scenes, args.1),
|
|
||||||
//selected: args.0.selected(),
|
|
||||||
//scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&args.0.scenes) as u16,
|
|
||||||
//color: args.0.color,
|
|
||||||
//reticle: Reticle(Style {
|
|
||||||
//fg: Some(args.0.color.lighter.rgb),
|
|
||||||
//bg: None,
|
|
||||||
//underline_color: None,
|
|
||||||
//add_modifier: Modifier::empty(),
|
|
||||||
//sub_modifier: Modifier::DIM
|
|
||||||
//}),
|
|
||||||
//});
|
|
||||||
//impl Content<TuiOut> for ArrangerVCursor {
|
|
||||||
//fn render (&self, to: &mut TuiOut) {
|
|
||||||
//let area = to.area();
|
|
||||||
//let focused = true;
|
|
||||||
//let selected = self.selected;
|
|
||||||
//let get_track_area = |t: usize| [
|
|
||||||
//self.scenes_w + area.x() + self.cols[t].1 as u16, area.y(),
|
|
||||||
//self.cols[t].0 as u16, area.h(),
|
|
||||||
//];
|
|
||||||
//let get_scene_area = |s: usize| [
|
|
||||||
//area.x(), HEADER_H + area.y() + (self.rows[s].1 / PPQ) as u16,
|
|
||||||
//area.w(), (self.rows[s].0 / PPQ) as u16
|
|
||||||
//];
|
|
||||||
//let get_clip_area = |t: usize, s: usize| [
|
|
||||||
//(self.scenes_w + area.x() + self.cols[t].1 as u16).saturating_sub(1),
|
|
||||||
//HEADER_H + area.y() + (self.rows[s].1/PPQ) as u16,
|
|
||||||
//self.cols[t].0 as u16 + 2,
|
|
||||||
//(self.rows[s].0 / PPQ) as u16
|
|
||||||
//];
|
|
||||||
//let mut track_area: Option<[u16;4]> = None;
|
|
||||||
//let mut scene_area: Option<[u16;4]> = None;
|
|
||||||
//let mut clip_area: Option<[u16;4]> = None;
|
|
||||||
//let area = match selected {
|
|
||||||
//ArrangerSelection::Mix => area,
|
|
||||||
//ArrangerSelection::Track(t) => {
|
|
||||||
//track_area = Some(get_track_area(t));
|
|
||||||
//area
|
|
||||||
//},
|
|
||||||
//ArrangerSelection::Scene(s) => {
|
|
||||||
//scene_area = Some(get_scene_area(s));
|
|
||||||
//area
|
|
||||||
//},
|
|
||||||
//ArrangerSelection::Clip(t, s) => {
|
|
||||||
//track_area = Some(get_track_area(t));
|
|
||||||
//scene_area = Some(get_scene_area(s));
|
|
||||||
//clip_area = Some(get_clip_area(t, s));
|
|
||||||
//area
|
|
||||||
//},
|
|
||||||
//};
|
|
||||||
//let bg = self.color.lighter.rgb;//Color::Rgb(0, 255, 0);
|
|
||||||
//if let Some([x, y, width, height]) = track_area {
|
|
||||||
//to.fill_fg([x, y, 1, height], bg);
|
|
||||||
//to.fill_fg([x + width, y, 1, height], bg);
|
|
||||||
//}
|
|
||||||
//if let Some([_, y, _, height]) = scene_area {
|
|
||||||
//to.fill_ul([area.x(), y - 1, area.w(), 1], bg);
|
|
||||||
//to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
|
|
||||||
//}
|
|
||||||
//if focused {
|
|
||||||
//to.place(if let Some(clip_area) = clip_area {
|
|
||||||
//clip_area
|
|
||||||
//} else if let Some(track_area) = track_area {
|
|
||||||
//track_area.clip_h(HEADER_H)
|
|
||||||
//} else if let Some(scene_area) = scene_area {
|
|
||||||
//scene_area.clip_w(self.scenes_w)
|
|
||||||
//} else {
|
|
||||||
//area.clip_w(self.scenes_w).clip_h(HEADER_H)
|
|
||||||
//}, &self.reticle)
|
|
||||||
//};
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//impl Arranger {
|
|
||||||
//fn render_mode (state: &Self) -> impl Content<TuiOut> + use<'_> {
|
|
||||||
//match state.mode {
|
|
||||||
//ArrangerMode::H => todo!("horizontal arranger"),
|
|
||||||
//ArrangerMode::V(factor) => Self::render_mode_v(state, factor),
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//render!(TuiOut: (self: Arranger) => {
|
|
||||||
//let pool_w = if self.pool.visible { self.splits[1] } else { 0 };
|
|
||||||
//let color = self.color;
|
|
||||||
//let layout = Bsp::a(Fill::xy(ArrangerStatus::from(self)),
|
|
||||||
//Bsp::n(Fixed::x(pool_w, PoolView(self.pool.visible, &self.pool)),
|
|
||||||
//Bsp::n(TransportView::new(true, &self.clock),
|
|
||||||
//Bsp::s(Fixed::y(1, MidiEditStatus(&self.editor)),
|
|
||||||
//Bsp::n(Fill::x(Fixed::y(20,
|
|
||||||
//Bsp::a(Fill::xy(Tui::bg(color.darkest.rgb, "background")),
|
|
||||||
//Bsp::a(
|
|
||||||
//Fill::xy(Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb))),
|
|
||||||
//Self::render_mode(self))))), Fill::y(&"fixme: self.editor"))))));
|
|
||||||
//self.size.of(layout)
|
|
||||||
//});
|
|
||||||
//Align::n(Fill::xy(lay!(
|
|
||||||
//Align::n(Fill::xy(Tui::bg(self.color.darkest.rgb, " "))),
|
|
||||||
//Align::n(Fill::xy(ArrangerVRowSep::from((self, 1)))),
|
|
||||||
//Align::n(Fill::xy(ArrangerVColSep::from(self))),
|
|
||||||
//Align::n(Fill::xy(ArrangerVClips::new(self, 1))),
|
|
||||||
//Align::n(Fill::xy(ArrangerVCursor::from((self, 1))))))))))))))));
|
|
||||||
//Align::n(Fill::xy(":")))))))))))));
|
|
||||||
//"todo:"))))))));
|
|
||||||
//Bsp::s(
|
|
||||||
//Align::n(Fixed::y(1, Fill::x(ArrangerVIns::from(self)))),
|
|
||||||
//Bsp::s(
|
|
||||||
//Fixed::y(20, Align::n(ArrangerVClips::new(self, 1))),
|
|
||||||
//Fill::x(Fixed::y(1, ArrangerVOuts::from(self)))))))))))));
|
|
||||||
//Bsp::s(
|
|
||||||
//Bsp::s(
|
|
||||||
//Bsp::s(
|
|
||||||
//Fill::xy(ArrangerVClips::new(self, 1)),
|
|
||||||
//Fill::x(ArrangerVOuts::from(self)))))
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue