update for unowned draw
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
i do not exist 2026-08-04 12:24:39 +03:00
parent 8de62463c0
commit a938b68980
5 changed files with 262 additions and 336 deletions

View file

@ -439,10 +439,18 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize +
fn w_mid (&self) -> u16; fn w_mid (&self) -> u16;
fn view_scenes_names (&self) -> impl Draw<Tui> { fn view_scenes_names (&self) -> impl Draw<Tui> {
view_scenes_names( let select = self.selection();
self.scenes_with_sizes(), self.selection(), self.editor(), self.is_editing() let editor = self.editor();
) let editing = self.is_editing();
draw(move |to: &mut Tui|{
for (index, scene, ..) in self.scenes_with_sizes() {
view_scene_name(select, editor, index, scene, editing).draw(to)?;
} }
Ok(Some(XYWH(1, 1, 1, 1)))
})
.exact_w(20)
}
fn scenes_with_sizes (&self) -> impl ScenesSizes<'_> { fn scenes_with_sizes (&self) -> impl ScenesSizes<'_> {
let mut y = 0; let mut y = 0;
self.scenes().iter().enumerate().skip(self.scene_scroll()).map_while(move|(s, scene)|{ self.scenes().iter().enumerate().skip(self.scene_scroll()).map_while(move|(s, scene)|{
@ -733,23 +741,84 @@ pub trait HasTrackScroll: HasTracks {
pub trait TracksView: ScenesView + HasMidiIns + HasMidiOuts + HasTrackScroll { pub trait TracksView: ScenesView + HasMidiIns + HasMidiOuts + HasTrackScroll {
/// Draw name of each track /// Draw name of each track
fn view_track_names (&self, theme: ItemTheme) -> impl Draw<Tui> { fn view_track_names (&self, theme: ItemTheme) -> impl Draw<Tui> {
view_track_names( let track_count = self.tracks().len();
theme, self.tracks_with_sizes(), self.tracks().len(), self.scenes().len(), self.selection() let scene_count = self.scenes().len();
) let selected = self.selection();
let button = south(
button_3("t", "rack ", format!("{}{track_count}", selected.track()
.map(|track|format!("{track}/")).unwrap_or_default()), false),
button_3("s", "cene ", format!("{}{scene_count}", selected.scene()
.map(|scene|format!("{scene}/")).unwrap_or_default()), false));
let button_2 = south(
button_2("T", "+", false),
button_2("S", "+", false));
view_track_row_section(theme, button, button_2, bg(theme.darker.term,
draw(|to: &mut Tui|{
for (index, track, x1, _x2) in self.tracks_with_sizes() {
let b = if selected.track() == Some(index) {
track.color.light.term
} else {
track.color.base.term
};
bg(b, south(east(
format!("·t{index:02} "),
fg(Rgb(255, 255, 255), bold(true, &track.name))
).align_nw().full_w(), ""))
.exact_w(track_width(index, track))
.push_x(x1 as u16)
.draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
}).exact_h(2)))
} }
/// Draw outputs per track /// Draw outputs per track
fn view_track_outputs <'a> (&'a self, theme: ItemTheme, _h: u16) -> impl Draw<Tui> { fn view_track_outputs <'a> (&'a self, theme: ItemTheme, _h: u16) -> impl Draw<Tui> {
view_track_outputs( view_track_row_section(theme,
theme, self.tracks_with_sizes(), self.midi_outs().iter() south(button_2("o", "utput", false).align_w().full_w(),
) draw(|to: &mut Tui|{
for port in self.midi_outs().iter() {
let _ = port.port_name().align_w().full_w().draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
})),
button_2("O", "+", false),
bg(theme.darker.term, draw(|to: &mut Tui|{
for (index, track, _x1, _x2) in self.tracks_with_sizes() {
let f = Rgb(255, 255, 255);
let b = track.color.dark.term;
let iter = ||track.sequencer.midi_outs.iter();
let draw = |port: &MidiOutput, _|fg(f, bg(b,
format!("·o{index:02} {}", port.port_name()).full_w().align_w()).exact_h(1));
iter_south(iter, draw).full_h().align_nw()
.exact_w(track_width(index, track))
.draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
}).align_w()))
} }
/// Draw inputs per track /// Draw inputs per track
fn view_track_inputs <'a> (&'a self, theme: ItemTheme) -> impl Draw<Tui> { fn view_track_inputs <'a> (&'a self, theme: ItemTheme) -> impl Draw<Tui> {
let mut h = 0u16; let mut height = 0u16;
for track in self.tracks().iter() { for track in self.tracks().iter() {
h = h.max(track.sequencer.midi_ins.len() as u16); height = height.max(track.sequencer.midi_ins.len() as u16);
} }
view_track_inputs(theme, self.tracks_with_sizes(), h) view_track_row_section(theme, button_2("i", "nput", false), button_2("I", "+", false),
bg(theme.darker.term, draw(move|to: &mut Tui|{
for (index, track, _x1, _x2) in self.tracks_with_sizes() {
south(
bg(track.color.base.term,
east!(
either(track.sequencer.monitoring, fg(Green, "●mon "), "·mon "),
either(track.sequencer.recording, fg(Red, "●rec "), "·rec "),
either(track.sequencer.overdub, fg(Yellow, "●dub "), "·dub "),
).align_w().full_w()),
iter_south(||track.sequencer.midi_ins.iter(),
|port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term,
format!("·i{index:02} {}", port.port_name()).align_w().full_w()))
).align_nw().exact_wh(track_width(index, track), height + 1).draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
}).align_w()))
} }
/// Iterate over tracks with their corresponding sizes. /// Iterate over tracks with their corresponding sizes.
fn tracks_with_sizes (&self) -> impl TracksSizes<'_> { fn tracks_with_sizes (&self) -> impl TracksSizes<'_> {
@ -801,21 +870,102 @@ impl_as_mut!(Vec<Track>: |self: App| self.project.as_mut());
impl Arrangement { impl Arrangement {
pub fn view_inputs (&self, _theme: ItemTheme) -> impl Draw<Tui> + '_ { pub fn view_inputs (&self, _theme: ItemTheme) -> impl Draw<Tui> + '_ {
view_inputs( let title_1 = button_3("i", "nput ", format!("{}", self.midi_ins().len()), false).align_w().exact_wh(20, 1);
self.tracks_with_sizes(), self.midi_ins().as_slice() let title_2 = button_2("I", "+", false).exact_wh(4, 1);
east(title_1, west(title_2, draw(move|to: &mut Tui|{
for (_index, track, x1, _x2) in self.tracks_with_sizes() {
let _ = south(
bg(track.color.dark.term, east!(
either(track.sequencer.monitoring, fg(Green, "mon "), "mon "),
either(track.sequencer.recording, fg(Red, "rec "), "rec "),
either(track.sequencer.overdub, fg(Yellow, "dub "), "dub "),
).exact_w(track.width as u16)).align_w().push_x(x1 as u16),
draw(move |to: &mut Tui|{
for (index, port) in self.midi_ins().as_slice().iter().enumerate() {
let _ = east(
east(
"",
bold(true, fg(Rgb(255,255,255), port.port_name()))
).align_w().exact_w(20),
west(
().exact_w(4),
bg(track.color.darker.term, east!(
either(track.sequencer.monitoring, fg(Green, ""), " · "),
either(track.sequencer.recording, fg(Red, ""), " · "),
either(track.sequencer.overdub, fg(Yellow, ""), " · "),
).exact_w(track.width as u16).align_w())
) )
).push_x(index as u16 * 10).exact_h(1).draw(to)?;
}
todo!()
})
).draw(to)?;
}
Ok(Some(to.area()))
})))
} }
pub fn view_outputs (&self, theme: ItemTheme) -> impl Draw<Tui> { pub fn view_outputs (&self, theme: ItemTheme) -> impl Draw<Tui> {
view_outputs( let height = self.outputs_height();
theme, self.tracks_with_sizes(), self.midi_outs(), self.outputs_height() let list = south(
) button_3(
"o", "utput", format!("{}", self.midi_outs().len()), false
).align_w().full_w().exact_h(1),
draw(|to: &mut Tui|{
for (_index, port) in self.midi_outs().iter().enumerate() {
east(
east("", fg(Rgb(255,255,255), bold(true, port.port_name()))).align_w(),
format!("{}/{} ",
port.port().get_connections().len(),
port.connections.len()).align_e().full_w().exact_h(1)).full_w().draw(to)?;
for (index, conn) in port.connections.iter().enumerate() {
format!(" c{index:02}{}", conn.info()).align_w().full_w().exact_h(1).draw(to)?;
}
}
todo!();
}).align_nw().full_wh().exact_h(height - 1)
);
view_track_row_section(theme, list, button_2("O", "+", false),
bg(theme.darker.term, draw(|to: &mut Tui|{
for (index, track, _x1, _x2) in self.tracks_with_sizes() {
let _ = draw(|to: &mut Tui|{
east(
either(true, fg(Green, "play "), "play "),
either(false, fg(Yellow, "solo "), "solo "),
).align_w().exact_h(1).draw(to)?;
for (_index, port) in self.midi_outs().iter().enumerate() {
east(
either(true, fg(Green, ""), " · "),
either(false, fg(Yellow, ""), " · "),
).align_w().exact_h(1).draw(to)?;
for (_index, _conn) in port.connections.iter().enumerate() {
"".full_w().exact_h(1).draw(to)?;
}
}
todo!()
}).exact_w(track_width(index, track)).draw(to)?;
}
todo!()
}).align_w().full_w())).exact_h(height)
} }
pub fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<Tui> { pub fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<Tui> {
view_track_devices( let height = self.devices_height();
theme, self.tracks_with_sizes(), self.track(), self.devices_height() view_track_row_section(theme,
) button_3("d", "evice", format!("{}", self.track().map(|t|t.devices.len()).unwrap_or(0)), false),
button_2("D", "+", false),
iter_once(self.tracks_with_sizes(), move|(_, track, _x1, _x2), index|bg(
track.color.dark.term,
iter_south(move||0..height,
|_, _index|fg_bg(
ItemTheme::G[32].lightest.term,
ItemTheme::G[32].dark.term,
format!(" · {}", "--").align_nw()
).exact_wh(track.width as u16, 2)
).align_nw()).exact_wh(
Some(track_width(index, track)),
Some(height + 1),
)))
} }
fn devices_height (&self) -> u16 { fn devices_height (&self) -> u16 {
@ -898,3 +1048,15 @@ impl HasTrackScroll for App {
pub(crate) fn track_width (_index: usize, track: &Track) -> u16 { pub(crate) fn track_width (_index: usize, track: &Track) -> u16 {
track.width as u16 track.width as u16
} }
/// Define a type alias for iterators of sized items (columns).
macro_rules! def_sizes_iter {
($Type:ident => $($Item:ty),+) => {
pub trait $Type<'a>: Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a {}
impl<'a, T: Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a> $Type<'a> for T {}
}
}
def_sizes_iter!(PortsSizes => Arc<str>, [Connect]);
def_sizes_iter!(ScenesSizes => Scene);
def_sizes_iter!(TracksSizes => Track);

View file

@ -144,6 +144,7 @@ impl PianoHorizontal {
//if h as usize != note_axis { //if h as usize != note_axis {
//panic!("area height mismatch: {h} <> {note_axis}"); //panic!("area height mismatch: {h} <> {note_axis}");
//} //}
if let Tui::Draw(to, ..) = to {
for (area_x, screen_x) in (x0..x0+w).enumerate() { for (area_x, screen_x) in (x0..x0+w).enumerate() {
for (area_y, screen_y, _note) in note_y_iter(note_lo, note_hi, y0) { for (area_y, screen_y, _note) in note_y_iter(note_lo, note_hi, y0) {
let source_x = time_start + area_x; let source_x = time_start + area_x;
@ -155,13 +156,14 @@ impl PianoHorizontal {
let is_in_y = source_y < source.height; let is_in_y = source_y < source.height;
if is_in_x && is_in_y { if is_in_x && is_in_y {
if let Some(source_cell) = source.get(source_x, source_y) { if let Some(source_cell) = source.get(source_x, source_y) {
if let Some(cell) = to.0.cell_mut(ratatui::prelude::Position::from((screen_x, screen_y))) { if let Some(cell) = to.cell_mut(ratatui::prelude::Position::from((screen_x, screen_y))) {
*cell = source_cell.clone(); *cell = source_cell.clone();
} }
} }
} }
} }
} }
}
Ok(Some(xywh)) Ok(Some(xywh))
}) })
} }

View file

@ -279,6 +279,7 @@ fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_
lines.push(Line::new(x, min_db, x, y, Color::Green)); lines.push(Line::new(x, min_db, x, y, Color::Green));
t += step / 2.; t += step / 2.;
} }
if let Tui::Draw(buf, ..) = to {
Canvas::default() Canvas::default()
.x_bounds([sample.start as f64, sample.end as f64]) .x_bounds([sample.start as f64, sample.end as f64])
.y_bounds([min_db, 0.]) .y_bounds([min_db, 0.])
@ -294,8 +295,10 @@ fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_
//text.red() //text.red()
//); //);
}) })
.render(area, to.as_mut()); .render(area, buf);
}
} else { } else {
if let Tui::Draw(buf, ..) = to {
Canvas::default() Canvas::default()
.x_bounds([0.0, width as f64]) .x_bounds([0.0, width as f64])
.y_bounds([0.0, height as f64]) .y_bounds([0.0, height as f64])
@ -307,7 +310,8 @@ fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_
//text.red() //text.red()
//); //);
}) })
.render(area, to.as_mut()); .render(area, buf);
}
} }
Ok(Some(xywh)) Ok(Some(xywh))
}) })

