diff --git a/engine/src/thunk.rs b/engine/src/thunk.rs index 936114f1..26297641 100644 --- a/engine/src/thunk.rs +++ b/engine/src/thunk.rs @@ -1,10 +1,28 @@ use crate::*; use std::marker::PhantomData; + /// Lazily-evaluated [Render]able. -pub struct Thunk, F: Fn()->T + Send + Sync>(F, PhantomData); +pub struct Thunk, F: Fn()->T + Send + Sync>(PhantomData, F); impl, F: Fn()->T + Send + Sync> Thunk { - pub fn new (thunk: F) -> Self { Self(thunk, Default::default()) } + pub fn new (thunk: F) -> Self { Self(Default::default(), thunk) } } impl, F: Fn()->T + Send + Sync> Content for Thunk { - fn content (&self) -> impl Render { (self.0)() } + fn content (&self) -> impl Render { (self.1)() } +} + +pub struct RenderThunk(PhantomData, F); +impl RenderThunk { + pub fn new (render: F) -> Self { Self(Default::default(), render) } +} +impl Content for RenderThunk { + fn render (&self, to: &mut E) { (self.1)(to) } +} + +pub struct LayoutThunkE::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync>(PhantomData, F1, F2); +implE::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> LayoutThunk { + pub fn new (layout: F1, render: F2) -> Self { Self(Default::default(), layout, render) } +} +implE::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> Content for LayoutThunk { + fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) } + fn render (&self, to: &mut E) { (self.2)(to) } } diff --git a/layout/src/map.rs b/layout/src/map.rs index 3a917b7f..7f1158f2 100644 --- a/layout/src/map.rs +++ b/layout/src/map.rs @@ -10,20 +10,30 @@ pub fn map_south( Fill::x(item)))) } -pub struct Map(pub F, pub G) where +pub struct Map<'a, A, B, I, F, G>(pub PhantomData<&'a()>, pub F, pub G) where I: Iterator + Send + Sync, - F: Fn() -> I + Send + Sync, + F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync; -impl Content for Map where +impl<'a, A, B, I, F, G> Map<'a, A, B, I, F, G> where + I: Iterator + Send + Sync, + F: Fn() -> I + Send + Sync + 'a, + G: Fn(A, usize)->B + Send + Sync +{ + pub fn new (f: F, g: G) -> Self { + Self(Default::default(), f, g) + } +} + +impl<'a, E, A, B, I, F, G> Content for Map<'a, A, B, I, F, G> where E: Output, B: Render, I: Iterator + Send + Sync, - F: Fn() -> I + Send + Sync, + F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync { fn layout (&self, area: E::Area) -> E::Area { - let Self(get_iterator, callback) = self; + let Self(_, get_iterator, callback) = self; let mut index = 0; let [mut min_x, mut min_y] = area.center(); let [mut max_x, mut max_y] = area.center(); @@ -42,7 +52,7 @@ impl Content for Map where area.center_xy([w.into(), h.into()].into()).into() } fn render (&self, to: &mut E) { - let Self(get_iterator, callback) = self; + let Self(_, get_iterator, callback) = self; let mut index = 0; //let area = self.layout(to.area()); for item in get_iterator() { diff --git a/src/arranger/arranger_track.rs b/src/arranger/arranger_track.rs index 7f38a351..d2865137 100644 --- a/src/arranger/arranger_track.rs +++ b/src/arranger/arranger_track.rs @@ -37,27 +37,6 @@ impl Arranger { has_clock!(|self:ArrangerTrack|self.player.clock()); has_player!(|self:ArrangerTrack|self.player); impl ArrangerTrack { - pub fn widths (tracks: &[Self]) -> Vec<(usize, usize)> { - let mut widths = vec![]; - let mut total = 0; - for track in tracks.iter() { - let width = track.width; - widths.push((width, total)); - total += width; - } - widths.push((0, total)); - widths - } - pub fn with_widths (tracks: &[ArrangerTrack]) - -> impl Iterator - { - let mut x = 0; - tracks.iter().enumerate().map(move |(index, track)|{ - let data = (index, track, x, x + track.width); - x += track.width; - data - }) - } /// Name of track pub fn name (&self) -> &Arc> { &self.name diff --git a/src/arranger/arranger_tui.rs b/src/arranger/arranger_tui.rs index 84abcef7..0b01390e 100644 --- a/src/arranger/arranger_tui.rs +++ b/src/arranger/arranger_tui.rs @@ -23,23 +23,32 @@ use crate::*; //}); render!(TuiOut: (self: Arranger) => { let scenes = &self.scenes; - let ppqs = Arranger::ppqs(scenes, 1); + let scene_heights = Arranger::scene_heights(scenes, 1); Fill::xy(self.size.of( Bsp::s(self.toolbar_view(), Bsp::n(self.status_view(), - Bsp::n(self.selector_view(), Bsp::w(self.pool_view(), - Bsp::s(Align::n(Fill::x(Fixed::y(3, self.header()))), - Bsp::s(Align::n(Fill::x(Fixed::y(1, self.ins()))), - Bsp::s(Align::n(Fill::x(Fixed::y(1, self.outs()))), - Fill::xy( - Bsp::a(Fill::xy(Fill::xy(Map( - move||scenes.iter(),//.zip(ppqs.iter().map(|row|row.0)), - move|scene, i|Arranger::format_scene(&self.tracks, scene, ppqs[i].0)))), + Bsp::n(self.selector_view(), + Bsp::n(Fixed::y(20, &self.editor), + Bsp::s( + Align::w(Fill::x( + Bsp::s(Fixed::y(3, Align::w(self.header())), + Bsp::s(Fixed::y(1, self.ins()), Fill::x(Fixed::y(1, self.outs())))) + )), + Bsp::a( Bsp::a( - Fill::xy(ArrangerVRowSep::from((self, 1))), - Fill::xy(ArrangerVColSep::from(self)))))))))))))) -}); + Map::new( + move||scenes.iter(),//.zip(scene_heights.iter().map(|row|row.0)), + move|scene, i|Arranger::format_scene(&self.tracks, scene, scene_heights[i].0) + ), + self.cursor(), + ), + Bsp::a( + Fill::xy(self.scene_row_sep()), + "" + //Fill::xy(ArrangerVColSep::from(self)) + ) + )))))))))}); //Align::n(Fill::xy(lay!( //Align::n(Fill::xy(Tui::bg(self.color.darkest.rgb, " "))), //Align::n(Fill::xy(ArrangerVRowSep::from((self, 1)))), @@ -71,7 +80,7 @@ impl<'a> ArrangerVClips<'a> { size: &state.size, tracks: &state.tracks, scenes: &state.scenes, - rows: Arranger::ppqs(&state.scenes, zoom), + rows: Arranger::scene_heights(&state.scenes, zoom), } } } @@ -81,7 +90,7 @@ fn row > (color: ItemPalette, field: T) -> impl Content impl Content + use<'_> { let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16; - Push::x(scenes_w, Map(||ArrangerTrack::with_widths(self.tracks.as_slice()), |(_, track, x1, x2), i| { + Push::x(scenes_w, Map::new(||Arranger::tracks_with_widths(self.tracks.as_slice()), |(_, track, x1, x2), i| { let (w, h) = (ArrangerTrack::MIN_WIDTH.max(x2 - x1), HEADER_H); let color = track.color(); let title = format!("{} {} {}", track.name.read().unwrap(), x1, x2); @@ -92,7 +101,7 @@ impl Arranger { } fn ins (&self) -> impl Content + use<'_> { let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16; - Push::x(scenes_w, Map(||ArrangerTrack::with_widths(self.tracks.as_slice()), |(_, track, x1, x2), i| { + Push::x(scenes_w, Map::new(||Arranger::tracks_with_widths(self.tracks.as_slice()), |(_, track, x1, x2), i| { let (w, h) = (ArrangerTrack::MIN_WIDTH.max(x2 - x1), HEADER_H); let color = track.color(); let input = Self::format_input(track); @@ -102,14 +111,14 @@ impl Arranger { } fn outs (&self) -> impl Content + use<'_> { let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16; - Push::x(scenes_w, Map(||ArrangerTrack::with_widths(self.tracks.as_slice()), |(_, track, x1, x2), i| { + Push::x(scenes_w, Map::new(||Arranger::tracks_with_widths(self.tracks.as_slice()), |(_, track, x1, x2), i| { let (w, h) = (ArrangerTrack::MIN_WIDTH.max(x2 - x1), HEADER_H); let color = track.color(); Fill::xy(Align::n(Push::x(x2 as u16, Tui::bg(color.base.rgb, Min::xy(w as u16, h, Fixed::xy(w as u16, 5, row(color, Self::format_output(track).ok()))))))) })) } - pub fn ppqs (scenes: &[ArrangerScene], factor: usize) -> Vec<(usize, usize)> { + pub fn scene_heights (scenes: &[ArrangerScene], factor: usize) -> Vec<(usize, usize)> { let mut total = 0; if factor == 0 { scenes.iter().map(|scene|{ @@ -135,7 +144,7 @@ impl Arranger { let name = Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb, Expand::x(1, Tui::bold(true, scene.name.read().unwrap().clone())) ); - let clips = Map(||ArrangerTrack::with_widths(tracks), move|(index, track, x1, x2), _| + let clips = Map::new(||Arranger::tracks_with_widths(tracks), move|(index, track, x1, x2), _| Push::x((x2 - x1) as u16, Self::format_clip(scene, index, track, (x2 - x1) as u16, height)) ); Fixed::y(height, Bsp::e(icon, Bsp::e(name, clips))) @@ -226,129 +235,209 @@ impl Arranger { Ok(format!("<{}", track.player.midi_outs().first().map(|port|port.short_name()) .transpose()?.unwrap_or("?".into()))) } -} -pub struct ArrangerVColSep { - fg: Color, - cols: Vec<(usize, usize)>, - scenes_w: u16 -} -from!(|state:&Arranger|ArrangerVColSep = Self { - fg: TuiTheme::separator_fg(false), - cols: ArrangerTrack::widths(&state.tracks), - scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16, -}); -render!(TuiOut: |self: ArrangerVColSep, to| { - let style = Some(Style::default().fg(self.fg)); - for x in self.cols.iter().map(|col|col.1) { - let x = self.scenes_w + to.area().x() + x as u16; - for y in to.area().y()..to.area().y2() { - to.blit(&"▎", x, y, style); + + fn track_col_sep <'a> (&'a self) -> impl Content + 'a { + let fg = TuiTheme::separator_fg(false); + let x = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16; + Map::new( + move||Self::tracks_with_widths(self.tracks.as_slice()), + move|(_n, _track, x1, _x2), _i|Push::x(x + x1 as u16, Fill::y(Tui::fg(fg, "▎"))) + ) + } + pub fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> { + let mut widths = vec![]; + let mut total = 0; + for track in tracks.iter() { + let width = track.width; + widths.push((width, total)); + total += width; } + widths.push((0, total)); + widths } -}); - -pub struct ArrangerVRowSep { - fg: Color, - rows: Vec<(usize, usize)>, -} -from!(|args:(&Arranger, usize)|ArrangerVRowSep = Self { - fg: Color::Rgb(255,255,255,), - rows: Arranger::ppqs(&args.0.scenes, args.1), -}); -render!(TuiOut: |self: ArrangerVRowSep, to|for y in self.rows.iter().map(|row|row.1) { - let y = to.area().y() + (y / PPQ) as u16 + 1; - if y >= to.buffer.area.height { break } - for x in to.area().x()..to.area().x2().saturating_sub(2) { - //if x < to.buffer.area.x && y < to.buffer.area.y { - if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { - cell.modifier = Modifier::UNDERLINED; - cell.underline_color = self.fg; - } - //} + pub fn tracks_with_widths (tracks: &[ArrangerTrack]) + -> impl Iterator + { + let mut x = 0; + tracks.iter().enumerate().map(move |(index, track)|{ + let data = (index, track, x, x + track.width); + x += track.width; + data + }) } -}); -pub struct ArrangerVCursor { - cols: Vec<(usize, usize)>, - rows: Vec<(usize, usize)>, - color: ItemPalette, - reticle: Reticle, - selected: ArrangerSelection, - scenes_w: u16, -} + fn scene_row_sep <'a> (&'a self) -> impl Content + 'a { + let fg = Color::Rgb(255,255,255); + Map::new(move||self.scenes_with_heights(), |_, _|"") + //Map(||rows.iter(), |(_n, _scene, y1, _y2), _i| { + //let y = to.area().y() + (y / PPQ) as u16 + 1; + //if y >= to.buffer.area.height { break } + //for x in to.area().x()..to.area().x2().saturating_sub(2) { + ////if x < to.buffer.area.x && y < to.buffer.area.y { + //if let Some(cell) = to.buffer.cell_mut(ratatui::prelude::Position::from((x, y))) { + //cell.modifier = Modifier::UNDERLINED; + //cell.underline_color = fg; + //} + ////} + //} + //}) + } + pub fn scenes_with_heights (&self) + -> impl Iterator + { + let mut y = 0; + self.scenes.iter().enumerate().map(move|(index, scene)|{ + let data = (index, scene, y, y + 1); + y += 1; + data + }) + } -from!(|args:(&Arranger, usize)|ArrangerVCursor = Self { - cols: ArrangerTrack::widths(&args.0.tracks), - rows: Arranger::ppqs(&args.0.scenes, args.1), - selected: args.0.selected(), - scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&args.0.scenes) as u16, - color: args.0.color, - reticle: Reticle(Style { - fg: Some(args.0.color.lighter.rgb), - bg: None, - underline_color: None, - add_modifier: Modifier::empty(), - sub_modifier: Modifier::DIM - }), -}); -impl Content for ArrangerVCursor { - fn render (&self, to: &mut TuiOut) { - let area = to.area(); + fn cursor (&self) -> impl Content + '_ { + let color = self.color; + let bg = color.lighter.rgb;//Color::Rgb(0, 255, 0); + let selected = self.selected(); + let cols = Arranger::track_widths(&self.tracks); + let rows = Arranger::scene_heights(&self.scenes, 1); + let scenes_w = SCENES_W_OFFSET + ArrangerScene::longest_name(&self.scenes) as u16; let focused = true; - let selected = self.selected; - let get_track_area = |t: usize| [ - self.scenes_w + area.x() + self.cols[t].1 as u16, area.y(), - self.cols[t].0 as u16, area.h(), - ]; - let get_scene_area = |s: usize| [ - area.x(), HEADER_H + area.y() + (self.rows[s].1 / PPQ) as u16, - area.w(), (self.rows[s].0 / PPQ) as u16 - ]; - let get_clip_area = |t: usize, s: usize| [ - (self.scenes_w + area.x() + self.cols[t].1 as u16).saturating_sub(1), - HEADER_H + area.y() + (self.rows[s].1/PPQ) as u16, - self.cols[t].0 as u16 + 2, - (self.rows[s].0 / PPQ) as u16 - ]; - let mut track_area: Option<[u16;4]> = None; - let mut scene_area: Option<[u16;4]> = None; - let mut clip_area: Option<[u16;4]> = None; - let area = match selected { - ArrangerSelection::Mix => area, - ArrangerSelection::Track(t) => { - track_area = Some(get_track_area(t)); - area - }, - ArrangerSelection::Scene(s) => { - scene_area = Some(get_scene_area(s)); - area - }, - ArrangerSelection::Clip(t, s) => { - track_area = Some(get_track_area(t)); - scene_area = Some(get_scene_area(s)); - clip_area = Some(get_clip_area(t, s)); - area - }, - }; - let bg = self.color.lighter.rgb;//Color::Rgb(0, 255, 0); - if let Some([x, y, width, height]) = track_area { - to.fill_fg([x, y, 1, height], bg); - to.fill_fg([x + width, y, 1, height], bg); - } - if let Some([_, y, _, height]) = scene_area { - to.fill_ul([area.x(), y - 1, area.w(), 1], bg); - to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg); - } - if focused { - to.place(if let Some(clip_area) = clip_area { - clip_area - } else if let Some(track_area) = track_area { - track_area.clip_h(HEADER_H) - } else if let Some(scene_area) = scene_area { - scene_area.clip_w(self.scenes_w) - } else { - area.clip_w(self.scenes_w).clip_h(HEADER_H) - }, &self.reticle) - }; + let reticle = Reticle(Style { + fg: Some(self.color.lighter.rgb), + bg: None, + underline_color: None, + add_modifier: Modifier::empty(), + sub_modifier: Modifier::DIM + }); + RenderThunk::new(move|to: &mut TuiOut|{ + let area = to.area(); + let [x, y, w, h] = area.xywh(); + let mut track_area: Option<[u16;4]> = match selected { + ArrangerSelection::Track(t) | ArrangerSelection::Clip(t, _) => Some([ + x + scenes_w + cols[t].1 as u16, y, + cols[t].0 as u16, h, + ]), + _ => None + }; + let mut scene_area: Option<[u16;4]> = match selected { + ArrangerSelection::Scene(s) | ArrangerSelection::Clip(_, s) => Some([ + x, y + HEADER_H + (rows[s].1 / PPQ) as u16, + w, (rows[s].0 / PPQ) as u16 + ]), + _ => None + }; + let mut clip_area: Option<[u16;4]> = match selected { + ArrangerSelection::Clip(t, s) => Some([ + (scenes_w + x + cols[t].1 as u16).saturating_sub(1), + HEADER_H + y + (rows[s].1/PPQ) as u16, + cols[t].0 as u16 + 2, + (rows[s].0 / PPQ) as u16 + ]), + _ => None + }; + if let Some([x, y, width, height]) = track_area { + to.fill_fg([x, y, 1, height], bg); + to.fill_fg([x + width, y, 1, height], bg); + } + if let Some([_, y, _, height]) = scene_area { + to.fill_ul([x, y - 1, w, 1], bg); + to.fill_ul([x, y + height - 1, w, 1], bg); + } + if focused { + to.place(if let Some(clip_area) = clip_area { + clip_area + } else if let Some(track_area) = track_area { + track_area.clip_h(HEADER_H) + } else if let Some(scene_area) = scene_area { + scene_area.clip_w(scenes_w) + } else { + area.clip_w(scenes_w).clip_h(HEADER_H) + }, &reticle) + }; + }) } } + +//pub struct ArrangerVCursor { + //cols: Vec<(usize, usize)>, + //rows: Vec<(usize, usize)>, + //color: ItemPalette, + //reticle: Reticle, + //selected: ArrangerSelection, + //scenes_w: u16, +//} + +//from!(|args:(&Arranger, usize)|ArrangerVCursor = Self { + //cols: Arranger::track_widths(&args.0.tracks), + //rows: Arranger::scene_heights(&args.0.scenes, args.1), + //selected: args.0.selected(), + //scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&args.0.scenes) as u16, + //color: args.0.color, + //reticle: Reticle(Style { + //fg: Some(args.0.color.lighter.rgb), + //bg: None, + //underline_color: None, + //add_modifier: Modifier::empty(), + //sub_modifier: Modifier::DIM + //}), +//}); +//impl Content for ArrangerVCursor { + //fn render (&self, to: &mut TuiOut) { + //let area = to.area(); + //let focused = true; + //let selected = self.selected; + //let get_track_area = |t: usize| [ + //self.scenes_w + area.x() + self.cols[t].1 as u16, area.y(), + //self.cols[t].0 as u16, area.h(), + //]; + //let get_scene_area = |s: usize| [ + //area.x(), HEADER_H + area.y() + (self.rows[s].1 / PPQ) as u16, + //area.w(), (self.rows[s].0 / PPQ) as u16 + //]; + //let get_clip_area = |t: usize, s: usize| [ + //(self.scenes_w + area.x() + self.cols[t].1 as u16).saturating_sub(1), + //HEADER_H + area.y() + (self.rows[s].1/PPQ) as u16, + //self.cols[t].0 as u16 + 2, + //(self.rows[s].0 / PPQ) as u16 + //]; + //let mut track_area: Option<[u16;4]> = None; + //let mut scene_area: Option<[u16;4]> = None; + //let mut clip_area: Option<[u16;4]> = None; + //let area = match selected { + //ArrangerSelection::Mix => area, + //ArrangerSelection::Track(t) => { + //track_area = Some(get_track_area(t)); + //area + //}, + //ArrangerSelection::Scene(s) => { + //scene_area = Some(get_scene_area(s)); + //area + //}, + //ArrangerSelection::Clip(t, s) => { + //track_area = Some(get_track_area(t)); + //scene_area = Some(get_scene_area(s)); + //clip_area = Some(get_clip_area(t, s)); + //area + //}, + //}; + //let bg = self.color.lighter.rgb;//Color::Rgb(0, 255, 0); + //if let Some([x, y, width, height]) = track_area { + //to.fill_fg([x, y, 1, height], bg); + //to.fill_fg([x + width, y, 1, height], bg); + //} + //if let Some([_, y, _, height]) = scene_area { + //to.fill_ul([area.x(), y - 1, area.w(), 1], bg); + //to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg); + //} + //if focused { + //to.place(if let Some(clip_area) = clip_area { + //clip_area + //} else if let Some(track_area) = track_area { + //track_area.clip_h(HEADER_H) + //} else if let Some(scene_area) = scene_area { + //scene_area.clip_w(self.scenes_w) + //} else { + //area.clip_w(self.scenes_w).clip_h(HEADER_H) + //}, &self.reticle) + //}; + //} +//} diff --git a/src/lib.rs b/src/lib.rs index 70231d0a..bcce4045 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,15 +10,7 @@ pub(crate) use ::tek_tui::{ *, tek_edn::*, tek_layout::*, - tek_engine::{ - from, - Usually, Perhaps, - Output, Content, Render, RenderBox, Thunk, render, Engine, Size, Area, - Input, handle, Handle, command, Command, input_to_command, InputToCommand, keymap, EventMap, - }, - Tui, - TuiIn, key, ctrl, shift, alt, kexp, kpat, - TuiOut, + tek_engine::*, crossterm::{ self, event::{ diff --git a/src/piano/piano_h_notes.rs b/src/piano/piano_h_notes.rs index 373e3176..247fd3fe 100644 --- a/src/piano/piano_h_notes.rs +++ b/src/piano/piano_h_notes.rs @@ -25,7 +25,9 @@ render!(TuiOut: |self: PianoHorizontalNotes<'a>, render|{ let is_in_y = source_y < source.height; if is_in_x && is_in_y { if let Some(source_cell) = source.get(source_x, source_y) { - *render.buffer.get_mut(screen_x, screen_y) = source_cell.clone(); + if let Some(cell) = render.buffer.cell_mut(ratatui::prelude::Position::from((screen_x, screen_y))) { + *cell = source_cell.clone(); + } } } } diff --git a/src/pool/pool_tui.rs b/src/pool/pool_tui.rs index 99aeb75c..2ddda0ea 100644 --- a/src/pool/pool_tui.rs +++ b/src/pool/pool_tui.rs @@ -7,7 +7,7 @@ render!(TuiOut: (self: PoolView<'a>) => { let color = self.1.phrase().read().unwrap().color; Outer( Style::default().fg(color.dark.rgb).bg(color.darkest.rgb) - ).enclose(Map(||model.phrases().iter(), |clip, i|{ + ).enclose(Map::new(||model.phrases().iter(), |clip, i|{ let item_height = 1; let item_offset = i as u16 * item_height; let selected = i == model.phrase_index(); diff --git a/src/sampler/sample_list.rs b/src/sampler/sample_list.rs index b8a1e4de..96804061 100644 --- a/src/sampler/sample_list.rs +++ b/src/sampler/sample_list.rs @@ -17,7 +17,7 @@ render!(TuiOut: (self: SampleList<'a>) => { let note_lo = editor.note_lo().load(Relaxed); let note_pt = editor.note_point(); let note_hi = editor.note_hi(); - Outer(Style::default().fg(TuiTheme::g(96))).enclose(Map(move||(note_lo..=note_hi).rev(), move|note, i| { + Outer(Style::default().fg(TuiTheme::g(96))).enclose(Map::new(move||(note_lo..=note_hi).rev(), move|note, i| { let offset = |a|Push::y(i as u16, Align::n(Fixed::y(1, Fill::x(a))));