switch between sequences; layout unfucking

This commit is contained in:
🪞👃🪞 2024-06-21 12:57:46 +03:00
parent c18aa2cbbd
commit 185c6b5b34
7 changed files with 253 additions and 201 deletions

View file

@ -5,6 +5,14 @@ pub struct Chain {
focused: bool,
focus: usize,
items: Vec<Box<dyn Device>>,
view: ChainView
}
pub enum ChainView {
Hidden,
Compact,
Row,
Column,
}
impl Chain {
@ -14,6 +22,7 @@ impl Chain {
focused: false,
focus: 0,
items,
view: ChainView::Column
}))
}
}
@ -26,44 +35,60 @@ pub fn render (state: &Chain, buf: &mut Buffer, area: Rect)
-> Usually<Rect>
{
let Rect { x, y, .. } = area;
let area = Rect { x, y, width: 40, height: 30 };
let mut y = area.y;
buf.set_string(area.x, y, "", Style::default().black());
buf.set_string(area.x + area.width - 1, y, "", Style::default().black());
buf.set_string(area.x + 2, y, "Input...", Style::default().dim());
let mut x = 0u16;
for (i, device) in state.items.iter().enumerate() {
let result = device.render(buf, Rect {
x: area.x,
y,
width: area.width,
height: 21//area.height.saturating_sub(y)
})?;
if i == state.focus {
if state.focused {
draw_box_styled(buf, result, Some(Style::default().green().not_dim()))
} else {
draw_box_styled_dotted(buf, result, Some(Style::default().green().dim()))
};
};
//let result = Rect { x: 0, y: 0, width: result.width, height: 21 };
x = x.max(result.width);
y = y + result.height;
Ok(match state.view {
ChainView::Hidden => Rect { x, y, width: 0, height: 0 },
ChainView::Compact => {
let area = Rect { x, y, width: (state.name.len() + 4) as u16, height: 3 };
buf.set_string(area.x + 2, area.y + 1, &state.name, Style::default());
draw_box_styled(buf, area, Some(Style::default().dim()))
},
ChainView::Row => {
let (area, areas) = draw_row(&state.items, buf, area, 0)?;
draw_box_styled(buf, area, Some(Style::default().dim()))
},
ChainView::Column => {
let (area, areas) = draw_column(&state.items, buf, area, 0)?;
draw_box_styled(buf, area, Some(Style::default().dim()))
},
})
//let area = Rect { x, y, width: 40, height: 30 };
//let mut y = area.y;
//buf.set_string(area.x, y, "│", Style::default().black());
//buf.set_string(area.x + area.width - 1, y, "│", Style::default().black());
//buf.set_string(area.x + 2, y, "Input...", Style::default().dim());
//let mut x = 0u16;
//for (i, device) in state.items.iter().enumerate() {
//let result = device.render(buf, Rect {
//x: area.x,
//y,
//width: area.width,
//height: 21//area.height.saturating_sub(y)
//})?;
//if i == state.focus {
//if state.focused {
//draw_box_styled(buf, result, Some(Style::default().green().not_dim()))
//} else {
//draw_box_styled_dotted(buf, result, Some(Style::default().green().dim()))
//};
//};
////let result = Rect { x: 0, y: 0, width: result.width, height: 21 };
//x = x.max(result.width);
//y = y + result.height;
////y = y + 1;
//buf.set_string(area.x, y, "│", Style::default().black());
//buf.set_string(area.x + area.width - 1, y, "│", Style::default().black());
//buf.set_string(area.x + 2, y, " Patch in ┐ │ └ Patch out", Style::default().dim());
//y = y + 1;
buf.set_string(area.x, y, "", Style::default().black());
buf.set_string(area.x + area.width - 1, y, "", Style::default().black());
buf.set_string(area.x + 2, y, " Patch in ┐ │ └ Patch out", Style::default().dim());
y = y + 1;
//buf.set_string(area.x, y, format!("{y}---BOT---"), Style::default().red());
//buf.set_string(area.x + area.width - 1, area.y + 1, "│", Style::default().black());
//buf.set_string(area.x + 2, y, "Patch...", Style::default().dim());
}
Ok(draw_box(buf, Rect {
x: area.x,
y: area.y,
width: area.width,
height: y - area.y,
}))
////buf.set_string(area.x, y, format!("{y}---BOT---"), Style::default().red());
////buf.set_string(area.x + area.width - 1, area.y + 1, "│", Style::default().black());
////buf.set_string(area.x + 2, y, "Patch...", Style::default().dim());
//}
//Ok(draw_box(buf, Rect {
//x: area.x,
//y: area.y,
//width: area.width,
//height: y - area.y,
//}))
}
impl Focus for Chain {

View file

@ -24,8 +24,10 @@ pub struct Sequencer {
notes_on: Vec<bool>,
/// Write input to sequence.
recording: bool,
/// Sequence selector
sequence: usize,
/// Map: tick -> MIDI events at tick
sequence: Sequence,
sequences: Vec<Sequence>,
/// Don't delete when recording.
overdub: bool,
/// Play sequence to output.
@ -58,7 +60,7 @@ enum SequencerView {
impl Sequencer {
pub fn new (name: &str, timebase: &Arc<Timebase>) -> Usually<DynamicDevice<Self>> {
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
DynamicDevice::new(render, handle, process, Self {
DynamicDevice::new(render, handle, Self::process, Self {
name: name.into(),
transport: client.transport(),
timebase: timebase.clone(),
@ -69,9 +71,10 @@ impl Sequencer {
input_connect: vec!["nanoKEY Studio * (capture): *".into()],
monitoring: true,
notes_on: vec![false;128],
recording: true,
recording: false,
overdub: true,
sequence: std::collections::BTreeMap::new(),
sequence: 0,
sequences: vec![std::collections::BTreeMap::new();8],
playing: true,
output_port: client.register_port("out", MidiOut::default())?,
output_connect: vec![],
@ -83,12 +86,12 @@ impl Sequencer {
time_cursor: 0,
}).activate(client)
}
}
pub fn process (s: &mut Sequencer, _: &Client, scope: &ProcessScope) -> Control {
process_out(s, scope);
process_in(s, scope);
Control::Continue
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
process_out(self, scope);
process_in(self, scope);
Control::Continue
}
}
fn process_in (s: &mut Sequencer, scope: &ProcessScope) {
@ -100,7 +103,7 @@ fn process_in (s: &mut Sequencer, scope: &ProcessScope) {
let steps = usecs / s.timebase.usec_per_step(s.resolution as usize);
let step = steps % s.steps;
let tick = step * s.timebase.ppq() / s.resolution;
let mut sequence = &mut s.sequences[s.sequence];
for event in s.input_port.iter(scope) {
match midly::live::LiveEvent::parse(event.bytes).unwrap() {
@ -108,19 +111,21 @@ fn process_in (s: &mut Sequencer, scope: &ProcessScope) {
midly::MidiMessage::NoteOn { key, vel: _ } => {
s.notes_on[key.as_int() as usize] = true;
if s.sequence.contains_key(&(tick as u32)) {
s.sequence.get_mut(&(tick as u32)).unwrap().push(message.clone());
let contains = sequence.contains_key(&(tick as u32));
if contains {
sequence.get_mut(&(tick as u32)).unwrap().push(message.clone());
} else {
s.sequence.insert(tick as u32, vec![message.clone()]);
sequence.insert(tick as u32, vec![message.clone()]);
}
},
midly::MidiMessage::NoteOff { key, vel: _ } => {
s.notes_on[key.as_int() as usize] = false;
if s.sequence.contains_key(&(tick as u32)) {
s.sequence.get_mut(&(tick as u32)).unwrap().push(message.clone());
let contains = sequence.contains_key(&(tick as u32));
if contains {
sequence.get_mut(&(tick as u32)).unwrap().push(message.clone());
} else {
s.sequence.insert(tick as u32, vec![message.clone()]);
sequence.insert(tick as u32, vec![message.clone()]);
}
},
@ -150,7 +155,7 @@ fn process_out (s: &mut Sequencer, scope: &ProcessScope) {
);
let mut writer = s.output_port.writer(scope);
for (time, tick) in ticks.iter() {
if let Some(events) = s.sequence.get(&(*tick as u32)) {
if let Some(events) = s.sequences[s.sequence].get(&(*tick as u32)) {
for message in events.iter() {
let mut buf = vec![];
::midly::live::LiveEvent::Midi {
@ -208,47 +213,44 @@ fn draw_header (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) -> Usu
let step = beat % s.steps;
let reps = s.steps / s.resolution;
let steps = s.steps % s.resolution;
let Rect { x, y, .. } = area;
let Rect { x, y, width, .. } = area;
let style = Style::default().gray();
buf.set_string(x + 2, y + 1,
&format!("{rep}.{step:2} / {reps}.{steps}"),
style);
buf.set_string(x + 2, y + 2,
&format!("⏹ STOP"),
style);
let timer = format!("{rep}.{step:02} / {reps}.{steps}");
buf.set_string(x + width - 2 - timer.len() as u16, y + 1, &timer, style.bold().not_dim());
buf.set_string(x + 2, y + 1, &format!("⏹ STOP"), style.not_dim().white().bold());
//buf.set_string(x + 2, y + 2,
//&format!("▶ PLAY"), if s.playing {
//Style::default().green()
//} else {
//Style::default().dim()
//});
buf.set_string(x + 10, y + 2,
buf.set_string(x + 10, y + 1,
&format!("⏺ REC"), if s.recording {
Style::default().red()
} else {
Style::default().dim()
Style::default().bold().dim()
});
buf.set_string(x + 17, y + 2,
buf.set_string(x + 17, y + 1,
&format!("⏺ DUB"), if s.overdub {
Style::default().yellow()
} else {
Style::default().dim()
Style::default().bold().dim()
});
let clips = draw_clips(s, buf, area)?;
Ok(Rect { x, y, width: area.width, height: 4 })
Ok(Rect { x, y, width: area.width, height: 3 })
}
fn draw_clips (s: &Sequencer, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let Rect { x, y, .. } = area;
let style = Style::default().gray();
buf.set_string(x + 2, y + 4, &format!("{}", &s.name), style.white().bold());
buf.set_string(x + 2, y + 6, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 8, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 10, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 12, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 14, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 16, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 18, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 3, &format!("{}", &s.name), style.not_dim().bold());
buf.set_string(x + 2, y + 5, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 7, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 9, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 11, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 13, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 15, &format!("{}", &s.name), style.dim());
buf.set_string(x + 2, y + 17, &format!("{}", &s.name), style.dim());
Ok(Rect { x, y, width: 14, height: 14 })
}
@ -256,6 +258,34 @@ const KEYS_VERTICAL: [&'static str; 6] = [
"", "", "", "", "", "",
];
fn draw_keys_vertical (s: &Sequencer, buf: &mut Buffer, mut area: Rect, beat: usize) {
let ppq = s.timebase.ppq() as u32;
let Rect { x, y, .. } = area;
let (note0, note1) = s.note_axis;
for key in note0..note1 {
let x = x + 5 + key - note0;
if key % 12 == 0 {
let octave = format!("C{}", (key / 12) as i8 - 4);
buf.set_string(x, y, &octave, Style::default());
}
let mut color = KEY_STYLE[key as usize % 12];
let mut is_on = s.notes_on[key as usize];
let step = beat % s.steps;
let (a, b, c) = (
(step + 0) as u32 * ppq / s.resolution as u32,
(step + 1) as u32 * ppq / s.resolution as u32,
(step + 2) as u32 * ppq / s.resolution as u32,
);
let key = ::midly::num::u7::from(key as u8);
is_on = is_on || contains_note_on(&s.sequences[s.sequence], key, a, b);
is_on = is_on || contains_note_on(&s.sequences[s.sequence], key, b, c);
if is_on {
color = Style::default().red();
}
buf.set_string(x, y - 1, &format!(""), color);
}
}
fn draw_vertical (s: &Sequencer, buf: &mut Buffer, mut area: Rect, beat: usize) -> Usually<Rect> {
let ppq = s.timebase.ppq() as u32;
area.x = area.x + 13;
@ -264,28 +294,7 @@ fn draw_vertical (s: &Sequencer, buf: &mut Buffer, mut area: Rect, beat: usize)
let (note0, note1) = s.note_axis;
let bw = Style::default().dim().on_black();
let bg = Style::default().on_black();
for key in note0..note1 {
let x = x + 5 + key - note0;
if key % 12 == 0 {
let octave = format!("C{}", (key / 12) as i8 - 4);
buf.set_string(x, y, &octave, Style::default());
}
let mut color = KEY_HORIZONTAL_STYLE[key as usize % 12];
let mut is_on = s.notes_on[key as usize];
let step = beat % s.steps;
let (a, b, c) = (
(step + 0) as u32 * ppq / s.resolution as u32,
(step + 1) as u32 * ppq / s.resolution as u32,
(step + 2) as u32 * ppq / s.resolution as u32,
);
let key = ::midly::num::u7::from(key as u8);
is_on = is_on || contains_note_on(&s.sequence, key, a, b);
is_on = is_on || contains_note_on(&s.sequence, key, b, c);
if is_on {
color = Style::default().red();
}
buf.set_string(x, y - 1, &format!(""), color);
}
draw_keys_vertical(s, buf, area, beat);
for step in time0..time1 {
let y = y - time0 + step / 2;
let step = step as usize;
@ -302,8 +311,8 @@ fn draw_vertical (s: &Sequencer, buf: &mut Buffer, mut area: Rect, beat: usize)
(step + 2) as u32 * ppq / s.resolution as u32,
);
let (character, style) = match (
contains_note_on(&s.sequence, key, a, b),
contains_note_on(&s.sequence, key, b, c),
contains_note_on(&s.sequences[s.sequence], key, a, b),
contains_note_on(&s.sequences[s.sequence], key, b, c),
) {
(true, true) => ("", bg),
(true, false) => ("", bg),
@ -319,7 +328,7 @@ fn draw_vertical (s: &Sequencer, buf: &mut Buffer, mut area: Rect, beat: usize)
let _color = if s.notes_on[key as usize] {
Style::default().red()
} else {
KEY_HORIZONTAL_STYLE[key as usize % 12]
KEY_STYLE[key as usize % 12]
};
}
}
@ -341,7 +350,7 @@ fn draw_vertical (s: &Sequencer, buf: &mut Buffer, mut area: Rect, beat: usize)
if s.time_cursor % 2 == 0 { "" } else { "" },
Style::default()
);
Ok(Rect { x, y, width: area.width, height })
Ok(Rect { x, y, width: area.width, height: height + 3 })
}
fn contains_note_on (sequence: &Sequence, k: ::midly::num::u7, start: u32, end: u32) -> bool {
@ -377,16 +386,15 @@ const KEY_BLACK: Style = Style {
sub_modifier: ::ratatui::style::Modifier::empty(),
};
const KEY_HORIZONTAL_STYLE: [Style;12] = [
const KEY_STYLE: [Style;12] = [
KEY_WHITE, KEY_BLACK, KEY_WHITE, KEY_BLACK, KEY_WHITE,
KEY_WHITE, KEY_BLACK, KEY_WHITE, KEY_BLACK, KEY_WHITE, KEY_BLACK, KEY_WHITE,
];
fn draw_horizontal (s: &Sequencer, buf: &mut Buffer, mut area: Rect) -> Usually<Rect> {
area.x = area.x + 13;
fn draw_keys_horizontal (s: &Sequencer, buf: &mut Buffer, mut area: Rect) -> Usually<Rect> {
let Rect { x, y, .. } = area;
let (time0, time1) = s.time_axis;
let (note0, note1) = s.note_axis;
let (time0, time1) = s.time_axis;
let bw = Style::default().dim();
let bg = Style::default().on_black();
for i in 0..32.max(note1-note0)/2 {
@ -396,13 +404,24 @@ fn draw_horizontal (s: &Sequencer, buf: &mut Buffer, mut area: Rect) -> Usually<
buf.set_string(x + 6, y, &"·".repeat((time1 - time0) as usize), bg.dim());
if i % 6 == 0 {
let octave = format!("C{}", ((note1 - i) / 6) as i8 - 4);
buf.set_string(x+5, y, &octave, Style::default());
buf.set_string(x + 4, y, &octave, Style::default());
}
}
Ok(area)
}
fn draw_horizontal (s: &Sequencer, buf: &mut Buffer, mut area: Rect) -> Usually<Rect> {
area.x = area.x + 13;
let Rect { x, y, .. } = area;
let (time0, time1) = s.time_axis;
let (note0, note1) = s.note_axis;
let bw = Style::default().dim();
let bg = Style::default().on_black();
draw_keys_horizontal(s, buf, area)?;
for step in time0..time1 {
let time_start = step as u32 * s.timebase.ppq() as u32;
let time_end = (step + 1) as u32 * s.timebase.ppq() as u32;
for (_, (_, events)) in s.sequence.range(time_start..time_end).enumerate() {
for (_, (_, events)) in s.sequences[s.sequence].range(time_start..time_end).enumerate() {
if events.len() > 0 {
buf.set_string(x + 5 + step as u16, y, "", bw);
}
@ -420,7 +439,7 @@ fn draw_horizontal (s: &Sequencer, buf: &mut Buffer, mut area: Rect) -> Usually<
s.time_axis.1,
), Style::default().dim());
buf.set_string(
x + 5 + s.time_cursor,
x + 6 + s.time_cursor,
y + s.note_cursor / 2,
if s.note_cursor % 2 == 0 { "" } else { "" },
Style::default()
@ -460,9 +479,24 @@ pub const KEYMAP: &'static [KeyBinding<Sequencer>] = keymap!(Sequencer {
[Char('n'), NONE, "note_axis", "Focus note axis", nop],
[Char('t'), NONE, "time_axis", "Focus time axis", nop],
[Char('v'), NONE, "variations", "Focus variation selector", nop],
[Char('s'), SHIFT, "sync", "Focus sync selector", nop]
[Char('s'), SHIFT, "sync", "Focus sync selector", nop],
[Char('1'), NONE, "focus_1", "Sequence 1", focus_seq(0)],
[Char('2'), NONE, "focus_1", "Sequence 1", focus_seq(1)],
[Char('3'), NONE, "focus_1", "Sequence 1", focus_seq(2)],
[Char('4'), NONE, "focus_1", "Sequence 1", focus_seq(3)],
[Char('5'), NONE, "focus_1", "Sequence 1", focus_seq(4)],
[Char('6'), NONE, "focus_1", "Sequence 1", focus_seq(5)],
[Char('7'), NONE, "focus_1", "Sequence 1", focus_seq(6)],
[Char('8'), NONE, "focus_1", "Sequence 1", focus_seq(7)],
});
const fn focus_seq (i: usize) -> impl Fn(&mut Sequencer)->Usually<bool> {
move |s: &mut Sequencer| {
s.sequence = i;
Ok(true)
}
}
fn nop (_: &mut Sequencer) -> Usually<bool> {
Ok(false)
}
@ -475,15 +509,16 @@ fn note_add (s: &mut Sequencer) -> Usually<bool> {
let key = ::midly::num::u7::from_int_lossy((s.note_cursor + s.note_axis.0) as u8);
let note_on = ::midly::MidiMessage::NoteOn { key, vel: 100.into() };
let note_off = ::midly::MidiMessage::NoteOff { key, vel: 100.into() };
if s.sequence.contains_key(&start) {
s.sequence.get_mut(&start).unwrap().push(note_on.clone());
let mut sequence = &mut s.sequences[s.sequence];
if sequence.contains_key(&start) {
sequence.get_mut(&start).unwrap().push(note_on.clone());
} else {
s.sequence.insert(start, vec![note_on]);
sequence.insert(start, vec![note_on]);
}
if s.sequence.contains_key(&end) {
s.sequence.get_mut(&end).unwrap().push(note_off.clone());
if sequence.contains_key(&end) {
sequence.get_mut(&end).unwrap().push(note_off.clone());
} else {
s.sequence.insert(end, vec![note_off]);
sequence.insert(end, vec![note_off]);
};
Ok(true)
}

View file

@ -38,54 +38,6 @@ pub fn draw_leaf (buffer: &mut Buffer, area: Rect, y: u16, x: u16, text: &str) {
buffer.set_string(area.x + x, area.y + 1 + y, bottom, border);
}
pub fn draw_box (buffer: &mut Buffer, area: Rect) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let border = Style::default().gray().dim();
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, border);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), border);
buffer.set_string(area.x + area.width - 1, y, format!(""), border);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, border);
area
}
pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let style = style.unwrap_or(Style::default());
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), style);
buffer.set_string(area.x + area.width - 1, y, format!(""), style);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, style);
area
}
pub fn draw_box_styled_dotted (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let style = style.unwrap_or(Style::default());
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), style);
buffer.set_string(area.x + area.width - 1, y, format!(""), style);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, style);
area
}
pub fn draw_corners (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
let style = style.unwrap_or(Style::default());
buffer.set_string(area.x, area.y, "", style);

View file

@ -1,5 +1,53 @@
use crate::prelude::*;
pub fn draw_box (buffer: &mut Buffer, area: Rect) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let border = Style::default().gray().dim();
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, border);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), border);
buffer.set_string(area.x + area.width - 1, y, format!(""), border);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, border);
area
}
pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let style = style.unwrap_or(Style::default());
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), style);
buffer.set_string(area.x + area.width - 1, y, format!(""), style);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, style);
area
}
pub fn draw_box_styled_dotted (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let style = style.unwrap_or(Style::default());
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), style);
buffer.set_string(area.x + area.width - 1, y, format!(""), style);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, style);
area
}
pub struct Column(pub Vec<Box<dyn Device>>);
impl Column {
@ -18,24 +66,25 @@ impl Row {
impl Device for Column {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
Ok(render_column(&self.0, buf, area)?.0)
Ok(draw_column(&self.0, buf, area, 0)?.0)
}
}
impl Device for Row {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
Ok(render_row(&self.0, buf, area)?.0)
Ok(draw_row(&self.0, buf, area, 0)?.0)
}
}
pub fn render_column (items: &[Box<dyn Device>], buf: &mut Buffer, area: Rect)
pub fn draw_column (items: &[Box<dyn Device>], buf: &mut Buffer, area: Rect, space: i16)
-> Usually<(Rect, Vec<Rect>)>
{
let mut w = 0u16;
let mut h = 0u16;
let mut rects = vec![];
for (i, device) in items.iter().enumerate() {
let rect = Rect { x: area.x, y: area.y + h, width: area.width, height: area.height - h };
let y = ((area.y + h) as i16).saturating_add(space) as u16;
let rect = Rect { x: area.x, y, width: area.width, height: area.height - h };
let result = device.render(buf, rect)?;
rects.push(result);
w = w.max(result.width);
@ -44,14 +93,15 @@ pub fn render_column (items: &[Box<dyn Device>], buf: &mut Buffer, area: Rect)
Ok((Rect { x: area.x, y: area.y, width: w, height: h }, rects))
}
pub fn render_row (items: &[Box<dyn Device>], buf: &mut Buffer, area: Rect)
pub fn draw_row (items: &[Box<dyn Device>], buf: &mut Buffer, area: Rect, space: i16)
-> Usually<(Rect, Vec<Rect>)>
{
let mut w = 0u16;
let mut h = 0u16;
let mut rects = vec![];
for (i, device) in items.iter().enumerate() {
let rect = Rect { x: area.x + w, y: area.y, width: area.width - w, height: area.height };
let x = ((area.x + w) as i16).saturating_add(space) as u16;
let rect = Rect { x, y: area.y, width: area.width - w, height: area.height };
let result = device.render(buf, rect)?;
rects.push(result);
w = w + result.width;

View file

@ -31,7 +31,7 @@ impl Device for FocusColumn {
handle_focus(self, event, KEYMAP_FOCUS_COLUMN)
}
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let (rect, rects) = super::render_column(self.1.0.as_ref(), buf, area, )?;
let (rect, rects) = draw_column(self.1.0.as_ref(), buf, area, 0)?;
//if i == self.focus {
//if self.focused {
//draw_box_styled(buf, result, Some(Style::default().white().not_dim()))
@ -110,23 +110,25 @@ pub struct FocusRow(pub Option<usize>, pub Row);
impl Device for FocusRow {
fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
handle_focus(self, event, keymap!(Self {
[Left, NONE, "focus_up", "focus row above",
|s: &mut Self|s.handle_focus(&FocusEvent::Backward)],
[Right, NONE, "focus_down", "focus row below",
|s: &mut Self|s.handle_focus(&FocusEvent::Forward)],
[Enter, NONE, "focus_down", "focus row below",
|s: &mut Self|s.handle_focus(&FocusEvent::Inward)],
[Esc, NONE, "focus_down", "focus row below",
|s: &mut Self|s.handle_focus(&FocusEvent::Outward)]
}))
handle_focus(self, event, KEYMAP_FOCUS_ROW)
}
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let (rect, rects) = super::render_row(&self.1.0, buf, area)?;
let (rect, rects) = draw_row(&self.1.0, buf, area, 0)?;
Ok(rect)
}
}
const KEYMAP_FOCUS_ROW: &'static [KeyBinding<FocusRow>] = keymap!(FocusRow {
[Left, NONE, "focus_up", "focus row above",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Backward)],
[Right, NONE, "focus_down", "focus row below",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Forward)],
[Enter, NONE, "focus_down", "focus row below",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Inward)],
[Esc, NONE, "focus_down", "focus row below",
|s: &mut FocusRow|s.handle_focus(&FocusEvent::Outward)]
});
impl Focus for FocusRow {
fn unfocus (&mut self) {
self.0 = None

View file

@ -20,26 +20,10 @@ fn main () -> Result<(), Box<dyn Error>> {
let _cli = cli::Cli::parse();
let xdg = microxdg::XdgApp::new("dawdle")?;
crate::config::create_dirs(&xdg)?;
//crate::device::run(Sequencer::new("Rhythm#000")?)
let transport = Transport::new("Transport")?;
let timebase = transport.state.lock().unwrap().timebase();
crate::device::run(FocusColumn(Some(0), Column::new(vec![
Box::new(transport) as Box<dyn Device>,
Box::new(Chain::new("Chain#0000", vec![
Box::new(Sequencer::new("Melody#000", &timebase)?),
Box::new(Plugin::new("Plugin#000")?),
])?),
//Box::new(Columns::new(false, vec![
//Box::new(Chain::new("Chain#00", vec![
//Box::new(Sequencer::new("Rhythm#000")?),
//Box::new(Sampler::new("Sampler#00")?),
//])?),
//Box::new(Chain::new("Chain#01", vec![
//Box::new(Sequencer::new("Melody#000")?),
//Box::new(Plugin::new("Plugin#000")?),
//])?),
//])),
//Box::new(Mixer::new("Mixer#000")?),
//Box::new(Sequencer::new("Rhythm#000")?),
])))
crate::device::run(Chain::new("Chain#0000", vec![
Box::new(Sequencer::new("Melody#000", &timebase)?),
Box::new(Plugin::new("Plugin#000")?),
])?)
}

View file

@ -17,7 +17,11 @@ pub use crate::layout::{
FocusColumn,
Focus,
FocusEvent,
handle_focus
handle_focus,
draw_box,
draw_box_styled,
draw_row,
draw_column,
};
pub use std::error::Error;