mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
wip: tryptich layout
This commit is contained in:
parent
438a2d86a6
commit
30f2cba54d
4 changed files with 246 additions and 282 deletions
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 "))
|
||||
)))
|
||||
Tui::fg_bg(mon, bg, "Mon "),
|
||||
))))
|
||||
}))
|
||||
}
|
||||
);
|
||||
row_top(w, 1, s, btn_ins, inputs, btn_add)
|
||||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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() };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue