mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip9 (15e)
This commit is contained in:
parent
2f772eceef
commit
f9d1456897
11 changed files with 252 additions and 209 deletions
|
|
@ -1,8 +1,15 @@
|
|||
use crate::*;
|
||||
|
||||
#[macro_export] macro_rules! lay {
|
||||
($(move)*|$add:ident|$expr:expr) => { Layers::new($(move)*|$add|$expr) };
|
||||
($($expr:expr),* $(,)?) => { Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) }) }
|
||||
([$($expr:expr),* $(,)?]) => {
|
||||
Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
(![$($expr:expr),* $(,)?]) => {
|
||||
Layers::new(|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
($expr:expr) => {
|
||||
Layers::new($expr)
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Layers<
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
use crate::*;
|
||||
|
||||
#[macro_export] macro_rules! col {
|
||||
($($move:ident)?|$add:ident|$expr:expr) => {
|
||||
Stack::down($(move)?|$add|$expr)
|
||||
};
|
||||
($pat:pat in $collection:expr => $item:expr) => {
|
||||
Stack::down(move |add|{
|
||||
for $pat in $collection { add(&$item)?; }
|
||||
Ok(())
|
||||
})
|
||||
};
|
||||
($($expr:expr),* $(,)?) => {
|
||||
([$($expr:expr),* $(,)?]) => {
|
||||
Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
(![$($expr:expr),* $(,)?]) => {
|
||||
Stack::down(|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
($expr:expr) => {
|
||||
Stack::down($expr)
|
||||
};
|
||||
($pat:pat in $collection:expr => $item:expr) => {
|
||||
Stack::down(move|add|{ for $pat in $collection { add(&$item)?; } Ok(()) })
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! col_up {
|
||||
($($move:ident)?|$add:ident|$expr:expr) => {
|
||||
($(move)?|$add:ident|$expr:expr) => {
|
||||
Stack::up($(move)?|$add|$expr)
|
||||
};
|
||||
($pat:pat in $collection:expr => $item:expr) => {
|
||||
|
|
@ -24,17 +25,23 @@ use crate::*;
|
|||
Ok(())
|
||||
})
|
||||
};
|
||||
($($expr:expr),* $(,)?) => { Stack::up(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
|
||||
($($expr:expr),* $(,)?) => {
|
||||
Stack::up(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! row {
|
||||
($($move:ident)?|$add:ident|$expr:expr) => {
|
||||
Stack::right($(move)?|$add|$expr)
|
||||
([$($expr:expr),* $(,)?]) => {
|
||||
Stack::right(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
(![$($expr:expr),* $(,)?]) => {
|
||||
Stack::right(|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
($expr:expr) => {
|
||||
Stack::right($expr)
|
||||
};
|
||||
($pat:pat in $collection:expr => $item:expr) => {
|
||||
Stack::right(move |add|{ for $pat in $collection { add(&$item)?; } Ok(()) })
|
||||
};
|
||||
($($expr:expr),* $(,)?) => {
|
||||
Stack::right(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
Stack::right(move|add|{ for $pat in $collection { add(&$item)?; } Ok(()) })
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl FocusWrap<TransportFocus> for TransportFocus {
|
|||
let focused = focus == self;
|
||||
let corners = focused.then_some(CORNERS);
|
||||
//let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50)));
|
||||
lay!(corners, /*highlight,*/ *content)
|
||||
lay!([corners, /*highlight,*/ *content])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ impl FocusWrap<TransportFocus> for Option<TransportFocus> {
|
|||
let focused = Some(focus) == self;
|
||||
let corners = focused.then_some(CORNERS);
|
||||
//let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50)));
|
||||
lay!(corners, /*highlight,*/ *content)
|
||||
lay!([corners, /*highlight,*/ *content])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,15 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C
|
|||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for () {
|
||||
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
|
||||
Ok(None)
|
||||
}
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Render<Tui> for &str {
|
||||
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
|
||||
// TODO: line breaks
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ render!(|self: ArrangerTui|{
|
|||
Tui::to_south(
|
||||
self.splits[0],
|
||||
Tui::to_south(
|
||||
lay!(
|
||||
lay!([
|
||||
Layers::new(move |add|{
|
||||
match self.mode {
|
||||
ArrangerMode::Horizontal =>
|
||||
|
|
@ -30,7 +30,7 @@ render!(|self: ArrangerTui|{
|
|||
}))
|
||||
.fg(TuiTheme::title_fg(arranger_focused))
|
||||
.push_x(1),
|
||||
),
|
||||
]),
|
||||
Split::right(
|
||||
self.splits[1],
|
||||
PhraseListView::from(self),
|
||||
|
|
@ -85,6 +85,14 @@ fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
|||
widths
|
||||
}
|
||||
|
||||
fn any_size <E: Engine> (_: E::Size) -> Perhaps<E::Size>{
|
||||
Ok(Some([0.into(),0.into()].into()))
|
||||
}
|
||||
|
||||
fn custom_render <F: Fn(&mut TuiOutput)->Usually<()>+Send+Sync> (render: F) -> impl Render<Tui> {
|
||||
Widget::new(|_|Ok(Some([0u16,0u16].into())), render)
|
||||
}
|
||||
|
||||
pub fn arranger_content_vertical (
|
||||
view: &ArrangerTui,
|
||||
factor: usize
|
||||
|
|
@ -100,9 +108,8 @@ pub fn arranger_content_vertical (
|
|||
let sep_fg = TuiTheme::separator_fg(false);
|
||||
let header_h = 3u16;//5u16;
|
||||
let scenes_w = 3 + ArrangerScene::longest_name(scenes) as u16; // x of 1st track
|
||||
let rows: &[(usize, usize)] = rows.as_ref();
|
||||
let cols: &[(usize, usize)] = cols.as_ref();
|
||||
let any_size = |_|Ok(Some([0,0]));
|
||||
//let rows: &[(usize, usize)] = rows_.as_ref();
|
||||
//let cols: &[(usize, usize)] = cols_.as_ref();
|
||||
|
||||
// track titles
|
||||
let header = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0)) => {
|
||||
|
|
@ -135,12 +142,12 @@ pub fn arranger_content_vertical (
|
|||
}).unwrap_or(String::from("▎"));
|
||||
let timer = Tui::to_south(until_next, elapsed);
|
||||
// name of active MIDI input
|
||||
let input = format!("▎>{}", track.player.midi_ins().get(0)
|
||||
let _input = format!("▎>{}", track.player.midi_ins().get(0)
|
||||
.map(|port|port.short_name())
|
||||
.transpose()?
|
||||
.unwrap_or("(none)".into()));
|
||||
// name of active MIDI output
|
||||
let output = format!("▎<{}", track.player.midi_outs().get(0)
|
||||
let _output = format!("▎<{}", track.player.midi_outs().get(0)
|
||||
.map(|port|port.short_name())
|
||||
.transpose()?
|
||||
.unwrap_or("(none)".into()));
|
||||
|
|
@ -189,93 +196,144 @@ pub fn arranger_content_vertical (
|
|||
)
|
||||
}));
|
||||
|
||||
let arrangement = Tui::bg(bg.rgb, lay!(move|add|{
|
||||
// column separators
|
||||
add(&Widget::new(any_size, move|to: &mut TuiOutput|{
|
||||
let style = Some(Style::default().fg(sep_fg));
|
||||
Ok(for x in cols.iter().map(|col|col.1) {
|
||||
let x = scenes_w + to.area().x() + x as u16;
|
||||
for y in to.area().y()..to.area().y2() { to.blit(&"▎", x, y, style); }
|
||||
})
|
||||
}))?;
|
||||
// row separators
|
||||
add(&Widget::new(any_size, move|to: &mut TuiOutput|{
|
||||
Ok(for y in 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 {
|
||||
let cell = to.buffer.get_mut(x, y);
|
||||
cell.modifier = Modifier::UNDERLINED;
|
||||
cell.underline_color = sep_fg;
|
||||
}
|
||||
}
|
||||
})
|
||||
}))?;
|
||||
// full grid with header and footer
|
||||
add(&Tui::to_south(header, content))?;
|
||||
// cursor
|
||||
add(&Widget::new(any_size, move|to: &mut TuiOutput|{
|
||||
let area = to.area();
|
||||
let focused = view.arranger_focused();
|
||||
let selected = view.selected;
|
||||
let get_track_area = |t: usize| [
|
||||
scenes_w + area.x() + cols[t].1 as u16, area.y(),
|
||||
cols[t].0 as u16, area.h(),
|
||||
];
|
||||
let get_scene_area = |s: usize| [
|
||||
area.x(), header_h + area.y() + (rows[s].1 / PPQ) as u16,
|
||||
area.w(), (rows[s].0 / PPQ) as u16
|
||||
];
|
||||
let get_clip_area = |t: usize, s: usize| [
|
||||
scenes_w + area.x() + cols[t].1 as u16,
|
||||
header_h + area.y() + (rows[s].1/PPQ) as u16,
|
||||
cols[t].0 as u16,
|
||||
(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 = TuiTheme::border_bg();
|
||||
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);
|
||||
}
|
||||
Ok(if focused {
|
||||
to.render_in(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) }, &CORNERS)?
|
||||
})
|
||||
}))
|
||||
}));
|
||||
let color = TuiTheme::title_fg(view.arranger_focused());
|
||||
let size = format!("{}x{}", view.size.w(), view.size.h());
|
||||
let lower_right = Tui::at_se(Tui::fill_xy(Tui::pull_x(1, Tui::fg(color, size))));
|
||||
lay!(arrangement, lower_right)
|
||||
lay!([
|
||||
Tui::bg(bg.rgb, lay!(![
|
||||
ArrangerVerticalColumnSeparator::from(view),
|
||||
ArrangerVerticalRowSeparator::from((view, factor)),
|
||||
col!(![header, content]),
|
||||
ArrangerCursor::from((view, factor)),
|
||||
])),
|
||||
Tui::at_se(Tui::fill_xy(Tui::pull_x(1, Tui::fg(color, format!("{}x{}", view.size.w(), view.size.h()))))),
|
||||
])
|
||||
}
|
||||
|
||||
struct ArrangerVerticalColumnSeparator {
|
||||
cols: Vec<(usize, usize)>,
|
||||
scenes_w: u16,
|
||||
sep_fg: Color,
|
||||
}
|
||||
impl From<&ArrangerTui> for ArrangerVerticalColumnSeparator {
|
||||
fn from (state: &ArrangerTui) -> Self {
|
||||
Self {
|
||||
cols: track_widths(state.tracks()),
|
||||
scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16,
|
||||
sep_fg: TuiTheme::separator_fg(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
render!(|self: ArrangerVerticalColumnSeparator|custom_render(move|to: &mut TuiOutput|{
|
||||
let style = Some(Style::default().fg(self.sep_fg));
|
||||
Ok(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);
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
struct ArrangerVerticalRowSeparator {
|
||||
rows: Vec<(usize, usize)>,
|
||||
sep_fg: Color,
|
||||
}
|
||||
impl From<(&ArrangerTui, usize)> for ArrangerVerticalRowSeparator {
|
||||
fn from ((state, factor): (&ArrangerTui, usize)) -> Self {
|
||||
Self {
|
||||
rows: ArrangerScene::ppqs(state.scenes(), factor),
|
||||
sep_fg: TuiTheme::separator_fg(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render!(|self: ArrangerVerticalRowSeparator|custom_render(move|to: &mut TuiOutput|{
|
||||
Ok(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 {
|
||||
let cell = to.buffer.get_mut(x, y);
|
||||
cell.modifier = Modifier::UNDERLINED;
|
||||
cell.underline_color = self.sep_fg;
|
||||
}
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
struct ArrangerCursor {
|
||||
cols: Vec<(usize, usize)>,
|
||||
rows: Vec<(usize, usize)>,
|
||||
focused: bool,
|
||||
selected: ArrangerSelection,
|
||||
scenes_w: u16,
|
||||
header_h: u16,
|
||||
}
|
||||
impl From<(&ArrangerTui, usize)> for ArrangerCursor {
|
||||
fn from ((state, factor): (&ArrangerTui, usize)) -> Self {
|
||||
Self {
|
||||
cols: track_widths(state.tracks()),
|
||||
rows: ArrangerScene::ppqs(state.scenes(), factor),
|
||||
focused: state.arranger_focused(),
|
||||
selected: state.selected,
|
||||
scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16,
|
||||
header_h: 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
render!(|self: ArrangerCursor|custom_render(move|to: &mut TuiOutput|{
|
||||
let area = to.area();
|
||||
let focused = self.focused;
|
||||
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(), self.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,
|
||||
self.header_h + area.y() + (self.rows[s].1/PPQ) as u16,
|
||||
self.cols[t].0 as u16,
|
||||
(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 = TuiTheme::border_bg();
|
||||
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);
|
||||
}
|
||||
Ok(if focused {
|
||||
to.render_in(if let Some(clip_area) = clip_area { clip_area }
|
||||
else if let Some(track_area) = track_area { track_area.clip_h(self.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(self.header_h) }, &CORNERS)?
|
||||
})
|
||||
}));
|
||||
|
||||
pub fn arranger_content_horizontal (
|
||||
view: &ArrangerTui,
|
||||
) -> impl Render<Tui> + use<'_> {
|
||||
|
|
|
|||
|
|
@ -63,31 +63,6 @@ render!(|self: PhraseView<'a>|{
|
|||
//now: _,
|
||||
..
|
||||
} = self;
|
||||
let upper_left = format!(
|
||||
"╭{note_hi} {note_hi_name} {}",
|
||||
phrase.as_ref().map(|p|p.read().unwrap().name.clone()).unwrap_or(String::new())
|
||||
);
|
||||
let lower_left = format!(
|
||||
"╰{note_lo} {note_lo_name}"
|
||||
);
|
||||
let mut lower_right = format!(
|
||||
" {} ", size.format()
|
||||
);
|
||||
if *focused && *entered {
|
||||
lower_right = format!("Note: {} ({}) {} {lower_right}",
|
||||
note_point, to_note_name(*note_point), pulses_to_name(*note_len)
|
||||
);
|
||||
}
|
||||
let mut upper_right = format!(
|
||||
"[{}]",
|
||||
if *entered {"■"} else {" "}
|
||||
);
|
||||
if let Some(phrase) = phrase {
|
||||
upper_right = format!("Time: {}/{} {} {upper_right}",
|
||||
time_point, phrase.read().unwrap().length, pulses_to_name(view_mode.time_zoom()),
|
||||
)
|
||||
};
|
||||
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
||||
// is it r6d that `to` is the receiver?
|
||||
let keys = move|to: &mut TuiOutput|{
|
||||
Ok(if to.area().h() >= 2 { view_mode.render_keys(to, *note_hi, *note_lo) })
|
||||
|
|
@ -124,7 +99,24 @@ render!(|self: PhraseView<'a>|{
|
|||
////}
|
||||
//Ok(())
|
||||
//};
|
||||
let indicators = lay!(|add|{
|
||||
let indicators = lay!(move|add|{
|
||||
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
||||
let upper_left = format!("╭{note_hi} {note_hi_name} {}",
|
||||
phrase.as_ref().map(|p|p.read().unwrap().name.clone()).unwrap_or(String::new())
|
||||
);
|
||||
let lower_left = format!("╰{note_lo} {note_lo_name}");
|
||||
let mut lower_right = format!(" {} ", size.format());
|
||||
if *focused && *entered {
|
||||
lower_right = format!("Note: {} ({}) {} {lower_right}",
|
||||
note_point, to_note_name(*note_point), pulses_to_name(*note_len)
|
||||
);
|
||||
}
|
||||
let mut upper_right = format!("[{}]", if *entered {"■"} else {" "});
|
||||
if let Some(phrase) = phrase {
|
||||
upper_right = format!("Time: {}/{} {} {upper_right}",
|
||||
time_point, phrase.read().unwrap().length, pulses_to_name(view_mode.time_zoom()),
|
||||
)
|
||||
};
|
||||
add(&Tui::at_nw(Tui::fg(title_color, upper_left)))?;
|
||||
add(&Tui::at_sw(Tui::fg(title_color, lower_left)))?;
|
||||
add(&Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right)))))?;
|
||||
|
|
@ -133,12 +125,15 @@ render!(|self: PhraseView<'a>|{
|
|||
});
|
||||
let content = Tui::bg(Color::Rgb(40, 50, 30), Tui::fill_x(Tui::to_east(
|
||||
Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(2))), keys))),
|
||||
Tui::fill_x(lay!(
|
||||
Tui::fill_x(lay!([
|
||||
Tui::push_y(1, Tui::fill_x(Widget::new(|to|Ok(Some(to)), notes))),
|
||||
Tui::push_y(1, Widget::new(|to|Ok(Some(to)), cursor))
|
||||
)),
|
||||
])),
|
||||
)));
|
||||
lay!(indicators, content)
|
||||
lay!([
|
||||
indicators,
|
||||
content
|
||||
])
|
||||
});
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
|
|||
|
|
@ -1,45 +1,17 @@
|
|||
use crate::*;
|
||||
|
||||
render!(|self:PhraseLength|{
|
||||
render!(|self: PhraseLength|{
|
||||
let bars = ||self.bars_string();
|
||||
let beats = ||self.beats_string();
|
||||
let ticks = ||self.ticks_string();
|
||||
row!(|add|(match self.focus {
|
||||
row!(move|add|match self.focus {
|
||||
None =>
|
||||
add(&row!(" ", bars(), "B", beats(), "b", ticks(), "T")),
|
||||
add(&row!([" ", bars(), "B", beats(), "b", ticks(), "T"])),
|
||||
Some(PhraseLengthFocus::Bar) =>
|
||||
add(&row!("[", bars(), "]", beats(), "b", ticks(), "T")),
|
||||
add(&row!(["[", bars(), "]", beats(), "b", ticks(), "T"])),
|
||||
Some(PhraseLengthFocus::Beat) =>
|
||||
add(&row!(" ", bars(), "[", beats(), "]", ticks(), "T")),
|
||||
add(&row!([" ", bars(), "[", beats(), "]", ticks(), "T"])),
|
||||
Some(PhraseLengthFocus::Tick) =>
|
||||
add(&row!(" ", bars(), "B", beats(), "[", ticks(), "]")),
|
||||
}))
|
||||
//Layers::new(move|add|{
|
||||
//match self.focus {
|
||||
//None => add(&row!(
|
||||
//" ", self.bars_string(),
|
||||
//".", self.beats_string(),
|
||||
//".", self.ticks_string(),
|
||||
//" "
|
||||
//)),
|
||||
//Some(PhraseLengthFocus::Bar) => add(&row!(
|
||||
//"[", self.bars_string(),
|
||||
//"]", self.beats_string(),
|
||||
//".", self.ticks_string(),
|
||||
//" "
|
||||
//)),
|
||||
//Some(PhraseLengthFocus::Beat) => add(&row!(
|
||||
//" ", self.bars_string(),
|
||||
//"[", self.beats_string(),
|
||||
//"]", self.ticks_string(),
|
||||
//" "
|
||||
//)),
|
||||
//Some(PhraseLengthFocus::Tick) => add(&row!(
|
||||
//" ", self.bars_string(),
|
||||
//".", self.beats_string(),
|
||||
//"[", self.ticks_string(),
|
||||
//"]"
|
||||
//)),
|
||||
//}
|
||||
//})
|
||||
add(&row!([" ", bars(), "B", beats(), "[", ticks(), "]"])),
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> {
|
|||
// TODO: Display phrases always in order of appearance
|
||||
render!(|self: PhraseListView<'a>|{
|
||||
let Self { title, focused, entered, phrases, index, mode } = self;
|
||||
let content = Stack::down(move|add|match mode {
|
||||
let content = col!(|add|match mode {
|
||||
Some(PhrasesMode::Import(_, ref browser)) => {
|
||||
add(browser)
|
||||
},
|
||||
|
|
@ -34,7 +34,7 @@ render!(|self: PhraseListView<'a>|{
|
|||
},
|
||||
_ => {
|
||||
for (i, phrase) in phrases.iter().enumerate() {
|
||||
add(&Layers::new(|add|{
|
||||
add(&lay!(|add|{
|
||||
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
|
||||
let mut length = PhraseLength::new(length, None);
|
||||
if let Some(PhrasesMode::Length(phrase, new_length, focus)) = mode {
|
||||
|
|
@ -44,7 +44,7 @@ render!(|self: PhraseListView<'a>|{
|
|||
}
|
||||
}
|
||||
let length = Tui::fill_x(Tui::at_e(length));
|
||||
let row1 = Tui::fill_x(lay!(Tui::fill_x(Tui::at_w(format!(" {i}"))), length));
|
||||
let row1 = Tui::fill_x(lay!([Tui::fill_x(Tui::at_w(format!(" {i}"))), length]));
|
||||
let mut row2 = format!(" {name}");
|
||||
if let Some(PhrasesMode::Rename(phrase, _)) = mode {
|
||||
if *focused && i == *phrase {
|
||||
|
|
@ -63,13 +63,13 @@ render!(|self: PhraseListView<'a>|{
|
|||
}
|
||||
});
|
||||
let border_color = if *focused {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
|
||||
let content = Tui::bg(Color::Rgb(28, 35, 25), Tui::fill_xy(content));
|
||||
let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
|
||||
let upper_left = format!("[{}] {title}", if *entered {"■"} else {" "});
|
||||
let upper_right = format!("({})", phrases.len());
|
||||
lay!(
|
||||
Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color)).wrap(content),
|
||||
lay!([
|
||||
Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color))
|
||||
.wrap(Tui::bg(Color::Rgb(28, 35, 25), Tui::fill_xy(content))),
|
||||
Tui::fill_xy(Tui::at_nw(Tui::push_x(1, Tui::fg(title_color, upper_left.to_string())))),
|
||||
Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right.to_string())))),
|
||||
)
|
||||
])
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ render!(|self:PhraseSelector<'a>|{
|
|||
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
|
||||
let length = PhraseLength::new(length, None);
|
||||
let length = Tui::fill_x(Tui::at_e(length));
|
||||
let row1 = Tui::fill_x(lay!(Tui::fill_x(Tui::at_w(format!(" "))), length));
|
||||
let row1 = Tui::fill_x(lay!([Tui::fill_x(Tui::at_w(format!(" "))), length]));
|
||||
let row2 = format!(" {name}");
|
||||
let row2 = Tui::bold(true, row2);
|
||||
add(&Tui::bg(color.base.rgb, Tui::fill_x(Tui::to_south(row1, row2))))?;
|
||||
|
|
|
|||
|
|
@ -2,16 +2,6 @@
|
|||
use crate::*;
|
||||
|
||||
render!(|self: SequencerTui|{
|
||||
let play = PhraseSelector::play_phrase(
|
||||
&self.player,
|
||||
self.focused() == SequencerFocus::PhrasePlay,
|
||||
self.entered()
|
||||
);
|
||||
let next = PhraseSelector::next_phrase(
|
||||
&self.player,
|
||||
self.focused() == SequencerFocus::PhraseNext,
|
||||
self.entered()
|
||||
);
|
||||
Tui::to_north(
|
||||
SequencerStatusBar::from(self),
|
||||
Tui::to_south(
|
||||
|
|
@ -19,14 +9,19 @@ render!(|self: SequencerTui|{
|
|||
Tui::min_y(
|
||||
20,
|
||||
Tui::to_east(
|
||||
20,
|
||||
Tui::to_south(
|
||||
Tui::fixed_y(4, play),
|
||||
Tui::to_south(
|
||||
Tui::fixed_y(4, next),
|
||||
PhraseListView::from(self)
|
||||
)
|
||||
),
|
||||
Tui::min_x(20, col!([
|
||||
Tui::fixed_y(4, PhraseSelector::play_phrase(
|
||||
&self.player,
|
||||
self.focused() == SequencerFocus::PhrasePlay,
|
||||
self.entered()
|
||||
)),
|
||||
Tui::fixed_y(4, PhraseSelector::next_phrase(
|
||||
&self.player,
|
||||
self.focused() == SequencerFocus::PhraseNext,
|
||||
self.entered()
|
||||
)),
|
||||
PhraseListView::from(self)
|
||||
])),
|
||||
PhraseView::from(self)
|
||||
)
|
||||
)
|
||||
|
|
@ -45,7 +40,7 @@ render!(|self: SequencerStatusBar|{
|
|||
Tui::to_east(
|
||||
Tui::bg(orange, Tui::fg(black, Tui::bold(true, self.mode))),
|
||||
Tui::bg(light, row!((prefix, hotkey, suffix) in self.help.iter() => {
|
||||
row!(" ", prefix, Tui::fg(yellow, *hotkey), suffix)
|
||||
row!([" ", prefix, Tui::fg(yellow, *hotkey), suffix])
|
||||
}))
|
||||
)
|
||||
};
|
||||
|
|
@ -55,17 +50,17 @@ render!(|self: SequencerStatusBar|{
|
|||
let cpu = &self.cpu;
|
||||
let res = &self.res;
|
||||
let size = &self.size;
|
||||
Tui::bg(dark, row!(
|
||||
Tui::bg(dark, row!([
|
||||
Tui::fg(orange, cpu),
|
||||
Tui::fg(orange, res),
|
||||
Tui::fg(orange, size),
|
||||
))
|
||||
]))
|
||||
};
|
||||
|
||||
lay!(|add|if self.width > 60 {
|
||||
add(&row!(modeline, statusbar))
|
||||
add(&row!(![modeline, statusbar]))
|
||||
} else if self.width > 0 {
|
||||
add(&col!(modeline, statusbar))
|
||||
add(&col!(![modeline, statusbar]))
|
||||
} else {
|
||||
Ok(())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub trait StatusBar: Render<Tui> {
|
|||
{
|
||||
let hotkey_fg = Self::hotkey_fg();
|
||||
row!([a, b, c] in commands.iter() => {
|
||||
row!(a, Tui::fg(hotkey_fg, Tui::bold(true, b)), c)
|
||||
row!([a, Tui::fg(hotkey_fg, Tui::bold(true, b)), c])
|
||||
})
|
||||
//Tui::reduce(commands.iter(), |prev, [a, b, c]|
|
||||
//Tui::to_east(prev,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue