From cdbcea0a8f7a09f141c07c71a61411649f44df35 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 25 Jan 2025 22:53:18 +0100 Subject: [PATCH] further reducing whatever is causing the wrong centering along 1 axis anyway, along the other i just saw it increase --- tek/src/view.rs | 239 ++--------------------------------------- tek/src/view/clip.rs | 112 +++++++++++++++++++ tek/src/view/input.rs | 42 ++++++++ tek/src/view/output.rs | 43 ++++++++ 4 files changed, 208 insertions(+), 228 deletions(-) create mode 100644 tek/src/view/clip.rs create mode 100644 tek/src/view/input.rs create mode 100644 tek/src/view/output.rs diff --git a/tek/src/view.rs b/tek/src/view.rs index cb8f9cc0..2f74c11a 100644 --- a/tek/src/view.rs +++ b/tek/src/view.rs @@ -1,5 +1,8 @@ use crate::*; -use std::fmt::Write; +pub(crate) use std::fmt::Write; +mod clip; pub use self::clip::*; +mod input; pub use self::input::*; +mod output; pub use self::output::*; macro_rules! def_sizes_iter { ($Type:ident => $($Item:ty),+) => { trait $Type<'a> = Iterator + Send + Sync + 'a; @@ -79,7 +82,7 @@ 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 }, }); -macro_rules! rewrite { +#[macro_export] macro_rules! rewrite { ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{$buf.clear();write!($buf, $($rest)*)} } } impl Tek { fn update_clock (&self) { @@ -175,18 +178,7 @@ impl Tek { .map(|pool|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), pool))) } } -macro_rules! per_track { - ($area:expr;|$self:ident,$track:ident,$index:ident|$content:expr) => {{ - let tracks = ||$self.tracks_sizes($self.is_editing(), $self.editor_w()) - .map_while(|(t, track, x1, x2)|if x2 >= $area { - None } else { Some((t, track, x1, x2)) }); - Box::new(move||Align::x(Map::new(tracks, move|(_, $track, x1, x2), $index| { - let width = (x2 - x1) as u16; - let content = Fixed::y(1, $content); - let styled = Tui::fg_bg($track.color.lightest.rgb, $track.color.base.rgb, content); - map_east(x1 as u16, width, Align::y(Fixed::x(width, styled))) }))).into() }} } impl Tek { - // SIZES ////////////////////////////////////////////////////////////////////////////////////// fn w (&self) -> u16 { self.size.w() as u16 } fn h (&self) -> u16 { self.size.h() as u16 } @@ -205,7 +197,6 @@ impl Tek { fn h_scenes (&self, editing: bool, height: usize, larger: usize) -> u16 { self.scenes_sizes(editing, height, larger).last().map(|(_, _, _, y)|y as u16).unwrap_or(0) } - // THINGS WITH SIZES ////////////////////////////////////////////////////////////////////////// const TRACK_SPACING: usize = 0; fn tracks_sizes <'a> (&'a self, editing: bool, bigger: usize) -> impl TracksSizes<'a> { @@ -254,42 +245,41 @@ impl Tek { data }) } - /// COMPONENTS //////////////////////////////////////////////////////////////////////////////// fn row <'a> ( &'a self, w: u16, h: u16, a: impl Content + 'a, b: impl Content + 'a ) -> impl Content + 'a { Fixed::y(h, Bsp::a( Fill::xy(Align::w(Fixed::x(self.w_sidebar() as u16, a))), - Fill::xy(Align::c(Fixed::x(w, b)))))} + Fill::xy(Align::c(Fixed::x(w, Align::x(b))))))} fn row_top <'a> ( &'a self, w: u16, h: u16, a: impl Content + 'a, b: impl Content + 'a ) -> impl Content + 'a { Fixed::y(h, Bsp::a( Fill::xy(Align::nw(Fixed::xy(self.w_sidebar() as u16, h, a))), - Fill::xy(Align::n(Fixed::xy(w, h, b)))))} + Fill::xy(Align::n(Fixed::xy(w, h, Align::x(b))))))} fn per_track <'a, T: Content + 'a> ( &'a self, f: impl Fn(usize, &'a Track)->T + Send + Sync + 'a ) -> impl Content + 'a { let width = self.size.w(); let filter = move|(t, track, x1, x2)|if x2 >= width {None} else {Some((t, track, x1, x2))}; let tracks = move||self.tracks_sizes(self.is_editing(), self.editor_w()).map_while(filter); - Map::new(tracks, move|(index, track, x1, x2), _|{ + Align::x(Tui::bg(Yellow, Map::new(tracks, move|(index, track, x1, x2), _|{ let width = (x2 - x1) as u16; let content = Fixed::y(1, f(index, track)); let styled = Tui::fg_bg(track.color.lightest.rgb, track.color.base.rgb, content); - map_east(x1 as u16, width, Align::y(Fixed::x(width, styled))) }) } + map_east(x1 as u16, width, Align::y(Fixed::x(width, styled))) }))) } fn per_track_top <'a, T: Content + 'a> ( &'a self, f: impl Fn(usize, &'a Track)->T + Send + Sync + 'a ) -> impl Content + 'a { let width = self.size.w(); let filter = move|(t, track, x1, x2)|if x2 >= width {None} else {Some((t, track, x1, x2))}; let tracks = move||self.tracks_sizes(self.is_editing(), self.editor_w()).map_while(filter); - Map::new(tracks, move|(index, track, x1, x2), _|{ + Align::x(Tui::bg(Green, Map::new(tracks, move|(index, track, x1, x2), _|{ let width = (x2 - x1) as u16; let content = Fixed::y(1, f(index, track)); let styled = Tui::fg_bg(track.color.lightest.rgb, track.color.base.rgb, content); - map_east(x1 as u16, width, Fixed::x(width, styled)) }) } + map_east(x1 as u16, width, Fixed::x(width, styled)) }))) } fn io_ports <'a, T: PortsSizes<'a>> ( &'a self, fg: Color, bg: Color, iter: impl Fn()->T + Send + Sync + 'a ) -> impl Content + 'a { @@ -341,211 +331,4 @@ impl Tek { fn wrap (bg: Color, fg: Color, content: impl Content) -> impl Content { Bsp::e(Tui::fg_bg(bg, Reset, "▐"), Bsp::w(Tui::fg_bg(bg, Reset, "▌"), Tui::fg_bg(fg, bg, content))) } - - // TRACKS ///////////////////////////////////////////////////////////////////////////////////// - fn view_tracks (&self) -> impl Content + use<'_> { - self.row(self.w(), 3, Tui::bg(Tui::g(32), Fill::x(Align::w({ - let data = (self.selected.track().unwrap_or(0), self.tracks().len()); - self.fmtd.write().unwrap().trks.update(Some(data), - rewrite!(buf, "({}/{})", data.0, data.1)); - Bsp::e( - self.button3(" t", "track", self.fmtd.read().unwrap().trks.view.clone()), - self.button2(" T", "add track"), - ) - }))), self.per_track(|t, track|{ - let active = self.selected().track() == Some(t+1); - 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) }; - Self::wrap(bg, fg, Tui::bold(true, Fill::x(Align::nw(name)))) - })) - } - - // ACTIVE CLIPS /////////////////////////////////////////////////////////////////////////////// - fn view_clips_into (&self) -> impl Content + use<'_> { - let heading = Align::e("Into:"); - let content = self.per_track_top(|_, _|Tui::bg(Reset, " --- ")); - self.row_top(self.w(), 1, heading, content) - } - fn view_clips_from (&self) -> impl Content + use<'_> { - let heading = Align::e("From:"); - let content = self.per_track_top(|_, _|Tui::bg(Reset, " --- ")); - self.row_top(self.w(), 1, heading, content) - } - fn view_clips_next (&self) -> impl Content + use<'_> { - let heading = Align::e("Next:"); - let content = self.per_track_top(|_, _|Tui::bg(Reset, " --- ")); - self.row_top(self.w(), 1, heading, content) - } - - // INPUTS ///////////////////////////////////////////////////////////////////////////////////// - fn view_inputs (&self) -> impl Content + use<'_> { - let fg = Tui::g(224); - let key = " i"; - let label = "midi ins"; - let count = self.midi_ins.len(); - Bsp::s( - Bsp::s( - self.row_top(self.w(), 1, - Fill::x(Align::w(Bsp::e( - self.button3(" i", "midi ins", format!("{count}")), - self.button2(" I", "add midi in"), - ))), - self.per_track_top(move|t, track|{ - let rec = track.player.recording; - let mon = track.player.monitoring; - let rec = if rec { White } else { track.color.darkest.rgb }; - let mon = if mon { White } else { track.color.darkest.rgb }; - let bg = if self.selected().track() == Some(t+1) { - track.color.light.rgb - } else { - track.color.base.rgb - }; - let bg2 = if t > 0 { self.tracks()[t - 1].color.base.rgb } else { Reset }; - Self::wrap(bg, fg, Tui::bold(true, Fill::x(Bsp::e( - Tui::fg_bg(rec, bg, "Rec "), - Tui::fg_bg(mon, bg, "Mon ")))))})), - self.row_top(self.w(), self.h_inputs() - 1, - self.io_ports(fg, Tui::g(32), ||self.inputs_sizes()), - self.per_track_top(move|t, track|self.io_connections( - track.color.dark.rgb, - track.color.darker.rgb, - ||self.inputs_sizes() - ))), - ), - self.view_clips_into() - ) - } - - // OUTPUTS //////////////////////////////////////////////////////////////////////////////////// - fn view_outputs (&self) -> impl Content + use<'_> { - let fg = Tui::g(224); - let key = " o"; - let label = "midi outs"; - let count = self.midi_outs.len(); - Align::n(Bsp::s( - Bsp::s( - self.view_clips_next(), - self.view_clips_from(), - ), - Bsp::s( - self.row_top(self.w(), 1, - Fill::x(Align::w(Bsp::e( - self.button3(" o", "midi outs", format!("{count}")), - self.button2(" O", "add midi out"), - ))), - self.per_track_top(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 bg = if self.selected().track() == Some(t+1) { track.color.light.rgb } else { track.color.base.rgb }; - let bg2 = if t > 0 { self.tracks()[t - 1].color.base.rgb } else { Reset }; - Self::wrap(bg, fg, Tui::bold(true, Fill::x(Bsp::e( - Tui::fg_bg(mute, bg, "Play "), - Tui::fg_bg(solo, bg, "Solo ")))))})), - self.row_top(self.w(), self.h_outputs() - 1, - self.io_ports(fg, Tui::g(32), ||self.outputs_sizes()), - self.per_track_top(move|t, track|self.io_connections( - track.color.dark.rgb, track.color.darker.rgb, ||self.outputs_sizes()))), - ) - )) - } - - // SCENES ///////////////////////////////////////////////////////////////////////////////////// - fn view_scenes (&self) -> impl Content + use<'_> { - let w = self.size.w() as u16; - let h = self.size.h() as u16; - let editing = self.is_editing(); - let selected_track = self.selected().track(); - let selected_scene = self.selected().scene(); - self.row(w, h, - Align::y(Map::new( - move||self.scenes_sizes(editing, 2, 15).map_while( - move|(s, scene, y1, y2)|if y2 as u16 > h { - None - } else { Some((s, scene, y1, y2, if s == 0 { - None - } else { - Some(self.scenes[s-1].color) - })) }), - move|(_, scene, y1, y2, prev), s| { - let height = (1 + y2 - y1) as u16; - let bg = scene.color; - let fg = scene.color.lightest.rgb; - let name = Some(scene.name.clone()); - map_south(y1 as u16, height, Fixed::y(height, self.view_clip_cell( - true, s, &bg, prev, name, " ⯈ ", fg))) - })).boxed(), - self.per_track(move|t, track|{ - let same_track = selected_track == Some(t+1); - Map::new( - move||self.scenes_sizes(editing, 2, 15).map_while( - move|(s, scene, y1, y2)|if y2 as u16 > h { None } else { Some((s, scene, y1, y2, if s == 0 { - None } else { Some(self.scenes[s-1].clips[t].as_ref() - .map(|c|c.read().unwrap().color) - .unwrap_or(ItemPalette::G[32])) })) }), - move|(_, scene, y1, y2, prev), s| { - let height = (1 + y2 - y1) as u16; - let (name, fg, bg) = if let Some(clip) = &scene.clips[t] { - let clip = clip.read().unwrap(); - (Some(clip.name.clone()), clip.color.lightest.rgb, clip.color) - } else { - (None, Tui::g(96), ItemPalette::G[32]) - }; - let active = editing && same_track && selected_scene == Some(s+1); - let edit = |x|Bsp::b(x, When(active, &self.editor)); - map_south(y1 as u16, height, edit(Fixed::y(height, self.view_clip_cell( - same_track, s, &bg, prev, name, " ⏹ ", fg))))}) - })) - } - const TAB: &str = " Tab"; - fn view_clip_cell <'a> ( - &self, - same_track: bool, - scene: usize, - color: &ItemPalette, - prev: Option, - name: Option>, - icon: &'a str, - fg: Color, - ) -> impl Content + use<'a> { - let selected_scene = self.selected().scene(); - let selected = same_track && selected_scene == Some(scene+1); - let neighbor = same_track && selected_scene == Some(scene); - let is_last = scene == self.scenes.len().saturating_sub(1); - let colors = colors(color, prev, selected, neighbor, is_last); - let content = Fill::x(Align::w(Tui::fg(fg, Tui::bold(true, Bsp::e(icon, name))))); - Phat { width: 0, height: 0, selected, content, colors, } - } - fn view_scene_add (&self) -> impl Content + use<'_> { - let data = (self.selected().scene().unwrap_or(0), self.scenes().len()); - self.fmtd.write().unwrap().scns.update(Some(data), rewrite!(buf, "({}/{})", data.0, data.1)); - self.button3(" S", "add scene", self.fmtd.read().unwrap().scns.view.clone()) - } -} -fn colors ( - this: &ItemPalette, - prev: Option, - selected: bool, - neighbor: bool, - is_last: bool, -) -> [Color;4] { - let fg = this.lightest.rgb; - let bg = if selected { this.light } else { this.base }.rgb; - let hi = if neighbor { - prev.map(|prev|prev.light.rgb) - } else { - prev.map(|prev|prev.base.rgb) - }.unwrap_or(Reset); - let lo = if is_last { - Reset - } else if selected { - this.light.rgb - } else { - this.base.rgb - }; - [fg, bg, hi, lo] } diff --git a/tek/src/view/clip.rs b/tek/src/view/clip.rs new file mode 100644 index 00000000..f5be8c3f --- /dev/null +++ b/tek/src/view/clip.rs @@ -0,0 +1,112 @@ +use crate::*; +impl Tek { + pub fn view_tracks (&self) -> impl Content + use<'_> { + let data = (self.selected.track().unwrap_or(0), self.tracks().len()); + self.fmtd.write().unwrap().trks.update(Some(data), rewrite!(buf, "({}/{})", data.0, data.1)); + self.row(self.w(), 3, Align::w(Bsp::e( + self.button3(" t", "track", self.fmtd.read().unwrap().trks.view.clone()), + self.button2(" T", "add track"), + )), self.per_track(|t, track|{ + let active = self.selected().track() == Some(t+1); + 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) }; + Self::wrap(bg, fg, Tui::bold(true, Fill::x(Align::nw(name)))) + })) + } + pub fn view_scenes (&self) -> impl Content + use<'_> { + let w = self.size.w() as u16; + let h = self.size.h() as u16; + let editing = self.is_editing(); + let selected_track = self.selected().track(); + let selected_scene = self.selected().scene(); + self.row(w, h, + Align::y(Map::new( + move||self.scenes_sizes(editing, 2, 15).map_while( + move|(s, scene, y1, y2)|if y2 as u16 > h { + None + } else { Some((s, scene, y1, y2, if s == 0 { + None + } else { + Some(self.scenes[s-1].color) + })) }), + move|(_, scene, y1, y2, prev), s| { + let height = (1 + y2 - y1) as u16; + let bg = scene.color; + let fg = scene.color.lightest.rgb; + let name = Some(scene.name.clone()); + map_south(y1 as u16, height, Fixed::y(height, self.view_clip_cell( + true, s, &bg, prev, name, " ⯈ ", fg))) + })).boxed(), + self.per_track(move|t, track|{ + let same_track = selected_track == Some(t+1); + Map::new( + move||self.scenes_sizes(editing, 2, 15).map_while( + move|(s, scene, y1, y2)|if y2 as u16 > h { None } else { Some((s, scene, y1, y2, if s == 0 { + None } else { Some(self.scenes[s-1].clips[t].as_ref() + .map(|c|c.read().unwrap().color) + .unwrap_or(ItemPalette::G[32])) })) }), + move|(_, scene, y1, y2, prev), s| { + let height = (1 + y2 - y1) as u16; + let (name, fg, bg) = if let Some(clip) = &scene.clips[t] { + let clip = clip.read().unwrap(); + (Some(clip.name.clone()), clip.color.lightest.rgb, clip.color) + } else { + (None, Tui::g(96), ItemPalette::G[32]) + }; + let active = editing && same_track && selected_scene == Some(s+1); + let edit = |x|Bsp::b(x, When(active, &self.editor)); + map_south(y1 as u16, height, edit(Fixed::y(height, self.view_clip_cell( + same_track, s, &bg, prev, name, " ⏹ ", fg))))}) + })) + } + const TAB: &str = " Tab"; + fn view_clip_cell <'a> ( + &self, + same_track: bool, + scene: usize, + color: &ItemPalette, + prev: Option, + name: Option>, + icon: &'a str, + fg: Color, + ) -> impl Content + use<'a> { + let selected_scene = self.selected().scene(); + let selected = same_track && selected_scene == Some(scene+1); + let neighbor = same_track && selected_scene == Some(scene); + let is_last = scene == self.scenes.len().saturating_sub(1); + let colors = Self::colors(color, prev, selected, neighbor, is_last); + let content = Fill::x(Align::w(Tui::fg(fg, Tui::bold(true, Bsp::e(icon, name))))); + Phat { width: 0, height: 0, selected, content, colors, } + } + pub fn view_scene_add (&self) -> impl Content + use<'_> { + let data = (self.selected().scene().unwrap_or(0), self.scenes().len()); + self.fmtd.write().unwrap().scns.update(Some(data), rewrite!(buf, "({}/{})", data.0, data.1)); + self.button3(" S", "add scene", self.fmtd.read().unwrap().scns.view.clone()) + } + fn colors ( + this: &ItemPalette, + prev: Option, + selected: bool, + neighbor: bool, + is_last: bool, + ) -> [Color;4] { + let fg = this.lightest.rgb; + let bg = if selected { this.light } else { this.base }.rgb; + let hi = if neighbor { + prev.map(|prev|prev.light.rgb) + } else { + prev.map(|prev|prev.base.rgb) + }.unwrap_or(Reset); + let lo = if is_last { + Reset + } else if selected { + this.light.rgb + } else { + this.base.rgb + }; + [fg, bg, hi, lo] + } +} diff --git a/tek/src/view/input.rs b/tek/src/view/input.rs new file mode 100644 index 00000000..eab7aef6 --- /dev/null +++ b/tek/src/view/input.rs @@ -0,0 +1,42 @@ +use crate::*; +impl Tek { + pub fn view_inputs (&self) -> impl Content + use<'_> { + let fg = Tui::g(224); + Bsp::s( + Bsp::s( + self.row_top(self.w(), 1, + Fill::x(Align::w(Bsp::e( + self.button3(" i", "midi ins", format!("{}", self.midi_ins.len())), + self.button2(" I", "add midi in"), + ))), + self.per_track_top(move|t, track|{ + let rec = track.player.recording; + let mon = track.player.monitoring; + let rec = if rec { White } else { track.color.darkest.rgb }; + let mon = if mon { White } else { track.color.darkest.rgb }; + let bg = if self.selected().track() == Some(t+1) { + track.color.light.rgb + } else { + track.color.base.rgb + }; + let bg2 = if t > 0 { self.tracks()[t - 1].color.base.rgb } else { Reset }; + Self::wrap(bg, fg, Tui::bold(true, Fill::x(Bsp::e( + Tui::fg_bg(rec, bg, "Rec "), + Tui::fg_bg(mon, bg, "Mon ")))))})), + self.row_top(self.w(), self.h_inputs() - 1, + self.io_ports(fg, Tui::g(32), ||self.inputs_sizes()), + self.per_track_top(move|t, track|self.io_connections( + track.color.dark.rgb, + track.color.darker.rgb, + ||self.inputs_sizes() + ))), + ), + self.view_clips_into() + ) + } + fn view_clips_into (&self) -> impl Content + use<'_> { + let heading = Align::e("Into:"); + let content = self.per_track_top(|_, _|Tui::bg(Reset, " --- ")); + self.row_top(self.w(), 1, heading, content) + } +} diff --git a/tek/src/view/output.rs b/tek/src/view/output.rs new file mode 100644 index 00000000..4dbffafa --- /dev/null +++ b/tek/src/view/output.rs @@ -0,0 +1,43 @@ +use crate::*; +impl Tek { + pub fn view_outputs (&self) -> impl Content + use<'_> { + let fg = Tui::g(224); + Align::n(Bsp::s( + Bsp::s( + self.view_clips_next(), + self.view_clips_from(), + ), + Bsp::s( + self.row_top(self.w(), 1, + Fill::x(Align::w(Bsp::e( + self.button3(" o", "midi outs", format!("{}", self.midi_outs.len())), + self.button2(" O", "add midi out"), + ))), + self.per_track_top(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 bg = if self.selected().track() == Some(t+1) { track.color.light.rgb } else { track.color.base.rgb }; + let bg2 = if t > 0 { self.tracks()[t - 1].color.base.rgb } else { Reset }; + Self::wrap(bg, fg, Tui::bold(true, Fill::x(Bsp::e( + Tui::fg_bg(mute, bg, "Play "), + Tui::fg_bg(solo, bg, "Solo ")))))})), + self.row_top(self.w(), self.h_outputs() - 1, + self.io_ports(fg, Tui::g(32), ||self.outputs_sizes()), + self.per_track_top(move|t, track|self.io_connections( + track.color.dark.rgb, track.color.darker.rgb, ||self.outputs_sizes()))), + ) + )) + } + fn view_clips_from (&self) -> impl Content + use<'_> { + let heading = Align::e("From:"); + let content = self.per_track_top(|_, _|Tui::bg(Reset, " --- ")); + self.row_top(self.w(), 1, heading, content) + } + fn view_clips_next (&self) -> impl Content + use<'_> { + let heading = Align::e("Next:"); + let content = self.per_track_top(|_, _|Tui::bg(Reset, " --- ")); + self.row_top(self.w(), 1, heading, content) + } +}