View file

@ -1479,76 +1479,49 @@ mod draw {
impl Keywords<Tui, XYWH<u16>> for App { impl Keywords<Tui, XYWH<u16>> for App {
fn keywords () -> impl Iterator<Item = fn(&Self, &mut Tui, &str) -> Perhaps<XYWH<u16>>> { fn keywords () -> impl Iterator<Item = fn(&Self, &mut Tui, &str) -> Perhaps<XYWH<u16>>> {
[ [kw_when, kw_either, kw_split, kw_align, kw_exact, kw_min, kw_max, kw_push,
kw_when, kw_either, kw_split, kw_align, kw_tui_text, kw_tui_fg, kw_tui_bg]
kw_exact, kw_fixed, kw_min, kw_max, kw_push .into_iter()
].into_iter()
} }
} }
impl Interpret<Tui, Option<XYWH<u16>>> for App { impl Interpret<Tui, Option<XYWH<u16>>> for App {
fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> { fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> {
tek_draw_expr(self, to, lang) self.keyword(to, lang)
} }
fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> { fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> {
tek_draw_word(self, to, lang) let mut frags = lang.src()?.unwrap().split("/");
}
}
fn tek_draw_expr (state: &App, to: &mut Tui, lang: &impl Expression) -> Drawn<u16> {
Ok(Some(if let Some(area) = eval_view(state, to, lang)? {
area
} else if let Some(area) = Tui::eval_view(state, to, lang)? {
area
} else {
return Err(format!("App::interpret_expr: unexpected: {lang:?}").into())
}))
}
fn tek_draw_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Drawn<u16> {
let mut frags = dsl.src()?.unwrap().split("/");
match frags.next() { match frags.next() {
//Some(":logo") => view_logo().draw(to), //Some(":logo") => view_logo().draw(to),
Some(":meters") => draw_meter_section(to, frags), Some(":meters") => draw_meter_section(to, frags),
Some(":tracks") => draw_tracks(to, frags, state), Some(":tracks") => draw_tracks(to, frags, self),
Some(":scenes") => draw_scenes(to, frags), Some(":scenes") => draw_scenes(to, frags),
Some(":dialog") => draw_dialog(to, frags, state, dsl), Some(":dialog") => draw_dialog(to, frags, self, lang),
Some(":templates") => draw_templates(to, frags, state), Some(":templates") => draw_templates(to, frags, self),
Some(":sessions") => view_sessions().draw(to), Some(":sessions") => view_sessions().draw(to),
Some(":browse/title") => view_browse_title(state).draw(to), Some(":browse/title") => view_browse_title(self).draw(to),
Some(":device") => view_device(state).draw(to), Some(":device") => view_device(self).draw(to),
Some(":status") => "TODO: Status Bar".exact_h(1).draw(to), Some(":status") => "TODO: Status Bar".exact_h(1).draw(to),
Some(":editor") => "TODO Editor".draw(to), Some(":editor") => "TODO Editor".draw(to),
Some(":transport") => view_transport(true, "", "", "").draw(to), Some(":transport") => view_transport(true, "", "", "").draw(to),
Some(":debug") => format!("[{:?}]", to.area()).exact_h(1).draw(to), Some(":debug") => format!("[{:?}]", to.area()).exact_h(1).draw(to),
Some(_) => { Some(_) => {
let views = state.config.views.read().unwrap(); let views = self.config.views.read().unwrap();
if let Some(dsl) = views.get(dsl.src()?.unwrap()) { if let Some(lang) = views.get(lang.src()?.unwrap()) {
let dsl = dsl.clone(); let lang = lang.clone();
std::mem::drop(views); std::mem::drop(views);
state.interpret(to, &dsl) self.interpret(to, &lang)
} else { } else {
unimplemented!("{dsl:?}"); unimplemented!("{lang:?}");
} }
}, },
_ => unreachable!() _ => unreachable!()
} }
} }
}
impl_has!(Sizer: |self: App|self.size); impl_has!(Sizer: |self: App|self.size);
/// Define a type alias for iterators of sized items (columns).
macro_rules! def_sizes_iter {
($Type:ident => $($Item:ty),+) => {
pub trait $Type<'a>: Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a {}
impl<'a, T: Iterator<Item=(usize, $(&'a $Item,)+ usize, usize)> + Send + Sync + 'a> $Type<'a> for T {}
}
}
def_sizes_iter!(PortsSizes => Arc<str>, [Connect]);
def_sizes_iter!(ScenesSizes => Scene);
def_sizes_iter!(TracksSizes => Track);
pub trait HasWidth { pub trait HasWidth {
const MIN_WIDTH: usize; const MIN_WIDTH: usize;
/// Increment track width. /// Increment track width.
@ -1967,106 +1940,6 @@ mod draw {
} }
} }
pub fn view_track_names <'a> (
theme: ItemTheme,
tracks: impl TracksSizes<'a>,
track_count: usize,
scene_count: usize,
selected: &Selection,
) -> impl Draw<Tui> {
let button = south(
button_3("t", "rack ", format!("{}{track_count}", selected.track()
.map(|track|format!("{track}/")).unwrap_or_default()), false),
button_3("s", "cene ", format!("{}{scene_count}", selected.scene()
.map(|scene|format!("{scene}/")).unwrap_or_default()), false));
let button_2 = south(
button_2("T", "+", false),
button_2("S", "+", false));
view_track_row_section(theme, button, button_2, bg(theme.darker.term,
draw(|to: &mut Tui|{
for (index, track, x1, _x2) in tracks {
let b = if selected.track() == Some(index) {
track.color.light.term
} else {
track.color.base.term
};
bg(b, south(east(
format!("·t{index:02} "),
fg(Rgb(255, 255, 255), bold(true, &track.name))
).align_nw().full_w(), ""))
.exact_w(track_width(index, track))
.push_x(x1 as u16)
.draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
}).exact_h(2)))
}
pub fn view_track_outputs <'a> (
theme: ItemTheme,
tracks: impl TracksSizes<'a>,
midi_outs: impl Iterator<Item = &'a MidiOutput>,
) -> impl Draw<Tui> {
view_track_row_section(theme,
south(button_2("o", "utput", false).align_w().full_w(),
draw(|to: &mut Tui|{
for port in midi_outs {
let _ = port.port_name().align_w().full_w().draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
})),
button_2("O", "+", false),
bg(theme.darker.term, draw(|to: &mut Tui|{
for (index, track, _x1, _x2) in tracks {
let f = Rgb(255, 255, 255);
let b = track.color.dark.term;
let iter = ||track.sequencer.midi_outs.iter();
let draw = |port: &MidiOutput, _|fg(f, bg(b,
format!("·o{index:02} {}", port.port_name()).full_w().align_w()).exact_h(1));
iter_south(iter, draw).full_h().align_nw()
.exact_w(track_width(index, track))
.draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
}).align_w()))
}
pub fn view_track_inputs <'a> (
theme: ItemTheme, tracks: impl TracksSizes<'a>, height: u16,
) -> impl Draw<Tui> {
view_track_row_section(theme, button_2("i", "nput", false), button_2("I", "+", false),
bg(theme.darker.term, draw(move|to: &mut Tui|{
for (index, track, _x1, _x2) in tracks {
south(
bg(track.color.base.term,
east!(
either(track.sequencer.monitoring, fg(Green, "●mon "), "·mon "),
either(track.sequencer.recording, fg(Red, "●rec "), "·rec "),
either(track.sequencer.overdub, fg(Yellow, "●dub "), "·dub "),
).align_w().full_w()),
iter_south(||track.sequencer.midi_ins.iter(),
|port, _|fg_bg(Rgb(255, 255, 255), track.color.dark.term,
format!("·i{index:02} {}", port.port_name()).align_w().full_w()))
).align_nw().exact_wh(track_width(index, track), height + 1).draw(to)?;
}
Ok(Some(XYWH(0, 0, 0, 0)))
}).align_w()))
}
pub fn view_scenes_names <'a> (
scenes: impl ScenesSizes<'a>,
select: &Selection,
editor: Option<&MidiEditor>,
editing: bool,
) -> impl Draw<Tui> {
draw(move |to: &mut Tui|{
for (index, scene, ..) in scenes {
view_scene_name(select, editor, index, scene, editing).draw(to)?;
}
Ok(Some(XYWH(1, 1, 1, 1)))
}).exact_w(20)
}
pub fn view_scene_name ( pub fn view_scene_name (
select: &Selection, select: &Selection,
editor: Option<&MidiEditor>, editor: Option<&MidiEditor>,
@ -2121,119 +1994,4 @@ mod draw {
}) })
} }
pub fn view_per_track () -> impl Draw<Tui> {}
pub fn view_per_track_top () -> impl Draw<Tui> {}
pub fn view_inputs <'a> (
tracks: impl TracksSizes<'a>, midi_ins: &[MidiInput]
) -> impl Draw<Tui> {
let title_1 = button_3("i", "nput ", format!("{}", midi_ins.len()), false).align_w().exact_wh(20, 1);
let title_2 = button_2("I", "+", false).exact_wh(4, 1);
east(title_1, west(title_2, draw(move|to: &mut Tui|{
for (_index, track, x1, _x2) in tracks {
let _ = south(
bg(track.color.dark.term, east!(
either(track.sequencer.monitoring, fg(Green, "mon "), "mon "),
either(track.sequencer.recording, fg(Red, "rec "), "rec "),
either(track.sequencer.overdub, fg(Yellow, "dub "), "dub "),
).exact_w(track.width as u16)).align_w().push_x(x1 as u16),
draw(move |to: &mut Tui|{
for (index, port) in midi_ins.iter().enumerate() {
let _ = east(
east(
"",
bold(true, fg(Rgb(255,255,255), port.port_name()))
).align_w().exact_w(20),
west(
().exact_w(4),
bg(track.color.darker.term, east!(
either(track.sequencer.monitoring, fg(Green, ""), " · "),
either(track.sequencer.recording, fg(Red, ""), " · "),
either(track.sequencer.overdub, fg(Yellow, ""), " · "),
).exact_w(track.width as u16).align_w())
)
).push_x(index as u16 * 10).exact_h(1).draw(to)?;
}
todo!()
})
).draw(to)?;
}
todo!()
})))
}
pub fn view_outputs <'a> (
theme: ItemTheme,
tracks: impl TracksSizes<'a>,
midi_outs: &[MidiOutput],
height: u16,
) -> impl Draw<Tui> {
let list = south(
button_3(
"o", "utput", format!("{}", midi_outs.len()), false
).align_w().full_w().exact_h(1),
draw(|to: &mut Tui|{
for (_index, port) in midi_outs.iter().enumerate() {
east(
east("", fg(Rgb(255,255,255), bold(true, port.port_name()))).align_w(),
format!("{}/{} ",
port.port().get_connections().len(),
port.connections.len()).align_e().full_w().exact_h(1)).full_w().draw(to)?;
for (index, conn) in port.connections.iter().enumerate() {
format!(" c{index:02}{}", conn.info()).align_w().full_w().exact_h(1).draw(to)?;
}
}
todo!();
}).align_nw().full_wh().exact_h(height - 1)
);
view_track_row_section(theme, list, button_2("O", "+", false),
bg(theme.darker.term, draw(|to: &mut Tui|{
for (index, track, _x1, _x2) in tracks {
let _ = draw(|to: &mut Tui|{
east(
either(true, fg(Green, "play "), "play "),
either(false, fg(Yellow, "solo "), "solo "),
).align_w().exact_h(1).draw(to)?;
for (_index, port) in midi_outs.iter().enumerate() {
east(
either(true, fg(Green, ""), " · "),
either(false, fg(Yellow, ""), " · "),
).align_w().exact_h(1).draw(to)?;
for (_index, _conn) in port.connections.iter().enumerate() {
"".full_w().exact_h(1).draw(to)?;
}
}
todo!()
}).exact_w(track_width(index, track)).draw(to)?;
}
todo!()
}).align_w().full_w())).exact_h(height)
}
pub fn view_track_devices <'a> (
theme: ItemTheme,
tracks: impl TracksSizes<'a>,
track: Option<&Track>,
h: u16,
) -> impl Draw<Tui> {
view_track_row_section(theme,
button_3("d", "evice", format!("{}", track.map(|t|t.devices.len()).unwrap_or(0)), false),
button_2("D", "+", false),
iter_once(tracks, move|(_, track, _x1, _x2), index|bg(
track.color.dark.term,
iter_south(move||0..h,
|_, _index|fg_bg(
ItemTheme::G[32].lightest.term,
ItemTheme::G[32].dark.term,
format!(" · {}", "--").align_nw()
).exact_wh(track.width as u16, 2)
).align_nw()).exact_wh(
Some(track_width(index, track)),
Some(h + 1),
)))
}
} }

2
tengri

@ -1 +1 @@
Subproject commit eb028c85fc94a1b86c44d4f079e5fb91667d4db2 Subproject commit ac9fd7dfba24335d09793a55d94ea54039253f62