This commit is contained in:
i do not exist 2026-06-20 21:54:31 +03:00
parent b130471f12
commit 4ec2165e3d
2 changed files with 39 additions and 19 deletions

View file

@ -184,9 +184,9 @@ pub trait ClipsView: TracksView + ScenesView {
pub trait TracksView: ScenesView + HasMidiIns + HasMidiOuts + HasTrackScroll { pub trait TracksView: ScenesView + HasMidiIns + HasMidiOuts + HasTrackScroll {
fn tracks_width_available (&self) -> u16 { //fn tracks_width_available (&self) -> u16 {
(self.size.width() as u16).saturating_sub(40) //(self.size.width() as u16).saturating_sub(40)
} //}
/// 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<'_> {
@ -854,7 +854,7 @@ impl ScenesView for Arrangement {
(self.size.w() as u16 * 2 / 10).max(20) (self.size.w() as u16 * 2 / 10).max(20)
} }
fn w_mid (&self) -> u16 { fn w_mid (&self) -> u16 {
(self.size.width() as u16).saturating_sub(2 * self.w_side()).max(40) (self.size.w() as u16).saturating_sub(2 * self.w_side()).max(40)
} }
} }
impl HasClipsSize for Arrangement { impl HasClipsSize for Arrangement {

View file

@ -547,16 +547,13 @@ pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, po
pub fn io_ports <'a, T: PortsSizes<'a>> ( pub fn io_ports <'a, T: PortsSizes<'a>> (
fg: Color, bg: Color, items: impl Fn()->T + Send + Sync + 'a fg: Color, bg: Color, items: impl Fn()->T + Send + Sync + 'a
) -> impl Draw<Tui> + 'a { ) -> impl Draw<Tui> + 'a {
iter(items, move|( type Item<'a> = (usize, &'a Arc<str>, &'a [Connect], usize, usize);
_index, name, connections, y, y2 iter(items, move|(_index, name, connections, y, y2): Item<'a>, _| {
): (usize, &'a Arc<str>, &'a [Connect], usize, usize), _| { y_push(y as u16, h_exact((y2-y) as u16,
let conns = ||connections.iter();
let conn = move|connect: &'a Connect, index|iter_south_fixed(
index as u16, 1, h_full(origin_w(bold(false, fg_bg(fg, bg, &connect.info))))
);
iter_south(y as u16, (y2-y) as u16,
south(h_full(bold(true, fg_bg(fg, bg, origin_w(east(" 󰣲 ", name))))), south(h_full(bold(true, fg_bg(fg, bg, origin_w(east(" 󰣲 ", name))))),
iter(conns, conn))) iter(||connections.iter(), move|connect: &'a Connect, index|y_push(
index as u16, h_exact(1, origin_w(bold(false, fg_bg(fg, bg, &connect.info))))
)))))
}) })
} }
@ -732,13 +729,17 @@ fn app_interpret_expr (state: &App, to: &mut Tui, lang: &impl Expression) -> Usu
fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usually<()> { fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usually<()> {
let mut frags = dsl.src()?.unwrap().split("/"); 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(":status") => h_exact(1, "TODO: Status Bar").draw(to), Some(":status") => h_exact(1, "TODO: Status Bar").draw(to),
Some(":meters") => match frags.next() { Some(":meters") => match frags.next() {
Some("input") => bg(Rgb(30, 30, 30), h_full(origin_s("Input Meters"))).draw(to), Some("input") => bg(Rgb(30, 30, 30), h_full(origin_s("Input Meters"))).draw(to),
Some("output") => bg(Rgb(30, 30, 30), h_full(origin_s("Output Meters"))).draw(to), Some("output") => bg(Rgb(30, 30, 30), h_full(origin_s("Output Meters"))).draw(to),
_ => panic!() _ => panic!()
}, },
Some(":tracks") => match frags.next() { Some(":tracks") => match frags.next() {
None => "TODO tracks".draw(to), None => "TODO tracks".draw(to),
Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), w_full(origin_w("Track Names")))), Some("names") => state.project.view_track_names(state.color.clone()).draw(to),//bg(Rgb(40, 40, 40), w_full(origin_w("Track Names")))),
@ -747,12 +748,15 @@ fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usua
Some("outputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Outputs"))).draw(to), Some("outputs") => bg(Rgb(40, 40, 40), w_full(origin_w("Track Outputs"))).draw(to),
_ => panic!() _ => panic!()
}, },
Some(":scenes") => match frags.next() { Some(":scenes") => match frags.next() {
None => "TODO scenes".draw(to), None => "TODO scenes".draw(to),
Some(":scenes/names") => "TODO Scene Names".draw(to), Some(":scenes/names") => "TODO Scene Names".draw(to),
_ => panic!() _ => panic!()
}, },
Some(":editor") => "TODO Editor".draw(to), Some(":editor") => "TODO Editor".draw(to),
Some(":dialog") => match frags.next() { Some(":dialog") => match frags.next() {
Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog { Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog {
let items = items.clone(); let items = items.clone();
@ -772,6 +776,7 @@ fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usua
}.draw(to), }.draw(to),
_ => unimplemented!("App::interpret_word: {dsl:?} ({frags:?})"), _ => unimplemented!("App::interpret_word: {dsl:?} ({frags:?})"),
}, },
Some(":templates") => { Some(":templates") => {
let modes = state.config.modes.clone(); let modes = state.config.modes.clone();
let height = (modes.read().unwrap().len() * 2) as u16; let height = (modes.read().unwrap().len() * 2) as u16;
@ -791,7 +796,8 @@ fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usua
} }
}))) })))
}.draw(to), }.draw(to),
Some(":sessions") => h_exact(Some(6), w_min(Some(30), thunk(|to: &mut Tui|{
Some(":sessions") => h_exact(Some(6), w_min(30, thunk(|to: &mut Tui|{
let fg = Rgb(224, 192, 128); let fg = Rgb(224, 192, 128);
for (index, name) in ["session1", "session2", "session3"].iter().enumerate() { for (index, name) in ["session1", "session2", "session3"].iter().enumerate() {
let bg = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) }; let bg = if index == 0 { Rgb(50,50,50) } else { Rgb(40,40,40) };
@ -799,6 +805,7 @@ fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usua
&h_exact(2, w_full(bg(bg, origin_w(fg(fg, name)))))).draw(to); &h_exact(2, w_full(bg(bg, origin_w(fg(fg, name)))))).draw(to);
} }
}))).draw(to), }))).draw(to),
Some(":browse/title") => w_full(origin_w(field_v(ItemColor::default(), Some(":browse/title") => w_full(origin_w(field_v(ItemColor::default(),
match state.dialog.browser_target().unwrap() { match state.dialog.browser_target().unwrap() {
BrowseTarget::SaveProject => "Save project:", BrowseTarget::SaveProject => "Save project:",
@ -808,17 +815,20 @@ fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usua
BrowseTarget::ImportClip(_) => "Import clip:", BrowseTarget::ImportClip(_) => "Import clip:",
BrowseTarget::ExportClip(_) => "Export clip:", BrowseTarget::ExportClip(_) => "Export clip:",
}, w_shrink(3, h_exact(1, fg(g(96), x_repeat("🭻"))))))).draw(to), }, w_shrink(3, h_exact(1, fg(g(96), x_repeat("🭻"))))))).draw(to),
Some(":device") => { Some(":device") => {
let selected = state.dialog.device_kind().unwrap(); let selected = state.dialog.device_kind().unwrap();
south(bold(true, "Add device"), iter_south( south(bold(true, "Add device"), iter_south(
move||device_kinds().iter(), move||device_kinds().iter(),
move|_label: &&'static str, i|{ move|_label: &&'static str, i|{
let bg = if i == selected { Rgb(64,128,32) } else { Rgb(0,0,0) }; let b = if i == selected { Rgb(64,128,32) } else { Rgb(0,0,0) };
let lb = if i == selected { "[ " } else { " " }; let l = if i == selected { "[ " } else { " " };
let rb = if i == selected { " ]" } else { " " }; let r = if i == selected { " ]" } else { " " };
w_full(bg(bg, east(lb, west(rb, "FIXME device name")))) })).draw(to) w_full(bg(b, east(l, west(r, "FIXME device name")))) })).draw(to)
}, },
Some(":debug") => h_exact(1, format!("[{:?}]", to.area())).draw(to), Some(":debug") => h_exact(1, format!("[{:?}]", to.area())).draw(to),
Some(_) => { Some(_) => {
let views = state.config.views.read().unwrap(); let views = state.config.views.read().unwrap();
if let Some(dsl) = views.get(dsl.src()?.unwrap()) { if let Some(dsl) = views.get(dsl.src()?.unwrap()) {
@ -829,6 +839,7 @@ fn app_interpret_word (state: &App, to: &mut Tui, dsl: &impl Expression) -> Usua
unimplemented!("{dsl:?}"); unimplemented!("{dsl:?}");
} }
}, },
_ => unreachable!() _ => unreachable!()
} }
Ok(()) Ok(())
@ -953,10 +964,17 @@ impl App {
} }
} }
} }
/// The [Draw] implementation for [App] handles the loaded view,
/// which is defined in terms of [dizzle] DSL.
///
/// If there is an error, the error is displayed. FIXME: overlay it
/// Then, every top-level form of the DSL description is rendered.
impl Draw<Tui> for App { impl Draw<Tui> for App {
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> { fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
let xywh = to.area().into();
if let Some(e) = self.error.read().unwrap().as_ref() { if let Some(e) = self.error.read().unwrap().as_ref() {
to.show(to.area().into(), e.as_ref()); to.show(xywh, e.as_ref());
} }
for (index, dsl) in self.mode.view.iter().enumerate() { for (index, dsl) in self.mode.view.iter().enumerate() {
if let Err(e) = self.interpret(to, dsl) { if let Err(e) = self.interpret(to, dsl) {
@ -964,8 +982,10 @@ impl Draw<Tui> for App {
break; break;
} }
} }
Ok(xywh)
} }
} }
impl HasClipsSize for App { fn clips_size (&self) -> &Size { &self.project.size_inner } } impl HasClipsSize for App { fn clips_size (&self) -> &Size { &self.project.size_inner } }
impl HasJack<'static> for App { fn jack (&self) -> &Jack<'static> { &self.jack } } impl HasJack<'static> for App { fn jack (&self) -> &Jack<'static> { &self.jack } }
impl_default!(AppCommand: Self::Nop); impl_default!(AppCommand: Self::Nop);