mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
239 lines
8.5 KiB
Rust
239 lines
8.5 KiB
Rust
use crate::*;
|
|
|
|
/// Draw arranger with 1 row per scene.
|
|
pub fn draw_compact_1 (state: &Arranger, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
|
let scene_rows = (0..=state.scenes.len()).map(|i|(96, 96*i)).collect::<Vec<_>>();
|
|
draw(state, buf, area, track_cols.as_slice(), scene_rows.as_slice())
|
|
}
|
|
|
|
/// Draw arranger with 2 rows per scene.
|
|
pub fn draw_compact_2 (state: &Arranger, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
|
let scene_rows = (0..=state.scenes.len()).map(|i|(192, 192*i)).collect::<Vec<_>>();
|
|
draw(state, buf, area, track_cols.as_slice(), scene_rows.as_slice())
|
|
}
|
|
|
|
/// Draw arranger with number of rows per scene corresponding to duration of scene.
|
|
pub fn draw_expanded (state: &Arranger, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
|
let scene_rows = scene_ppqs(state.tracks.as_slice(), state.scenes.as_slice());
|
|
draw(state, buf, area, track_cols.as_slice(), scene_rows.as_slice())
|
|
}
|
|
|
|
pub fn draw (
|
|
state: &Arranger,
|
|
buf: &mut Buffer,
|
|
mut area: Rect,
|
|
cols: &[(usize, usize)],
|
|
rows: &[(usize, usize)],
|
|
) -> Usually<Rect> {
|
|
area.height = 2 + (rows[rows.len() - 1].1 / 96) as u16;
|
|
let offset = 3 + scene_name_max_len(state.scenes.as_ref()) as u16;
|
|
let Arranger { focus_sequencer, focused, entered, selected, .. } = *state;
|
|
let tracks = state.tracks.as_ref();
|
|
let scenes = state.scenes.as_ref();
|
|
Layered::new()
|
|
.add(FillBg(Nord::bg_lo(state.focused, state.entered)))
|
|
.add(ColumnSeparators(offset, cols))
|
|
.add(CursorFocus(focus_sequencer, focused, entered, selected, offset, cols, rows))
|
|
.add(Split::down()
|
|
.add(TracksHeader(offset, cols, tracks))
|
|
.add(SceneRows(offset, cols, rows, tracks, scenes)))
|
|
.add(RowSeparators(rows))
|
|
.render(buf, area)
|
|
}
|
|
|
|
struct ColumnSeparators<'a>(u16, &'a [(usize, usize)]);
|
|
|
|
impl<'a> Render for ColumnSeparators<'a> {
|
|
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let Self(offset, cols) = self;
|
|
let style = Some(Style::default().fg(Nord::SEPARATOR));
|
|
for (_, x) in cols.iter() {
|
|
let x = offset + area.x + *x as u16 - 1;
|
|
for y in area.y..area.height+area.y {
|
|
"▎".blit(buf, x, y, style)?;
|
|
}
|
|
}
|
|
Ok(area)
|
|
}
|
|
}
|
|
|
|
struct RowSeparators<'a>(&'a [(usize, usize)]);
|
|
|
|
impl<'a> Render for RowSeparators<'a> {
|
|
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let Self(rows) = self;
|
|
for (_, y) in rows.iter() {
|
|
let y = area.y + (*y / 96) as u16 + 1;
|
|
if y >= buf.area.height {
|
|
break
|
|
}
|
|
for x in area.x..area.width+area.y-2 {
|
|
let cell = buf.get_mut(x, y);
|
|
cell.modifier = Modifier::UNDERLINED;
|
|
cell.underline_color = Nord::SEPARATOR;
|
|
}
|
|
}
|
|
Ok(area)
|
|
}
|
|
}
|
|
|
|
struct CursorFocus<'a>(
|
|
bool, bool, bool, ArrangerFocus, u16, &'a [(usize, usize)], &'a [(usize, usize)]
|
|
);
|
|
|
|
impl<'a> Render for CursorFocus<'a> {
|
|
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let Self(focus_sequencer, focused, entered, selected, offset, cols, rows) = *self;
|
|
let area = match selected {
|
|
ArrangerFocus::Mix => if focused
|
|
&& entered
|
|
&& selected == ArrangerFocus::Mix
|
|
{
|
|
fill_bg(buf, area, Nord::bg_hi(focused, entered));
|
|
area
|
|
} else {
|
|
area
|
|
},
|
|
ArrangerFocus::Track(t) => {
|
|
let area = Rect {
|
|
x: offset + area.x + cols[t].1 as u16 - 1,
|
|
y: area.y,
|
|
width: cols[t].0 as u16,
|
|
height: area.height
|
|
};
|
|
fill_bg(buf, area, Nord::bg_hi(focused, entered));
|
|
area
|
|
},
|
|
ArrangerFocus::Scene(s) => {
|
|
let area = Rect {
|
|
x: area.x,
|
|
y: 2 + area.y + (rows[s].1 / 96) as u16,
|
|
width: area.width,
|
|
height: (rows[s].0 / 96) as u16
|
|
};
|
|
fill_bg(buf, area, Nord::bg_hi(focused, entered));
|
|
area
|
|
},
|
|
ArrangerFocus::Clip(t, s) => {
|
|
let track_area = Rect {
|
|
x: offset + area.x + cols[t].1 as u16 - 1,
|
|
y: area.y,
|
|
width: cols[t].0 as u16,
|
|
height: area.height
|
|
};
|
|
let scene_area = Rect {
|
|
x: area.x,
|
|
y: 2 + area.y + (rows[s].1 / 96) as u16,
|
|
width: area.width,
|
|
height: (rows[s].0 / 96) as u16
|
|
};
|
|
let area = Rect {
|
|
x: offset + area.x + cols[t].1 as u16 - 1,
|
|
y: 2 + area.y + (rows[s].1 / 96) as u16,
|
|
width: cols[t].0 as u16,
|
|
height: (rows[s].0 / 96) as u16
|
|
};
|
|
let lo = Nord::bg_hi(focused, entered);
|
|
let hi = Nord::bg_hier(focused, entered);
|
|
fill_bg(buf, track_area, lo);
|
|
fill_bg(buf, scene_area, lo);
|
|
fill_bg(buf, area, hi);
|
|
area
|
|
},
|
|
};
|
|
if !focus_sequencer {
|
|
Corners(Style::default().green().not_dim()).draw(buf, area)?;
|
|
}
|
|
Ok(area)
|
|
}
|
|
}
|
|
|
|
struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer]);
|
|
|
|
impl<'a> Render for TracksHeader<'a> {
|
|
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let Self(offset, track_cols, tracks) = *self;
|
|
let Rect { y, width, .. } = area;
|
|
for (track, (_, x)) in tracks.iter().zip(track_cols) {
|
|
let x = *x as u16;
|
|
if x > width {
|
|
break
|
|
}
|
|
track.name.blit(buf, offset + x + 1, y, Some(Style::default()))?;
|
|
}
|
|
Ok(Rect { x: area.x, y, width, height: 2 })
|
|
}
|
|
}
|
|
|
|
struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer], &'a[Scene]);
|
|
|
|
impl<'a> Render for SceneRows<'a> {
|
|
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
|
|
let Self(offset, track_cols, scene_rows, tracks, scenes) = *self;
|
|
let black = Some(Style::default().fg(Nord::SEPARATOR));
|
|
let Rect { mut y, height, .. } = area;
|
|
for (_, x) in track_cols.iter() {
|
|
let x = *x as u16;
|
|
if x > 0 {
|
|
for y in area.y-2..y-2 {
|
|
"▎".blit(buf, x - 1, y, black)?;
|
|
}
|
|
}
|
|
}
|
|
for (scene, (pulses, _)) in scenes.iter().zip(scene_rows) {
|
|
if y > height {
|
|
break
|
|
}
|
|
let h = 1.max((pulses / 96) as u16);
|
|
scene_row(tracks, buf, Rect {
|
|
x: area.x,
|
|
y,
|
|
width: area.width,
|
|
height: h,//.min(area.height - y)
|
|
}, scene, track_cols, offset)?;
|
|
y = y + h
|
|
}
|
|
Ok(area)
|
|
}
|
|
}
|
|
|
|
fn scene_row <'a> (
|
|
tracks: &'a[Sequencer],
|
|
buf: &mut Buffer,
|
|
area: Rect,
|
|
scene: &Scene,
|
|
track_cols: &[(usize, usize)],
|
|
offset: u16
|
|
) -> Usually<u16> {
|
|
let Rect { y, width, .. } = area;
|
|
let playing = scene.is_playing(tracks);
|
|
(if playing { "▶" } else { " " }).blit(buf, area.x, y, None)?;
|
|
scene.name.blit(buf, area.x + 1, y, None)?;
|
|
let style = Some(Style::default().white());
|
|
for (track, (w, x)) in track_cols.iter().enumerate() {
|
|
let x = *x as u16 + offset;
|
|
if x > width {
|
|
break
|
|
}
|
|
if let (Some(track), Some(Some(clip))) = (
|
|
tracks.get(track), scene.clips.get(track)
|
|
) {
|
|
if let Some(phrase) = track.phrases.get(*clip) {
|
|
let phrase = phrase.read().unwrap();
|
|
phrase.name.blit(buf, x + 1, y, style)?;
|
|
if track.sequence == Some(*clip) {
|
|
fill_bg(buf, Rect {
|
|
x: x - 1,
|
|
y,
|
|
width: *w as u16,
|
|
height: area.height,
|
|
}, Nord::PLAYING);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok((scene.pulses(tracks) / 96) as u16)
|
|
}
|