mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
show tracks ins and outs
This commit is contained in:
parent
45f57214f1
commit
325492ec42
2 changed files with 52 additions and 63 deletions
|
|
@ -74,11 +74,11 @@ pub struct ArrangementTrack<E: Engine> {
|
||||||
/// Name of track
|
/// Name of track
|
||||||
pub name: Arc<RwLock<String>>,
|
pub name: Arc<RwLock<String>>,
|
||||||
/// Inputs
|
/// Inputs
|
||||||
pub inputs: Vec<()>,
|
pub inputs: Vec<Port<MidiIn>>,
|
||||||
/// MIDI player/recorder
|
/// MIDI player/recorder
|
||||||
pub player: PhrasePlayer<E>,
|
pub player: PhrasePlayer<E>,
|
||||||
/// Outputs
|
/// Outputs
|
||||||
pub outputs: Vec<()>,
|
pub outputs: Vec<Port<MidiIn>>,
|
||||||
/// Preferred width of track column
|
/// Preferred width of track column
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
/// Identifying color of track
|
/// Identifying color of track
|
||||||
|
|
@ -152,9 +152,7 @@ impl<E: Engine> Arranger<E> {
|
||||||
Ok(Some(true))
|
Ok(Some(true))
|
||||||
}
|
}
|
||||||
/// Focus the editor with the current phrase
|
/// Focus the editor with the current phrase
|
||||||
pub fn show_phrase (&mut self) {
|
pub fn show_phrase (&mut self) { self.editor.show(self.arrangement.phrase().as_ref()); }
|
||||||
self.editor.show(self.arrangement.phrase().as_ref());
|
|
||||||
}
|
|
||||||
/// Focus the editor with the current phrase
|
/// Focus the editor with the current phrase
|
||||||
pub fn edit_phrase (&mut self) {
|
pub fn edit_phrase (&mut self) {
|
||||||
if self.arrangement.phrase().is_none() {
|
if self.arrangement.phrase().is_none() {
|
||||||
|
|
@ -382,18 +380,10 @@ impl<E: Engine> Arrangement<E> {
|
||||||
pub fn track_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
|
pub fn track_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
|
||||||
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
|
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
|
||||||
}
|
}
|
||||||
pub fn track_width_inc (&mut self) {
|
pub fn track_width_inc (&mut self) { self.track_mut().map(|t|t.width_inc()); }
|
||||||
self.track_mut().map(|t|t.width_inc());
|
pub fn track_width_dec (&mut self) { self.track_mut().map(|t|t.width_dec()); }
|
||||||
}
|
pub fn track_next (&mut self) { self.selected.track_next(self.tracks.len() - 1) }
|
||||||
pub fn track_width_dec (&mut self) {
|
pub fn track_prev (&mut self) { self.selected.track_prev() }
|
||||||
self.track_mut().map(|t|t.width_dec());
|
|
||||||
}
|
|
||||||
pub fn track_next (&mut self) {
|
|
||||||
self.selected.track_next(self.tracks.len() - 1)
|
|
||||||
}
|
|
||||||
pub fn track_prev (&mut self) {
|
|
||||||
self.selected.track_prev()
|
|
||||||
}
|
|
||||||
pub fn track_add (
|
pub fn track_add (
|
||||||
&mut self, name: Option<&str>, color: Option<Color>
|
&mut self, name: Option<&str>, color: Option<Color>
|
||||||
) -> Usually<&mut ArrangementTrack<E>> {
|
) -> Usually<&mut ArrangementTrack<E>> {
|
||||||
|
|
@ -460,14 +450,10 @@ impl<E: Engine> Arrangement<E> {
|
||||||
/// Methods for phrases in arrangement
|
/// Methods for phrases in arrangement
|
||||||
impl<E: Engine> Arrangement<E> {
|
impl<E: Engine> Arrangement<E> {
|
||||||
pub fn sequencer (&self) -> Option<&ArrangementTrack<E>> {
|
pub fn sequencer (&self) -> Option<&ArrangementTrack<E>> {
|
||||||
self.selected.track()
|
self.selected.track().map(|track|self.tracks.get(track)).flatten()
|
||||||
.map(|track|self.tracks.get(track))
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
pub fn sequencer_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
|
pub fn sequencer_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
|
||||||
self.selected.track()
|
self.selected.track().map(|track|self.tracks.get_mut(track)).flatten()
|
||||||
.map(|track|self.tracks.get_mut(track))
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
pub fn phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
|
pub fn phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
|
||||||
self.scene()?.clips.get(self.selected.track()?)?.clone()
|
self.scene()?.clips.get(self.selected.track()?)?.clone()
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,12 @@ impl Content for ArrangerStatusBar {
|
||||||
["", "a", "ppend"],
|
["", "a", "ppend"],
|
||||||
["", "i", "nsert"],
|
["", "i", "nsert"],
|
||||||
["", "d", "uplicate"],
|
["", "d", "uplicate"],
|
||||||
|
["", "Del", "ete"],
|
||||||
["", "c", "olor"],
|
["", "c", "olor"],
|
||||||
["re", "n", "ame"],
|
["re", "n", "ame"],
|
||||||
["leng", "t", "h"],
|
["leng", "t", "h"],
|
||||||
["", ",.", "move"],
|
["", ",.", "move"],
|
||||||
["", "+-", "resize view"],
|
["", "+-", "resize view"],
|
||||||
["", "Del", "ete"],
|
|
||||||
]),
|
]),
|
||||||
Self::PhraseView => command(&[
|
Self::PhraseView => command(&[
|
||||||
["", "enter", " edit"],
|
["", "enter", " edit"],
|
||||||
|
|
@ -118,7 +118,8 @@ impl Content for Arrangement<Tui> {
|
||||||
ArrangementViewMode::Vertical(factor) => add(&VerticalArranger(&self, factor)),
|
ArrangementViewMode::Vertical(factor) => add(&VerticalArranger(&self, factor)),
|
||||||
}?;
|
}?;
|
||||||
let color = if self.focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
let color = if self.focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
||||||
add(&TuiStyle::fg("Session", color).push_x(1))
|
add(&TuiStyle::fg("Session", color).push_x(1))?;
|
||||||
|
add(&self.size)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,14 +138,13 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
||||||
let border_lo = Color::Rgb(70, 80, 50);
|
let border_lo = Color::Rgb(70, 80, 50);
|
||||||
let border_fg = if self.0.focused { border_hi } else { border_lo };
|
let border_fg = if self.0.focused { border_hi } else { border_lo };
|
||||||
let border = Lozenge(Style::default().bg(border_bg).fg(border_fg));
|
let border = Lozenge(Style::default().bg(border_bg).fg(border_fg));
|
||||||
let track_title_h = 3u16;
|
let track_title_h = 2u16;
|
||||||
|
let tracks_footer = 3u16;
|
||||||
let scene_title_w = 3 + Scene::longest_name(scenes) as u16; // x of 1st track
|
let scene_title_w = 3 + Scene::longest_name(scenes) as u16; // x of 1st track
|
||||||
let content = Layers::new(move |add|{
|
let arrangement = Layers::new(move |add|{
|
||||||
let rows: &[(usize, usize)] = rows.as_ref();
|
let rows: &[(usize, usize)] = rows.as_ref();
|
||||||
let cols: &[(usize, usize)] = cols.as_ref();
|
let cols: &[(usize, usize)] = cols.as_ref();
|
||||||
let any_size = |_|Ok(Some([0,0]));
|
let any_size = |_|Ok(Some([0,0]));
|
||||||
// store render area
|
|
||||||
add(&self.0.size)?;
|
|
||||||
// column separators
|
// column separators
|
||||||
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
||||||
let area = to.area();
|
let area = to.area();
|
||||||
|
|
@ -175,6 +175,18 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
||||||
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
||||||
let name = format!("▎{}", &name[0..max_w]);
|
let name = format!("▎{}", &name[0..max_w]);
|
||||||
let name = TuiStyle::bold(name, true);
|
let name = TuiStyle::bold(name, true);
|
||||||
|
let input_name = track.inputs.get(0)
|
||||||
|
.map(|port|port.short_name())
|
||||||
|
.transpose()?
|
||||||
|
.unwrap_or("(none)".into());
|
||||||
|
let input = format!("▎i {}", input_name);
|
||||||
|
col!(name, input)
|
||||||
|
.min_xy(w as u16, track_title_h)
|
||||||
|
.bg(track.color)
|
||||||
|
.push_x(scene_title_w)
|
||||||
|
});
|
||||||
|
// track controls
|
||||||
|
let footer = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0))=>{
|
||||||
let player = &track.player;
|
let player = &track.player;
|
||||||
let clock = &player.clock;
|
let clock = &player.clock;
|
||||||
let elapsed = player.phrase.as_ref()
|
let elapsed = player.phrase.as_ref()
|
||||||
|
|
@ -185,15 +197,13 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
||||||
let until_next = player.next_phrase.as_ref()
|
let until_next = player.next_phrase.as_ref()
|
||||||
.map(|(t, _)|format!("▎-{:>}", clock.format_beats(t.load(Ordering::Relaxed))))
|
.map(|(t, _)|format!("▎-{:>}", clock.format_beats(t.load(Ordering::Relaxed))))
|
||||||
.unwrap_or(String::from("▎"));
|
.unwrap_or(String::from("▎"));
|
||||||
col!(
|
let output_name = track.outputs.get(0)
|
||||||
name,
|
.map(|port|port.short_name())
|
||||||
//"▎> 12345",
|
.transpose()?
|
||||||
//"▎< 12345",
|
.unwrap_or("(none)".into());
|
||||||
//"▎m s r o",
|
let output = format!("▎o {}", output_name);
|
||||||
elapsed,
|
col!(until_next, elapsed, output)
|
||||||
until_next
|
.min_xy(w as u16, tracks_footer)
|
||||||
)
|
|
||||||
.min_xy(w as u16, track_title_h)
|
|
||||||
.bg(track.color)
|
.bg(track.color)
|
||||||
.push_x(scene_title_w)
|
.push_x(scene_title_w)
|
||||||
});
|
});
|
||||||
|
|
@ -218,7 +228,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
||||||
add(&Background(color))
|
add(&Background(color))
|
||||||
}).fixed_xy(w, h);
|
}).fixed_xy(w, h);
|
||||||
// tracks and scenes
|
// tracks and scenes
|
||||||
add(&col!(header, col!(
|
let content = col!(
|
||||||
// scenes:
|
// scenes:
|
||||||
(scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => {
|
(scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => {
|
||||||
let height = 1.max((pulses / PPQ) as u16);
|
let height = 1.max((pulses / PPQ) as u16);
|
||||||
|
|
@ -232,23 +242,21 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
||||||
})
|
})
|
||||||
}).fixed_y(height)
|
}).fixed_y(height)
|
||||||
}
|
}
|
||||||
)))?;
|
).fixed_y((self.0.size.h() as u16).saturating_sub(track_title_h + tracks_footer + 2));
|
||||||
|
// full grid with header and footer
|
||||||
|
add(&col!(header, content, footer))?;
|
||||||
// cursor
|
// cursor
|
||||||
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
||||||
let area = to.area();
|
let area = to.area();
|
||||||
let focused = state.focused;
|
let focused = state.focused;
|
||||||
let selected = state.selected;
|
let selected = state.selected;
|
||||||
let get_track_area = |t: usize| [
|
let get_track_area = |t: usize| [
|
||||||
scene_title_w + area.x() + cols[t].1 as u16,
|
scene_title_w + area.x() + cols[t].1 as u16, area.y(),
|
||||||
area.y(),
|
cols[t].0 as u16, area.h(),
|
||||||
cols[t].0 as u16,
|
|
||||||
area.h(),
|
|
||||||
];
|
];
|
||||||
let get_scene_area = |s: usize| [
|
let get_scene_area = |s: usize| [
|
||||||
area.x(),
|
area.x(), track_title_h + area.y() + (rows[s].1 / PPQ) as u16,
|
||||||
track_title_h + area.y() + (rows[s].1 / PPQ) as u16,
|
area.w(), (rows[s].0 / PPQ) as u16
|
||||||
area.w(),
|
|
||||||
(rows[s].0 / PPQ) as u16
|
|
||||||
];
|
];
|
||||||
let get_clip_area = |t: usize, s: usize| [
|
let get_clip_area = |t: usize, s: usize| [
|
||||||
scene_title_w + area.x() + cols[t].1 as u16,
|
scene_title_w + area.x() + cols[t].1 as u16,
|
||||||
|
|
@ -286,15 +294,10 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
}).bg(bg).grow_y(1).border(border);
|
}).bg(bg).grow_y(1).border(border);
|
||||||
let title_color = if self.0.focused {
|
let color = if self.0.focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
|
||||||
Color::Rgb(150, 160, 90)
|
let size = format!("{}x{}", self.0.size.w(), self.0.size.h());
|
||||||
} else {
|
let lower_right = TuiStyle::fg(size, color).pull_x(1).align_se().fill_xy();
|
||||||
Color::Rgb(120, 130, 100)
|
lay!(arrangement, lower_right)
|
||||||
};
|
|
||||||
let [w, h] = self.0.size.wh();
|
|
||||||
let lower_right = TuiStyle::fg(format!("{w}x{h}"), title_color)
|
|
||||||
.pull_x(1).align_se().fill_xy();
|
|
||||||
lay!(content, lower_right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Content for HorizontalArranger<'a, Tui> {
|
impl<'a> Content for HorizontalArranger<'a, Tui> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue