wip: tryptich layout

This commit is contained in:
🪞👃🪞 2025-03-09 07:00:19 +02:00
parent 438a2d86a6
commit 30f2cba54d
4 changed files with 246 additions and 282 deletions

View file

@ -6,6 +6,7 @@
#![feature(impl_trait_in_assoc_type)]
#![feature(type_alias_impl_trait)]
#![feature(trait_alias)]
#![feature(type_changing_struct_update)]
mod cli; pub use self::cli::*;
mod audio; pub use self::audio::*;
mod device; pub use self::device::*;

View file

@ -36,38 +36,6 @@ provide_num!(u16: |self: Tek| {
":y-outs" => (self.size.h() as u16).saturating_sub(self.h_outputs() + 1),
":y-samples" => if self.is_editing() { 1 } else { 0 },
});
pub(crate) fn row <'a> (
w: u16,
h: u16,
s: u16,
a: impl Content<TuiOut> + 'a,
b: impl Content<TuiOut> + 'a,
c: impl Content<TuiOut> + 'a,
) -> impl Content<TuiOut> + 'a {
Fixed::y(h, Bsp::a(
Fill::xy(Align::c(Fixed::x(w, Align::x(b)))),
Bsp::a(
Fill::xy(Align::w(Fixed::x(s, a))),
Fill::xy(Align::e(Fixed::x(s, c))),
),
))
}
pub(crate) fn row_top <'a> (
w: u16,
h: u16,
s: u16,
a: impl Content<TuiOut> + 'a,
b: impl Content<TuiOut> + 'a,
c: impl Content<TuiOut> + 'a,
) -> impl Content<TuiOut> + 'a {
Fixed::y(h, Bsp::a(
Fill::x(Align::n(Fixed::x(w, Align::x(Tui::bg(Reset, b))))),
Bsp::a(
Fill::x(Align::nw(Fixed::x(s, Tui::bg(Reset, a)))),
Fill::x(Align::ne(Fixed::x(s, Tui::bg(Reset, c)))),
),
))
}
pub(crate) fn wrap (
bg: Color,
fg: Color,

View file

@ -1,65 +1,67 @@
use crate::*;
/// A three-column row.
struct Tryptich<A, B, C> {
pub top: bool,
pub h: u16,
pub left: (u16, A),
pub middle: (u16, B),
pub right: (u16, C),
}
impl Tryptich<(), (), ()> {
fn center (h: u16) -> Self {
Self { h, top: false, left: (0, ()), middle: (0, ()), right: (0, ()) }
}
fn top (h: u16) -> Self {
Self { h, top: true, left: (0, ()), middle: (0, ()), right: (0, ()) }
}
}
impl<A, B, C> Tryptich<A, B, C> {
fn left <D> (self, w: u16, content: D) -> Tryptich<D, B, C> {
Tryptich { left: (w, content), ..self }
}
fn middle <D> (self, w: u16, content: D) -> Tryptich<A, D, C> {
Tryptich { middle: (w, content), ..self }
}
fn right <D> (self, w: u16, content: D) -> Tryptich<A, B, D> {
Tryptich { right: (w, content), ..self }
}
}
impl<A, B, C> Content<TuiOut> for Tryptich<A, B, C>
where A: Content<TuiOut>, B: Content<TuiOut>, C: Content<TuiOut> {
fn content (&self) -> impl Render<TuiOut> {
let Self { top, h, left: (w_a, ref a), middle: (w_b, ref b), right: (w_c, ref c) } = *self;
if top {
Fixed::y(h, Bsp::a(
Fill::x(Align::n(Fixed::x(w_b, Align::x(Tui::bg(Reset, b))))),
Bsp::a(
Fill::x(Align::nw(Fixed::x(w_a, Tui::bg(Reset, a)))),
Fill::x(Align::ne(Fixed::x(w_c, Tui::bg(Reset, c)))),
),
))
} else {
Fixed::y(h, Bsp::a(
Fill::xy(Align::c(Fixed::x(w_b, Align::x(Tui::bg(Reset, b))))),
Bsp::a(
Fill::xy(Align::w(Fixed::x(w_a, Tui::bg(Reset, a)))),
Fill::xy(Align::e(Fixed::x(w_c, Tui::bg(Reset, c)))),
),
))
}
}
}
impl Tek {
// FIXME: The memoized arranger is too complex.
// Just render a slice of the arranger for now,
// starting from tracks[scroll_offset] and ending
// at the last track that fits fully.
/// Blit the currently visible section of the arranger view buffer to the output.
///
/// If the arranger is larger than the available display area,
/// the scrollbars determine the portion that will be shown.
///
/// This function is called on every frame, but is relatively cheap
/// as the rendering logic of [redraw_arranger] is only invoked on
/// changes to the content.
pub fn view_arranger_todo (&self) -> impl Content<TuiOut> + use<'_> {
Fill::xy(ThunkRender::new(move|to: &mut TuiOut|{
let [x0, y0, w, h] = to.area().xywh();
let source = self.arranger.read().unwrap();
for (source_x, target_x) in (x0..x0+w).enumerate() {
for (source_y, target_y) in (y0..y0+h).enumerate() {
let target_pos = Position::from((target_x, target_y));
if let Some(target) = to.buffer.cell_mut(target_pos) {
//target.set_bg(Color::Rgb(128,0,0));
let source_pos = Position::from((source_x as u16, source_y as u16));
if let Some(source) = source.cell(source_pos) {
*target = source.clone();
//target.set_bg(Color::Rgb(0,128,0));
}
}
}
}
}))
}
/// Draw the full arranger to the arranger view buffer.
///
/// This should happen on changes to the arrangement contents,
/// i.e. not on scroll. Scrolling just determines which part
/// of the arranger buffer to blit in [view_arranger].
pub fn redraw_arranger (&self) {
return;
//let width = self.w_tracks();
//let height = self.h_scenes() + self.h_inputs() + self.h_outputs();
//let buffer = Buffer::empty(ratatui::prelude::Rect { x: 0, y: 0, width, height });
//let mut output = TuiOut { buffer, area: [0, 0, width, height] };
//let layout = Bsp::s(self.view_inputs(),
//Bsp::s(self.view_tracks(),
//Bsp::n(self.view_outputs(),
//self.view_scenes())));
//Content::render(&layout, &mut output);
//*self.arranger.write().unwrap() = output.buffer;
}
pub fn redraw_arranger (&self) { /*FIXME: remove*/ }
pub fn view_arranger (&self) -> impl Content<TuiOut> + use<'_> {
let ins = self.view_inputs();
let trs = self.view_tracks();
let out = self.view_outputs();
let scn = self.view_scenes();
Bsp::s(ins, Bsp::s(trs, Bsp::n(out, scn)))
let inputs = self.view_inputs();
let tracks = self.view_tracks();
let scenes = self.view_scenes();
let outputs = self.view_outputs();
Bsp::s(inputs, Bsp::s(tracks, Bsp::n(outputs, scenes)))
}
pub fn view_tracks (&self) -> impl Content<TuiOut> + use<'_> {
@ -68,8 +70,12 @@ impl Tek {
let data = (self.selected.track().unwrap_or(0), self.tracks().len());
let editing = self.is_editing();
self.fmtd.write().unwrap().trks.update(Some(data), rewrite!(buf, "{}/{}", data.0, data.1));
row(w, 1, s, button_3("t", "track", self.fmtd.read().unwrap().trks.view.clone(), editing),
self.per_track(|t, track|track_header(t, track, self.selected().track() == Some(t))),
Tryptich::center(1)
.left(s,
button_3("t", "track", self.fmtd.read().unwrap().trks.view.clone(), editing))
.middle(w,
self.per_track(|t, track|track_header(t, track, self.selected().track() == Some(t))))
.right(s,
button_2("T", "add track", editing))
}
@ -94,8 +100,8 @@ impl Tek {
let total = self.h_scenes() as usize;
Fill::y(Fixed::x(1, ScrollbarV { offset, length, total }))
};
Tui::bg(Reset, Bsp::s(track_scroll, Bsp::e(scene_scroll, Fixed::y(h_area, row(w, h, s,
Map::new(
let row = Tryptich::center(h)
.left(s, Map::new(
move||self.scenes_with_colors(editing, h_area),
move|(s, scene, y1, y2, prev): SceneWithColor, _|view_scene_name(
w_full,
@ -107,15 +113,14 @@ impl Tek {
s == self.scenes.len().saturating_sub(1),
self.selected().scene(),
)
),
self.per_track(move|t, track|Map::new(
))
.middle(w, self.per_track(move|t, track|Map::new(
move||self.scenes_with_track_colors(editing, h_area, t),
move|(s, scene, y1, y2, prev): SceneWithColor, _|self.view_scene_clip(
w, (1 + y2 - y1) as u16, y1 as u16,
scene, prev, s, t, editing, st == Some(t), ss)
)),
()
)))))
)));
Tui::bg(Reset, Bsp::s(track_scroll, Bsp::e(scene_scroll, Fixed::y(h_area, row))))
}
fn view_scene_clip (
@ -160,59 +165,42 @@ impl Tek {
}
pub fn view_outputs (&self) -> impl Content<TuiOut> + use<'_> {
let fg = Tui::g(224);
let bg = Tui::g(32);
let len = self.midi_outs.len();
let ed = self.is_editing();
let ws = self.w_tracks_area();
let s = self.w_sidebar() as u16;
let ts = move||self.tracks_sizes_scrolled();
let sel = self.selected().track();
let ho = self.h_outputs() - 1;
let os = ||self.outputs_sizes();
let pts = io_ports(fg, bg, os);
let tr = self.tracks.as_ref();
view_outputs(ws, s, ho, len, ed, sel, tr, ts, os, pts)
let height = self.h_outputs().saturating_sub(1);
let w_mid = self.w_tracks_area();
let w_side = self.w_sidebar() as u16;
let tracks = ||self.tracks_sizes_scrolled();
view_outputs(
view_output_nexts(w_mid, w_side, tracks),
view_output_froms(w_mid, w_side, tracks),
view_output_conns(w_mid, w_side, tracks, height, ||self.outputs_sizes()),
view_output_ports(w_mid, w_side, tracks,
self.midi_outs.len(), self.selected().track(), self.is_editing()))
}
pub fn view_inputs (&self) -> impl Content<TuiOut> + use<'_> {
let fg = Tui::g(224);
let bg = Tui::g(32);
let ws = self.w_sidebar() as u16;
let w = (self.size.w() as u16).saturating_sub(2 * ws);
let wt = self.w_tracks_area();
let ts = move||self.tracks_sizes_scrolled();
let is = ||self.inputs_sizes();
let len = self.midi_ins.len();
let sel = self.selected().track();
let tr = self.tracks().as_ref();
let ed = self.is_editing();
let hi = self.h_inputs() - 1;
let pts = io_ports(fg, bg, is);
let to_conns = move|_, &Track { color, .. }|io_conns(color.dark.rgb, color.darker.rgb, is);
view_inputs(w, ws, wt, ts,
row_top(w, hi, ws, pts, per_track_top(wt, ts, to_conns), ()),
input_ports(w, ws, len, wt, ts, sel, tr, ed))
let height = self.h_inputs().saturating_sub(1);
let w_mid = self.w_tracks_area();
let w_side = self.w_sidebar() as u16;
let tracks = ||self.tracks_sizes_scrolled();
view_inputs(
view_input_intos(w_mid, w_side, tracks),
view_input_routes(w_mid, w_side, tracks, height, ||self.inputs_sizes()),
view_input_ports(w_mid, w_side, tracks,
self.midi_ins.len(), self.selected().track(), self.is_editing()))
}
/// Render something centered for each track.
fn per_track <'a, T: Content<TuiOut> + 'a> (
&'a self, f: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
self.per_track_top(
move|index, track|Fill::y(Align::y(f(index, track)))
)
self.per_track_top(move|index, track|Fill::y(Align::y(f(index, track))))
}
/// Render something top-aligned for each track.
fn per_track_top <'a, T: Content<TuiOut> + 'a> (
&'a self, callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
per_track_top(
self.w_tracks_area(),
move||self.tracks_sizes_scrolled(),
callback
)
per_track_top(self.w_tracks_area(), move||self.tracks_sizes_scrolled(), callback)
}
}
@ -225,11 +213,11 @@ fn view_scene_name (
scene: &Scene,
prev: Option<ItemPalette>,
last: bool,
selected: Option<usize>,
select: Option<usize>,
) -> impl Content<TuiOut> {
Fill::x(map_south(offset, height, Fixed::y(height, scene_cell(
last,
selected,
select,
true,
index,
&scene.color,
@ -240,110 +228,50 @@ fn view_scene_name (
))))
}
fn view_inputs <'a, T, U, V, W> (
ws: u16,
s: u16,
wt: u16,
ts: U,
routes: V,
ports: W,
) -> impl Content<TuiOut> + use<'a, T, U, V, W> where
T: TracksSizes<'a>,
U: Fn()->T + Send + Sync + 'a,
V: Content<TuiOut>,
W: Content<TuiOut>,
fn view_inputs <'a, T, U, V> (
intos: T, routes: U, ports: V,
) -> impl Content<TuiOut> + use<'a, T, U, V> where
T: Content<TuiOut> + 'a,
U: Content<TuiOut> + 'a,
V: Content<TuiOut> + 'a,
{
let headers = Bsp::s(Align::e("Input:"), Align::e("Into:"));
let sep = |_, _|Tui::bg(Reset, Align::c(Bsp::s(OctaveVertical::default(), " ------ ")));
let separators = per_track_top(wt, ts, sep);
Bsp::s(Bsp::s(routes, ports), row_top(ws, 2, s, headers, separators, ()))
Bsp::s(Bsp::s(routes, ports), intos)
}
fn view_outputs <'a, T, U, V, W, X> (
ws: u16,
s: u16,
ho: u16,
len: usize,
ed: bool,
sel: Option<usize>,
tr: &'a [Track],
ts: U,
os: W,
pts: X,
) -> impl Content<TuiOut> + use<'a, T, U, V, W, X> where
T: TracksSizes<'a>,
U: Fn()->T + Send + Sync + 'a,
V: PortsSizes<'a>,
W: Fn()->V + Send + Sync + 'a,
X: Content<TuiOut> + 'a
{
let fg = Tui::g(224);
let conns = row_top(ws, ho, s, pts, per_track_top(
ws, ts, |t, track|io_conns(track.color.dark.rgb, track.color.darker.rgb, os)
), ());
let nexts = row_top(ws, 2, s, Align::ne("Next:"), per_track_top(ws, ts, |t, track|Either(
track.player.next_clip.is_some(),
Thunk::new(||Tui::bg(Reset, format!("{:?}",
track.player.next_clip.as_ref()
.map(|(moment, clip)|clip.as_ref()
.map(|clip|clip.read().unwrap().name.clone()))
.flatten().as_ref()))),
Thunk::new(||Tui::bg(Reset, " ------ "))
)), ());
let bar = row_top(
ws,
2,
s,
Align::ne("From:"),
per_track_top(
ws,
ts,
|_, _|Tui::bg(Reset, Align::c(Bsp::s(" ------ ", OctaveVertical::default(),)))
),
()
);
let baz = row_top(
ws,
1,
s,
button_3("o", "midi outs", format!("{}", len), ed),
per_track_top(
ws,
ts,
move|t, track|{
let mute = false;
let solo = false;
let mute = if mute { White } else { track.color.darkest.rgb };
let solo = if solo { White } else { track.color.darkest.rgb };
let bg1 = if sel == Some(t) { track.color.light.rgb } else { track.color.base.rgb };
let bg2 = if t > 0 { tr[t].color.base.rgb } else { Reset };
wrap(bg1, fg, Tui::bold(true, Fill::x(Bsp::e(
Tui::fg_bg(mute, bg1, "Play "),
Tui::fg_bg(solo, bg1, "Solo ")))))
}
),
button_2("O", "add midi out", ed)
);
Align::n(Bsp::s(Bsp::s(nexts, bar), Bsp::s(baz, conns)))
fn view_input_intos <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
w_mid: u16, w_side: u16, tracks: U,
) -> impl Content<TuiOut> + use<'a, T, U> {
Tryptich::top(2)
.left(w_side, Bsp::s(Align::e("Input:"), Align::e("Into:")))
.middle(w_mid, per_track_top(w_mid, tracks, |_, _|Tui::bg(Reset,
Align::c(Bsp::s(OctaveVertical::default(), " ------ ")))))
}
fn input_ports <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
w: u16,
s: u16,
midi_ins: usize,
w_tracks_area: u16,
tracks_sizes: U,
fn view_input_routes <'a, T, U, V, W> (
w_mid: u16, w_side: u16, tracks: U, height: u16, inputs: W
) -> impl Content<TuiOut> + use<'a, T, U> where
T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a,
V: PortsSizes<'a>, W: Fn()->T + Send + Sync + 'a,
{
Tryptich::top(height)
.left(w_side, io_ports(Tui::g(224), Tui::g(32), inputs))
.middle(w_mid, per_track_top(w_mid, tracks, move|_, &Track { color, .. }|{
io_conns(color.dark.rgb, color.darker.rgb, inputs)
}))
}
fn view_input_ports <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
w_mid: u16,
w_side: u16,
tracks: U,
port_count: usize,
selected_track: Option<usize>,
tracks: &'a [Track],
editing: bool,
) -> impl Content<TuiOut> + use<'a, T, U> {
let fg = Tui::g(224);
let btn_ins = button_3("i", "midi ins", format!("{}", midi_ins), editing);
let btn_add = button_2("I", "add midi in", editing);
let inputs = per_track_top(
w_tracks_area,
tracks_sizes,
move|t, track|{
Tryptich::top(1)
.left(w_side, button_3("i", "midi ins", format!("{port_count}"), editing))
.right(w_side, button_2("I", "add midi in", editing))
.middle(w_mid, per_track_top(w_mid, tracks, move|t, track|{
let rec = track.player.recording;
let mon = track.player.monitoring;
let rec = if rec { White } else { track.color.darkest.rgb };
@ -353,14 +281,87 @@ fn input_ports <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
} else {
track.color.base.rgb
};
//let bg2 = if t > 0 { tracks[t - 1].color.base.rgb } else { Reset };
wrap(bg, fg, Tui::bold(true, Fill::x(Bsp::e(
//let bg2 = if t > 0 { track.color.base.rgb } else { Reset };
wrap(bg, Tui::g(224), Tui::bold(true, Fill::x(Bsp::e(
Tui::fg_bg(rec, bg, "Rec "),
Tui::fg_bg(mon, bg, "Mon "))
)))
}
);
row_top(w, 1, s, btn_ins, inputs, btn_add)
Tui::fg_bg(mon, bg, "Mon "),
))))
}))
}
fn view_outputs <'a, T, U, V, W> (
nexts: T, froms: U, conns: V, outputs: W,
) -> impl Content<TuiOut> + use<'a, T, U, V, W> where
T: Content<TuiOut> + 'a,
U: Content<TuiOut> + 'a,
V: Content<TuiOut> + 'a,
W: Content<TuiOut> + 'a,
{
Align::n(Bsp::s(Bsp::s(nexts, froms), Bsp::s(outputs, conns)))
}
fn view_output_nexts <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
w_mid: u16, w_side: u16, tracks: U
) -> impl Content<TuiOut> + use<'a, T, U> {
Tryptich::top(2)
.left(w_side, Align::ne("From:"))
.middle(w_mid, per_track_top(w_mid, tracks, |_, _|Tui::bg(Reset,
Align::c(Bsp::s(" ------ ", OctaveVertical::default())))))
}
fn view_output_froms <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
w_mid: u16, w_side: u16, tracks: U
) -> impl Content<TuiOut> + use<'a, T, U> {
Tryptich::top(2)
.left(w_side, Align::ne("Next:"))
.middle(w_mid, per_track_top(w_mid, tracks, |t, track|Either(
track.player.next_clip.is_some(),
Thunk::new(||Tui::bg(Reset, format!("{:?}",
track.player.next_clip.as_ref()
.map(|(moment, clip)|clip.as_ref()
.map(|clip|clip.read().unwrap().name.clone()))
.flatten().as_ref()))),
Thunk::new(||Tui::bg(Reset, " ------ ")))))
}
fn view_output_conns <'a, T, U, V, W> (
w_mid: u16, w_side: u16, tracks: U, height: u16, outputs: W
) -> impl Content<TuiOut> + use<'a, T, U, V, W> where
T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a,
V: PortsSizes<'a>, W: Fn()->T + Send + Sync + 'a,
{
Tryptich::top(height)
.left(w_side,
io_ports(Tui::g(224), Tui::g(32), outputs))
.middle(w_mid,
per_track_top(w_mid, tracks, |_, t|{
io_conns(t.color.dark.rgb, t.color.darker.rgb, outputs)
}))
}
fn view_output_ports <'a, T: TracksSizes<'a>, U: Fn()->T + Send + Sync + 'a> (
w_mid: u16,
w_side: u16,
tracks_sizes: U,
port_count: usize,
selected_track: Option<usize>,
editing: bool,
) -> impl Content<TuiOut> + use<'a, T, U> {
Tryptich::top(1)
.left(w_side, button_3("o", "midi outs", format!("{port_count}"), editing))
.right(w_side, button_2("O", "add midi out", editing))
.middle(w_mid, per_track_top(w_mid, tracks_sizes, move|t, track|{
let mute = false;
let solo = false;
let mute = if mute { White } else { track.color.darkest.rgb };
let solo = if solo { White } else { track.color.darkest.rgb };
let bg1 = if selected_track == Some(t) { track.color.light.rgb } else { track.color.base.rgb };
let bg2 = if t > 0 { track.color.base.rgb } else { Reset };
wrap(bg1, Tui::g(224), Tui::bold(true, Fill::x(Bsp::e(
Tui::fg_bg(mute, bg1, "Play "),
Tui::fg_bg(solo, bg1, "Solo "),
))))
}))
}
fn per_track_top <'a, T: Content<TuiOut> + 'a, U: TracksSizes<'a>> (
@ -380,7 +381,7 @@ fn per_track_top <'a, T: Content<TuiOut> + 'a, U: TracksSizes<'a>> (
fn scene_cell <'a> (
is_last: bool,
selected_scene: Option<usize>,
selected: Option<usize>,
same_track: bool,
scene: usize,
color: &ItemPalette,
@ -396,26 +397,22 @@ fn scene_cell <'a> (
colors: Tek::colors(
color,
prev,
same_track && selected_scene == Some(scene),
same_track && scene > 0 && selected_scene == Some(scene - 1),
same_track && selected == Some(scene),
same_track && scene > 0 && selected == Some(scene - 1),
is_last
)
}
}
fn track_header <'a> (t: usize, track: &'a Track, active: bool) -> impl Content<TuiOut> + use<'a> {
let name = &track.name;
let fg = track.color.lightest.rgb;
let bg = if active { track.color.light.rgb } else { track.color.base.rgb };
let bg2 = Reset;//if t > 0 { self.tracks()[t - 1].color.base.rgb } else { Reset };
let bfg = if active { Rgb(255,255,255) } else { Rgb(0,0,0) };
wrap(bg, fg, Tui::bold(true, Fill::x(Align::nw(name))))
wrap(bg, fg, Tui::bold(true, Fill::x(Align::nw(&track.name))))
}
fn io_ports <'a, T: PortsSizes<'a>> (
fg: Color,
bg: Color,
iter: impl Fn()->T + Send + Sync + 'a
fg: Color, bg: Color, iter: impl Fn()->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
Map::new(iter,
move|(index, name, connections, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s(
@ -426,9 +423,7 @@ fn io_ports <'a, T: PortsSizes<'a>> (
}
fn io_conns <'a, T: PortsSizes<'a>> (
fg: Color,
bg: Color,
iter: impl Fn()->T + Send + Sync + 'a
fg: Color, bg: Color, iter: impl Fn()->T + Send + Sync + 'a
) -> impl Content<TuiOut> + 'a {
Map::new(iter,
move|(index, name, connections, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s(

View file

@ -547,10 +547,10 @@ impl AddSampleModal {
return Ok(false)
}
}
pub fn read_sample_data (_: &str) -> Usually<(usize, Vec<Vec<f32>>)> {
fn read_sample_data (_: &str) -> Usually<(usize, Vec<Vec<f32>>)> {
todo!();
}
pub fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
let (mut subdirs, mut files) = std::fs::read_dir(dir)?
.fold((vec!["..".into()], vec![]), |(mut subdirs, mut files), entry|{
let entry = entry.expect("failed to read drectory entry");
@ -566,7 +566,7 @@ pub fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
files.sort();
Ok((subdirs, files))
}
pub fn draw_sample (
fn draw_sample (
to: &mut TuiOut, x: u16, y: u16, note: Option<&u7>, sample: &Sample, focus: bool
) -> Usually<usize> {
let style = if focus { Style::default().green() } else { Style::default() };