mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
instant crash
This commit is contained in:
parent
a6643ab990
commit
2401dc8fcd
5 changed files with 105 additions and 122 deletions
|
|
@ -184,6 +184,7 @@ pub fn main () -> Usually<()> {
|
||||||
midi_buf: vec![vec![];65536],
|
midi_buf: vec![vec![];65536],
|
||||||
note_buf: vec![],
|
note_buf: vec![],
|
||||||
compact: false,
|
compact: false,
|
||||||
|
editing: true,
|
||||||
color,
|
color,
|
||||||
perf,
|
perf,
|
||||||
size,
|
size,
|
||||||
|
|
|
||||||
|
|
@ -12,42 +12,35 @@ pub trait HasEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains state for viewing and editing a phrase
|
/// Contains state for viewing and editing a phrase
|
||||||
pub struct MidiEditor {
|
pub struct MidiEditor {
|
||||||
pub mode: PianoHorizontal,
|
pub mode: PianoHorizontal,
|
||||||
pub size: Measure<TuiOut>
|
pub size: Measure<TuiOut>
|
||||||
}
|
}
|
||||||
|
|
||||||
from!(|phrase: &Arc<RwLock<MidiClip>>|MidiEditor = {
|
from!(|phrase: &Arc<RwLock<MidiClip>>|MidiEditor = {
|
||||||
let mut model = Self::from(Some(phrase.clone()));
|
let model = Self::from(Some(phrase.clone()));
|
||||||
model.redraw();
|
model.redraw();
|
||||||
model
|
model
|
||||||
});
|
});
|
||||||
|
|
||||||
from!(|phrase: Option<Arc<RwLock<MidiClip>>>|MidiEditor = {
|
from!(|phrase: Option<Arc<RwLock<MidiClip>>>|MidiEditor = {
|
||||||
let mut model = Self::default();
|
let mut model = Self::default();
|
||||||
*model.phrase_mut() = phrase;
|
*model.phrase_mut() = phrase;
|
||||||
model.redraw();
|
model.redraw();
|
||||||
model
|
model
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Default for MidiEditor {
|
impl Default for MidiEditor {
|
||||||
fn default () -> Self {
|
fn default () -> Self {
|
||||||
let mut mode = PianoHorizontal::new(None);
|
let mode = PianoHorizontal::new(None);
|
||||||
mode.redraw();
|
mode.redraw();
|
||||||
Self { mode, size: Measure::new() }
|
Self { mode, size: Measure::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
has_size!(<TuiOut>|self: MidiEditor|&self.size);
|
has_size!(<TuiOut>|self: MidiEditor|&self.size);
|
||||||
|
|
||||||
render!(TuiOut: (self: MidiEditor) => {
|
render!(TuiOut: (self: MidiEditor) => {
|
||||||
self.autoscroll();
|
self.autoscroll();
|
||||||
self.autozoom();
|
self.autozoom();
|
||||||
Fill::xy(Bsp::b(&self.size, &self.mode))
|
Fill::xy(Bsp::b(&self.size, &self.mode))
|
||||||
});
|
});
|
||||||
|
|
||||||
impl TimeRange for MidiEditor {
|
impl TimeRange for MidiEditor {
|
||||||
fn time_len (&self) -> &AtomicUsize { self.mode.time_len() }
|
fn time_len (&self) -> &AtomicUsize { self.mode.time_len() }
|
||||||
fn time_zoom (&self) -> &AtomicUsize { self.mode.time_zoom() }
|
fn time_zoom (&self) -> &AtomicUsize { self.mode.time_zoom() }
|
||||||
|
|
@ -55,42 +48,27 @@ impl TimeRange for MidiEditor {
|
||||||
fn time_start (&self) -> &AtomicUsize { self.mode.time_start() }
|
fn time_start (&self) -> &AtomicUsize { self.mode.time_start() }
|
||||||
fn time_axis (&self) -> &AtomicUsize { self.mode.time_axis() }
|
fn time_axis (&self) -> &AtomicUsize { self.mode.time_axis() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoteRange for MidiEditor {
|
impl NoteRange for MidiEditor {
|
||||||
fn note_lo (&self) -> &AtomicUsize { self.mode.note_lo() }
|
fn note_lo (&self) -> &AtomicUsize { self.mode.note_lo() }
|
||||||
fn note_axis (&self) -> &AtomicUsize { self.mode.note_axis() }
|
fn note_axis (&self) -> &AtomicUsize { self.mode.note_axis() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotePoint for MidiEditor {
|
impl NotePoint for MidiEditor {
|
||||||
fn note_len (&self) -> usize { self.mode.note_len() }
|
fn note_len (&self) -> usize { self.mode.note_len() }
|
||||||
fn set_note_len (&self, x: usize) { self.mode.set_note_len(x) }
|
fn set_note_len (&self, x: usize) { self.mode.set_note_len(x) }
|
||||||
fn note_point (&self) -> usize { self.mode.note_point() }
|
fn note_point (&self) -> usize { self.mode.note_point() }
|
||||||
fn set_note_point (&self, x: usize) { self.mode.set_note_point(x) }
|
fn set_note_point (&self, x: usize) { self.mode.set_note_point(x) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimePoint for MidiEditor {
|
impl TimePoint for MidiEditor {
|
||||||
fn time_point (&self) -> usize { self.mode.time_point() }
|
fn time_point (&self) -> usize { self.mode.time_point() }
|
||||||
fn set_time_point (&self, x: usize) { self.mode.set_time_point(x) }
|
fn set_time_point (&self, x: usize) { self.mode.set_time_point(x) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MidiViewer for MidiEditor {
|
impl MidiViewer for MidiEditor {
|
||||||
fn buffer_size (&self, phrase: &MidiClip) -> (usize, usize) {
|
fn buffer_size (&self, phrase: &MidiClip) -> (usize, usize) { self.mode.buffer_size(phrase) }
|
||||||
self.mode.buffer_size(phrase)
|
fn redraw (&self) { self.mode.redraw() }
|
||||||
}
|
fn phrase (&self) -> &Option<Arc<RwLock<MidiClip>>> { self.mode.phrase() }
|
||||||
fn redraw (&self) {
|
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> { self.mode.phrase_mut() }
|
||||||
self.mode.redraw()
|
fn set_phrase (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_phrase(p) }
|
||||||
}
|
|
||||||
fn phrase (&self) -> &Option<Arc<RwLock<MidiClip>>> {
|
|
||||||
self.mode.phrase()
|
|
||||||
}
|
|
||||||
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> {
|
|
||||||
self.mode.phrase_mut()
|
|
||||||
}
|
|
||||||
fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<MidiClip>>>) {
|
|
||||||
self.mode.set_phrase(phrase)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MidiEditor {
|
impl MidiEditor {
|
||||||
/// Put note at current position
|
/// Put note at current position
|
||||||
pub fn put_note (&mut self, advance: bool) {
|
pub fn put_note (&mut self, advance: bool) {
|
||||||
|
|
@ -136,27 +114,23 @@ impl MidiEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_status (&self) -> impl Content<TuiOut> + '_ {
|
pub fn edit_status (&self) -> impl Content<TuiOut> + '_ {
|
||||||
let (color, name, length, looped) = if let Some(phrase) = self.phrase().as_ref().map(|p|p.read().unwrap()) {
|
let (color, length) = if let Some(phrase) = self.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
(phrase.color, phrase.length)
|
||||||
} else {
|
} else {
|
||||||
(ItemPalette::from(TuiTheme::g(64)), String::new().into(), 0, false)
|
(ItemPalette::from(TuiTheme::g(64)), 0)
|
||||||
};
|
};
|
||||||
let time_point = self.time_point();
|
let time_point = self.time_point();
|
||||||
let time_start = self.time_start();
|
|
||||||
let time_end = self.time_end();
|
|
||||||
let time_axis = self.time_axis().get();
|
|
||||||
let time_zoom = self.time_zoom().get();
|
let time_zoom = self.time_zoom().get();
|
||||||
let time_lock = if self.time_lock().get() { "[lock]" } else { " " };
|
let time_lock = if self.time_lock().get() { "[lock]" } else { " " };
|
||||||
let time_field = FieldV(color, "Time", format!("{length}/{time_zoom}+{time_point} {time_lock}"));
|
|
||||||
|
|
||||||
let note_point = format!("{:>3}", self.note_point());
|
let note_point = format!("{:>3}", self.note_point());
|
||||||
let note_name = format!("{:4}", Note::pitch_to_name(self.note_point()));
|
let note_name = format!("{:4}", Note::pitch_to_name(self.note_point()));
|
||||||
let note_len = format!("{:>4}", self.note_len());;;;
|
let note_len = format!("{:>4}", self.note_len());
|
||||||
let note_field = FieldV(color, "Note", format!("{note_name} {note_point} {note_len}"));
|
Bsp::e(
|
||||||
Bsp::e(time_field, note_field,)
|
FieldV(color, "Time", format!("{length}/{time_zoom}+{time_point} {time_lock}")),
|
||||||
|
FieldV(color, "Note", format!("{note_name} {note_point} {note_len}")),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for MidiEditor {
|
impl std::fmt::Debug for MidiEditor {
|
||||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||||
f.debug_struct("MidiEditor")
|
f.debug_struct("MidiEditor")
|
||||||
|
|
@ -164,7 +138,6 @@ impl std::fmt::Debug for MidiEditor {
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum MidiEditCommand {
|
pub enum MidiEditCommand {
|
||||||
// TODO: 1-9 seek markers that by default start every 8th of the phrase
|
// TODO: 1-9 seek markers that by default start every 8th of the phrase
|
||||||
|
|
@ -179,9 +152,7 @@ pub enum MidiEditCommand {
|
||||||
SetTimeLock(bool),
|
SetTimeLock(bool),
|
||||||
Show(Option<Arc<RwLock<MidiClip>>>),
|
Show(Option<Arc<RwLock<MidiClip>>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
handle!(TuiIn: |self: MidiEditor, input|MidiEditCommand::execute_with_state(self, input.event()));
|
handle!(TuiIn: |self: MidiEditor, input|MidiEditCommand::execute_with_state(self, input.event()));
|
||||||
|
|
||||||
keymap!(KEYS_MIDI_EDITOR = |s: MidiEditor, _input: Event| MidiEditCommand {
|
keymap!(KEYS_MIDI_EDITOR = |s: MidiEditor, _input: Event| MidiEditCommand {
|
||||||
key(Up) => SetNoteCursor(s.note_point() + 1),
|
key(Up) => SetNoteCursor(s.note_point() + 1),
|
||||||
key(Char('w')) => SetNoteCursor(s.note_point() + 1),
|
key(Char('w')) => SetNoteCursor(s.note_point() + 1),
|
||||||
|
|
@ -217,13 +188,11 @@ keymap!(KEYS_MIDI_EDITOR = |s: MidiEditor, _input: Event| MidiEditCommand {
|
||||||
//// TODO: kpat!(Char('/')) => // toggle 3plet
|
//// TODO: kpat!(Char('/')) => // toggle 3plet
|
||||||
//// TODO: kpat!(Char('?')) => // toggle dotted
|
//// TODO: kpat!(Char('?')) => // toggle dotted
|
||||||
});
|
});
|
||||||
|
|
||||||
impl MidiEditor {
|
impl MidiEditor {
|
||||||
fn phrase_length (&self) -> usize {
|
fn phrase_length (&self) -> usize {
|
||||||
self.phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1)
|
self.phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command<MidiEditor> for MidiEditCommand {
|
impl Command<MidiEditor> for MidiEditCommand {
|
||||||
fn execute (self, state: &mut MidiEditor) -> Perhaps<Self> {
|
fn execute (self, state: &mut MidiEditor) -> Perhaps<Self> {
|
||||||
use MidiEditCommand::*;
|
use MidiEditCommand::*;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator<Item=(usize, u16, usize)> {
|
pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator<Item=(usize, u16, usize)> {
|
||||||
(note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n))
|
(note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n))
|
||||||
}
|
}
|
||||||
|
render!(TuiOut: (self: PianoHorizontal) => Bsp::s( // the freeze is in the piano
|
||||||
render!(TuiOut: (self: PianoHorizontal) => Bsp::s(
|
|
||||||
Fixed::y(1, Bsp::e(
|
Fixed::y(1, Bsp::e(
|
||||||
Fixed::x(self.keys_width, ""),
|
Fixed::x(self.keys_width, ""),
|
||||||
Fill::x(PianoHorizontalTimeline(self)),
|
Fill::x(PianoHorizontalTimeline(self)),
|
||||||
|
|
@ -18,7 +16,6 @@ render!(TuiOut: (self: PianoHorizontal) => Bsp::s(
|
||||||
))),
|
))),
|
||||||
)),
|
)),
|
||||||
));
|
));
|
||||||
|
|
||||||
impl PianoHorizontal {
|
impl PianoHorizontal {
|
||||||
/// Draw the piano roll foreground using full blocks on note on and half blocks on legato: █▄ █▄ █▄
|
/// Draw the piano roll foreground using full blocks on note on and half blocks on legato: █▄ █▄ █▄
|
||||||
fn draw_bg (buf: &mut BigBuffer, phrase: &MidiClip, zoom: usize, note_len: usize) {
|
fn draw_bg (buf: &mut BigBuffer, phrase: &MidiClip, zoom: usize, note_len: usize) {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ pub struct Arranger {
|
||||||
pub note_buf: Vec<u8>,
|
pub note_buf: Vec<u8>,
|
||||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||||
pub editor: MidiEditor,
|
pub editor: MidiEditor,
|
||||||
|
pub editing: bool,
|
||||||
pub perf: PerfModel,
|
pub perf: PerfModel,
|
||||||
pub compact: bool,
|
pub compact: bool,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,55 +31,6 @@ impl Arranger {
|
||||||
pub const LEFT_SEP: char = '▎';
|
pub const LEFT_SEP: char = '▎';
|
||||||
pub const TRACK_MIN_WIDTH: usize = 4;
|
pub const TRACK_MIN_WIDTH: usize = 4;
|
||||||
|
|
||||||
/// A 1-row cell.
|
|
||||||
fn cell <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
|
||||||
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Fixed::y(1, field))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A phat line
|
|
||||||
fn phat_lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
|
||||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▄")))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn phat_hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
|
||||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▀")))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A cell that is 3-row on its own, but stacks, giving (N+1)*2 rows per N cells.
|
|
||||||
fn phat_cell <T: Content<TuiOut>> (
|
|
||||||
color: ItemPalette, last: ItemPalette, field: T
|
|
||||||
) -> impl Content<TuiOut> {
|
|
||||||
Bsp::s(Self::phat_lo(color.base.rgb, last.base.rgb),
|
|
||||||
Bsp::n(Self::phat_hi(color.base.rgb, last.base.rgb),
|
|
||||||
Fixed::y(1, Fill::x(Tui::fg_bg(color.lightest.rgb, color.base.rgb, field))),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn phat_cell_3 <T: Content<TuiOut>> (
|
|
||||||
field: T, top: Color, middle: Color, bottom: Color
|
|
||||||
) -> impl Content<TuiOut> {
|
|
||||||
Bsp::s(Self::phat_lo(middle, top),
|
|
||||||
Bsp::n(Self::phat_hi(middle, bottom),
|
|
||||||
Fixed::y(1, Fill::x(Tui::bg(middle, field))),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn phat_sel_3 <T: Content<TuiOut>> (
|
|
||||||
selected: bool, field_1: T, field_2: T, top: Option<Color>, middle: Color, bottom: Color
|
|
||||||
) -> impl Content<TuiOut> {
|
|
||||||
let border = Style::default().fg(Color::Rgb(255,255,255)).bg(middle);
|
|
||||||
Either(selected,
|
|
||||||
Tui::bg(middle, Outer(border).enclose( Align::w(Bsp::s("", Bsp::s(field_1, ""))))),
|
|
||||||
Bsp::s(
|
|
||||||
Fixed::y(1, top.map(|top|Self::phat_lo(middle, top))),
|
|
||||||
Bsp::n(Self::phat_hi(middle, bottom),
|
|
||||||
Fixed::y(1, Fill::x(Tui::bg(middle, field_2))),
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn output_row_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
let fg = TuiTheme::g(192);
|
let fg = TuiTheme::g(192);
|
||||||
let bg = TuiTheme::g(48);
|
let bg = TuiTheme::g(48);
|
||||||
|
|
@ -90,7 +41,7 @@ impl Arranger {
|
||||||
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
||||||
let w = (x2 - x1) as u16;
|
let w = (x2 - x1) as u16;
|
||||||
let color: ItemPalette = track.color().dark.into();
|
let color: ItemPalette = track.color().dark.into();
|
||||||
let cell = Bsp::s(format!(" M S "), Self::phat_hi(color.dark.rgb, color.darker.rgb));
|
let cell = Bsp::s(format!(" M S "), phat_hi(color.dark.rgb, color.darker.rgb));
|
||||||
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, cell)))
|
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, cell)))
|
||||||
})).boxed()).into()
|
})).boxed()).into()
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +62,7 @@ impl Arranger {
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
});
|
});
|
||||||
let cell = Bsp::s(value, Self::phat_hi(color.dark.rgb, color.darker.rgb));
|
let cell = Bsp::s(value, phat_hi(color.dark.rgb, color.darker.rgb));
|
||||||
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
||||||
})).boxed()).into()
|
})).boxed()).into()
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +76,7 @@ impl Arranger {
|
||||||
let color: ItemPalette = track.color().dark.into();
|
let color: ItemPalette = track.color().dark.into();
|
||||||
let until_next = Self::cell(color, Tui::bold(true, Self::cell_until_next(track, &self.clock().playhead)));
|
let until_next = Self::cell(color, Tui::bold(true, Self::cell_until_next(track, &self.clock().playhead)));
|
||||||
let value = Tui::fg_bg(color.lightest.rgb, color.base.rgb, until_next);
|
let value = Tui::fg_bg(color.lightest.rgb, color.base.rgb, until_next);
|
||||||
let cell = Bsp::s(value, Self::phat_hi(color.dark.rgb, color.darker.rgb));
|
let cell = Bsp::s(value, phat_hi(color.dark.rgb, color.darker.rgb));
|
||||||
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16, cell))
|
||||||
})).boxed()).into()
|
})).boxed()).into()
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +91,7 @@ impl Arranger {
|
||||||
let name = Push::x(1, &track.name);
|
let name = Push::x(1, &track.name);
|
||||||
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16,
|
Tui::bg(color.base.rgb, map_east(x1 as u16, (x2 - x1) as u16,
|
||||||
Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
Tui::fg_bg(color.lightest.rgb, color.base.rgb,
|
||||||
Self::phat_cell(color, color.darkest.rgb.into(),
|
phat_cell(color, color.darkest.rgb.into(),
|
||||||
Tui::bold(true, name))))) })).boxed()).into()
|
Tui::bold(true, name))))) })).boxed()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,7 +121,7 @@ impl Arranger {
|
||||||
let h = (y2 - y1) as u16;
|
let h = (y2 - y1) as u16;
|
||||||
let name = format!("🭬{}", &scene.name);
|
let name = format!("🭬{}", &scene.name);
|
||||||
let color = scene.color();
|
let color = scene.color();
|
||||||
let cell = Self::phat_sel_3(
|
let cell = phat_sel_3(
|
||||||
selected_scene == Some(i),
|
selected_scene == Some(i),
|
||||||
Push::x(1, Tui::bold(true, name.clone())),
|
Push::x(1, Tui::bold(true, name.clone())),
|
||||||
Push::x(1, Tui::bold(true, name)),
|
Push::x(1, Tui::bold(true, name)),
|
||||||
|
|
@ -193,7 +144,8 @@ impl Arranger {
|
||||||
}).into()
|
}).into()
|
||||||
}
|
}
|
||||||
fn scene_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn scene_row_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
||||||
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), i| {
|
let editing = self.editing;
|
||||||
|
(move||Fixed::y(2, Map::new(||self.tracks_with_widths(), move|(_, track, x1, x2), t| {
|
||||||
let w = (x2 - x1) as u16;
|
let w = (x2 - x1) as u16;
|
||||||
let cell = Bsp::s("[Rec]", "[Mon]");
|
let cell = Bsp::s("[Rec]", "[Mon]");
|
||||||
let color: ItemPalette = track.color().dark.into();
|
let color: ItemPalette = track.color().dark.into();
|
||||||
|
|
@ -204,21 +156,38 @@ impl Arranger {
|
||||||
};
|
};
|
||||||
map_east(x1 as u16, w, Fixed::x(w, Tui::bg(Color::Rgb(0,0,0), Fill::y(Map::new(
|
map_east(x1 as u16, w, Fixed::x(w, Tui::bg(Color::Rgb(0,0,0), Fill::y(Map::new(
|
||||||
||self.scenes_with_heights(2),
|
||self.scenes_with_heights(2),
|
||||||
move|(_, scene, y1, y2), j| {
|
move|(_, scene, y1, y2), s| {
|
||||||
let h = (y2 - y1) as u16;
|
let h = (y2 - y1) as u16;
|
||||||
let color = scene.color();
|
let color = scene.color();
|
||||||
let name = "⏹ ";
|
let name = "⏹ ";
|
||||||
let cell = Self::phat_sel_3(
|
let last = last_color.read().unwrap().clone();
|
||||||
selected_track == Some(i) && selected_scene == Some(j),
|
//let cell = phat_sel_3(
|
||||||
Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
//selected_track == Some(i) && selected_scene == Some(j),
|
||||||
Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
//Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
||||||
if selected_track == Some(i) && selected_scene.map(|s|s+1) == Some(j) {
|
//Tui::fg(TuiTheme::g(64), Push::x(1, name)),
|
||||||
None
|
//if selected_track == Some(i) && selected_scene.map(|s|s+1) == Some(j) {
|
||||||
} else {
|
//None
|
||||||
Some(TuiTheme::g(32).into())
|
//} else {
|
||||||
},
|
//Some(TuiTheme::g(32).into())
|
||||||
TuiTheme::g(32).into(),
|
//},
|
||||||
TuiTheme::g(32).into(),
|
//TuiTheme::g(32).into(),
|
||||||
|
//TuiTheme::g(32).into(),
|
||||||
|
//);
|
||||||
|
let active = editing && selected_track == Some(t) && selected_scene == Some(s);
|
||||||
|
let cell = Either(active,
|
||||||
|
Thunk::new(||&self.editor),
|
||||||
|
Thunk::new(move||phat_sel_3(
|
||||||
|
selected_track == Some(t) && selected_scene == Some(s),
|
||||||
|
Tui::fg(TuiTheme::g(64), Push::x(1, Tui::bold(true, name.to_string()))),
|
||||||
|
Tui::fg(TuiTheme::g(64), Push::x(1, Tui::bold(true, name.to_string()))),
|
||||||
|
if selected_track == Some(t) && selected_scene.map(|s|s+1) == Some(s) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(TuiTheme::g(32).into())
|
||||||
|
},
|
||||||
|
TuiTheme::g(32).into(),
|
||||||
|
TuiTheme::g(32).into(),
|
||||||
|
))
|
||||||
);
|
);
|
||||||
map_south(y1 as u16, 3, Fill::x(cell))
|
map_south(y1 as u16, 3, Fill::x(cell))
|
||||||
}
|
}
|
||||||
|
|
@ -283,7 +252,8 @@ impl Arranger {
|
||||||
Map::new(||self.scenes_with_heights(1), move|(_, scene, y1, y2), i| {
|
Map::new(||self.scenes_with_heights(1), move|(_, scene, y1, y2), i| {
|
||||||
let h = (y2 - y1) as u16;
|
let h = (y2 - y1) as u16;
|
||||||
let color = scene.color();
|
let color = scene.color();
|
||||||
let cell = Fixed::y(h, Fixed::x(scenes_w, Self::cell(color, scene.name.clone())));
|
let cell = Self::cell(color, scene.name.clone());
|
||||||
|
let cell = Fixed::y(h, Fixed::x(scenes_w, cell));
|
||||||
map_south(y1 as u16, 1, cell)
|
map_south(y1 as u16, 1, cell)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -439,6 +409,51 @@ impl Arranger {
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A 1-row cell.
|
||||||
|
fn cell <T: Content<TuiOut>> (color: ItemPalette, field: T) -> impl Content<TuiOut> {
|
||||||
|
Tui::fg_bg(color.lightest.rgb, color.base.rgb, Fixed::y(1, field))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A phat line
|
||||||
|
fn phat_lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||||
|
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▄")))
|
||||||
|
}
|
||||||
|
/// A phat line
|
||||||
|
fn phat_hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||||
|
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▀")))
|
||||||
|
}
|
||||||
|
/// A cell that is 3-row on its own, but stacks, giving (N+1)*2 rows per N cells.
|
||||||
|
fn phat_cell <T: Content<TuiOut>> (
|
||||||
|
color: ItemPalette, last: ItemPalette, field: T
|
||||||
|
) -> impl Content<TuiOut> {
|
||||||
|
Bsp::s(phat_lo(color.base.rgb, last.base.rgb),
|
||||||
|
Bsp::n(phat_hi(color.base.rgb, last.base.rgb),
|
||||||
|
Fixed::y(1, Fill::x(Tui::fg_bg(color.lightest.rgb, color.base.rgb, field))),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn phat_cell_3 <T: Content<TuiOut>> (
|
||||||
|
field: T, top: Color, middle: Color, bottom: Color
|
||||||
|
) -> impl Content<TuiOut> {
|
||||||
|
Bsp::s(phat_lo(middle, top),
|
||||||
|
Bsp::n(phat_hi(middle, bottom),
|
||||||
|
Fixed::y(1, Fill::x(Tui::bg(middle, field))),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn phat_sel_3 <T: Content<TuiOut>> (
|
||||||
|
selected: bool, field_1: T, field_2: T, top: Option<Color>, middle: Color, bottom: Color
|
||||||
|
) -> impl Content<TuiOut> {
|
||||||
|
let border = Style::default().fg(Color::Rgb(255,255,255)).bg(middle);
|
||||||
|
Either(selected,
|
||||||
|
Tui::bg(middle, Outer(border).enclose( Align::w(Bsp::s("", Bsp::s(field_1, ""))))),
|
||||||
|
Bsp::s(
|
||||||
|
Fixed::y(1, top.map(|top|phat_lo(middle, top))),
|
||||||
|
Bsp::n(phat_hi(middle, bottom),
|
||||||
|
Fixed::y(1, Fill::x(Tui::bg(middle, field_2))),
|
||||||
|
)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub struct ArrangerVCursor {
|
//pub struct ArrangerVCursor {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue