mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
add RenderThunk, LayoutThunk, Map::new, fold some components into arranger methods
This commit is contained in:
parent
38e2e64751
commit
b2fb71b405
8 changed files with 268 additions and 178 deletions
|
|
@ -1,10 +1,28 @@
|
|||
use crate::*;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Lazily-evaluated [Render]able.
|
||||
pub struct Thunk<E: Output, T: Render<E>, F: Fn()->T + Send + Sync>(F, PhantomData<E>);
|
||||
pub struct Thunk<E: Output, T: Render<E>, F: Fn()->T + Send + Sync>(PhantomData<E>, F);
|
||||
impl<E: Output, T: Render<E>, F: Fn()->T + Send + Sync> Thunk<E, T, F> {
|
||||
pub fn new (thunk: F) -> Self { Self(thunk, Default::default()) }
|
||||
pub fn new (thunk: F) -> Self { Self(Default::default(), thunk) }
|
||||
}
|
||||
impl<E: Output, T: Render<E>, F: Fn()->T + Send + Sync> Content<E> for Thunk<E, T, F> {
|
||||
fn content (&self) -> impl Render<E> { (self.0)() }
|
||||
fn content (&self) -> impl Render<E> { (self.1)() }
|
||||
}
|
||||
|
||||
pub struct RenderThunk<E: Output, F: Fn(&mut E) + Send + Sync>(PhantomData<E>, F);
|
||||
impl<E: Output, F: Fn(&mut E) + Send + Sync> RenderThunk<E, F> {
|
||||
pub fn new (render: F) -> Self { Self(Default::default(), render) }
|
||||
}
|
||||
impl<E: Output, F: Fn(&mut E) + Send + Sync> Content<E> for RenderThunk<E, F> {
|
||||
fn render (&self, to: &mut E) { (self.1)(to) }
|
||||
}
|
||||
|
||||
pub struct LayoutThunk<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync>(PhantomData<E>, F1, F2);
|
||||
impl<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> LayoutThunk<E, F1, F2> {
|
||||
pub fn new (layout: F1, render: F2) -> Self { Self(Default::default(), layout, render) }
|
||||
}
|
||||
impl<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> Content<E> for LayoutThunk<E, F1, F2> {
|
||||
fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) }
|
||||
fn render (&self, to: &mut E) { (self.2)(to) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,20 +10,30 @@ pub fn map_south<O: Output>(
|
|||
Fill::x(item))))
|
||||
}
|
||||
|
||||
pub struct Map<A, B, I, F, G>(pub F, pub G) where
|
||||
pub struct Map<'a, A, B, I, F, G>(pub PhantomData<&'a()>, pub F, pub G) where
|
||||
I: Iterator<Item = A> + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync + 'a,
|
||||
G: Fn(A, usize)->B + Send + Sync;
|
||||
|
||||
impl<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> where
|
||||
impl<'a, A, B, I, F, G> Map<'a, A, B, I, F, G> where
|
||||
I: Iterator<Item = A> + 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<E> for Map<'a, A, B, I, F, G> where
|
||||
E: Output,
|
||||
B: Render<E>,
|
||||
I: Iterator<Item = A> + 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<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> 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() {
|
||||
|
|
|
|||
|
|
@ -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<Item = (usize, &ArrangerTrack, usize, usize)>
|
||||
{
|
||||
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<RwLock<String>> {
|
||||
&self.name
|
||||
|
|
|
|||
|
|
@ -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 <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOu
|
|||
impl Arranger {
|
||||
fn header (&self) -> impl Content<TuiOut> + 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<TuiOut> + 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<TuiOut> + 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<TuiOut> + '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<Item = (usize, &ArrangerTrack, usize, usize)>
|
||||
{
|
||||
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<TuiOut> + '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<Item = (usize, &ArrangerScene, usize, usize)>
|
||||
{
|
||||
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<TuiOut> for ArrangerVCursor {
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let area = to.area();
|
||||
fn cursor (&self) -> impl Content<TuiOut> + '_ {
|
||||
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<TuiOut> 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)
|
||||
//};
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
10
src/lib.rs
10
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::{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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))));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue