This commit is contained in:
🪞👃🪞 2024-06-29 22:06:53 +03:00
parent 3886e34519
commit de2e2a2124
7 changed files with 119 additions and 65 deletions

View file

@ -70,8 +70,9 @@ pub fn render (state: &Chain, buf: &mut Buffer, area: Rect)
draw_box_styled(buf, area, selected) draw_box_styled(buf, area, selected)
}, },
ChainView::Row => { ChainView::Row => {
draw_box_styled(buf, area, selected);
let (area, areas) = Row::draw(buf, area, &state.items, 0)?; let (area, areas) = Row::draw(buf, area, &state.items, 0)?;
draw_box_styled(buf, area, selected) area
}, },
ChainView::Column => { ChainView::Column => {
draw_as_column(state, buf, area, selected)? draw_as_column(state, buf, area, selected)?
@ -124,7 +125,7 @@ pub fn draw_as_row (
x = x + 1; x = x + 1;
let mut h = 0u16; let mut h = 0u16;
let mut frames = vec![]; let mut frames = vec![];
for device in state.items.iter() { for (i, device) in state.items.iter().enumerate() {
let mut x2 = 1u16; let mut x2 = 1u16;
let mut y2 = 1u16; let mut y2 = 1u16;
for port in device.midi_ins()?.iter() { for port in device.midi_ins()?.iter() {
@ -138,7 +139,18 @@ pub fn draw_as_row (
y2 = y2 + 1; y2 = y2 + 1;
} }
let width = width.saturating_sub(x).saturating_sub(x2); let width = width.saturating_sub(x).saturating_sub(x2);
let style = Some(if i == state.focus {
if state.focused {
Style::default().green().not_dim()
} else {
Style::default().green().dim()
}
} else {
Style::default().dim()
});
lozenge_left(buf, x + x2, y, height, style);
let frame = device.render(buf, Rect { x: x + x2, y, width, height })?; let frame = device.render(buf, Rect { x: x + x2, y, width, height })?;
lozenge_right(buf, x + x2 + frame.width - 1, y, height, style);
let mut y2 = 1u16; let mut y2 = 1u16;
for port in device.midi_outs()?.iter() { for port in device.midi_outs()?.iter() {
port.blit(buf, x + x2 + frame.width, y + y2, Some(Style::default())); port.blit(buf, x + x2 + frame.width, y + y2, Some(Style::default()));

View file

@ -168,43 +168,34 @@ impl PortList for Plugin {
pub fn render (state: &Plugin, buf: &mut Buffer, area: Rect) pub fn render (state: &Plugin, buf: &mut Buffer, area: Rect)
-> Usually<Rect> -> Usually<Rect>
{ {
let Rect { x, y, width, height } = area; let Rect { x, y, height, .. } = area;
let height = height.saturating_sub(3);
let style = Style::default().gray();
let mut width = 40u16; let mut width = 40u16;
match &state.plugin { match &state.plugin {
Some(PluginKind::LV2 { portList, instance, .. }) => { Some(PluginKind::LV2 { portList, .. }) => {
for i in 0..height - 4 { //draw_box(buf, Rect { x, y, width, height });
for i in 0..height-3 {
if let Some(port) = portList.get(i as usize) { if let Some(port) = portList.get(i as usize) {
let label = &format!("C·· M·· {:25} = {:03}", port.name, port.default_value); let label = &format!("C·· M·· {:25} = {:03}", port.name, port.default_value);
width = width.max(label.len() as u16); width = width.max(label.len() as u16);
label.blit(buf, x + 2, y + 3 + i as u16, None); label.blit(buf, x + 2, y + 2 + i as u16, None);
} else { } else {
break break
} }
} }
draw_box(buf, Rect { x, y, width, height });
}, },
_ => { _ => {}
buf.set_string(x + 1, y + 3, &format!(" Parameter 1 0.0"), style);
buf.set_string(x + 1, y + 4, &format!(" Parameter 2 0.0"), style);
buf.set_string(x + 1, y + 5, &format!(" Parameter 3 0.0"), style);
buf.set_string(x + 1, y + 6, &format!(" Parameter 4 0.0"), style);
}
}; };
draw_header(state, buf, area.x, area.y, width); draw_header(state, buf, area.x, area.y, width)?;
Ok(Rect { width, ..area }) Ok(Rect { width, ..area })
} }
fn draw_header (state: &Plugin, buf: &mut Buffer, x: u16, y: u16, w: u16) -> Usually<Rect> { fn draw_header (state: &Plugin, buf: &mut Buffer, x: u16, y: u16, w: u16) -> Usually<Rect> {
let style = Style::default().gray(); let style = Style::default().gray();
buf.set_string(x + 1, y + 1, let label1 = format!(" {}", state.name);
&format!(" {}", state.name), style.white().bold()); label1.blit(buf, x + 1, y, Some(style.white().bold()));
buf.set_string(x + 13, y + 1, let label2 = format!("{}", &HELM[..(w as usize - 10).min(HELM.len())]);
&format!("{}...", &HELM[..(w as usize - 20).min(HELM.len())]), style.not_dim()); label2.blit(buf, x + 2 + label1.len() as u16, y, Some(style.not_dim()));
buf.set_string(x + 0, y + 2, Ok(Rect { x, y, width: w, height: 1 })
&format!("{}", "-".repeat(w as usize - 2)), style.dim());
Ok(Rect { x, y, width: w, height: 3 })
} }
pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> { pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {

View file

@ -52,7 +52,7 @@ impl Sampler {
samples: samples.unwrap_or(BTreeMap::new()), samples: samples.unwrap_or(BTreeMap::new()),
voices: vec![], voices: vec![],
midi_in: client.register_port("midi", ::jack::MidiIn::default())?, midi_in: client.register_port("midi", ::jack::MidiIn::default())?,
audio_ins: vec![ audio_ins: vec![
client.register_port("recL", ::jack::AudioIn::default())?, client.register_port("recL", ::jack::AudioIn::default())?,
client.register_port("recR", ::jack::AudioIn::default())?, client.register_port("recR", ::jack::AudioIn::default())?,
], ],
@ -127,7 +127,7 @@ pub fn render (state: &Sampler, buf: &mut Buffer, Rect { x, y, height, .. }: Rec
{ {
let width = 40; let width = 40;
let style = Style::default().gray(); let style = Style::default().gray();
format!(" {}", state.name).blit(buf, x+1, y, Some(style.white().bold())); format!(" {} ", state.name).blit(buf, x+1, y, Some(style.white().bold().not_dim()));
for (i, (note, sample)) in state.samples.iter().enumerate() { for (i, (note, sample)) in state.samples.iter().enumerate() {
let style = if i == state.cursor.0 { let style = if i == state.cursor.0 {
Style::default().green() Style::default().green()
@ -198,9 +198,9 @@ pub fn handle (state: &mut Sampler, event: &AppEvent) -> Usually<bool> {
Ok(handle_keymap(state, event, KEYMAP)?) Ok(handle_keymap(state, event, KEYMAP)?)
} }
pub const KEYMAP: &'static [KeyBinding<Sampler>] = keymap!(Sampler { pub const KEYMAP: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
[Up, NONE, "cursor_up", "move cursor up", cursor_up], [Up, NONE, "cursor_up", "move cursor up", cursor_up],
[Down, NONE, "cursor_down", "move cursor down", cursor_down], [Down, NONE, "cursor_down", "move cursor down", cursor_down],
[Enter, NONE, "enter", "activate", enter], [Enter, NONE, "select", "select item under cursor", select],
}); });
fn cursor_up (state: &mut Sampler) -> Usually<bool> { fn cursor_up (state: &mut Sampler) -> Usually<bool> {
state.cursor.0 = if state.cursor.0 == 0 { state.cursor.0 = if state.cursor.0 == 0 {
@ -214,6 +214,9 @@ fn cursor_down (state: &mut Sampler) -> Usually<bool> {
state.cursor.0 = (state.cursor.0 + 1) % state.samples.len(); state.cursor.0 = (state.cursor.0 + 1) % state.samples.len();
Ok(true) Ok(true)
} }
fn enter (state: &mut Sampler) -> Usually<bool> { fn select (state: &mut Sampler) -> Usually<bool> {
if let Some(sample) = state.samples.get(&u7::from_int_lossy(state.cursor.0 as u8)) {
state.voices.push(sample.play())
}
Ok(true) Ok(true)
} }

View file

@ -17,13 +17,13 @@ impl<'a> LauncherGridView<'a> {
//self.separator_h(2, false); //self.separator_h(2, false);
//self.separator_h((self.state.cursor.1 * 2) as u16, true); //self.separator_h((self.state.cursor.1 * 2) as u16, true);
//self.separator_h(((self.state.cursor.1 + 1) * 2) as u16, true); //self.separator_h(((self.state.cursor.1 + 1) * 2) as u16, true);
draw_box_styled(self.buf, self.area, Some( let style = Some(Style::default().green().dim());
if self.focused { if self.focused {
Style::default().green().dim() let Rect { x, y, width, height } = self.area;
} else { lozenge_left(self.buf, x, y, height, style);
Style::default().dim() lozenge_right(self.buf, x + width - 1, y, height, style);
} }
));
let columns = self.column_names(); let columns = self.column_names();
let mut x = self.area.x; let mut x = self.area.x;

View file

@ -52,15 +52,16 @@ impl Launcher {
let transport = client.transport(); let transport = client.transport();
let ppq = timebase.ppq() as u32; let ppq = timebase.ppq() as u32;
DynamicDevice::new(render, handle, process, Self { DynamicDevice::new(render, handle, process, Self {
name: name.into(), name: name.into(),
view: LauncherView::Tracks, view: LauncherView::Tracks,
playing: transport.query_state()?, playing: transport.query_state()?,
monitoring: true,
recording: false,
overdub: true,
transport, transport,
cursor: (0, 0), timebase: timebase.clone(),
position: 0, monitoring: true,
recording: false,
overdub: true,
cursor: (0, 0),
position: 0,
scenes: scenes.unwrap_or_else(||vec![Scene::new(&"Scene 1", &[None])]), scenes: scenes.unwrap_or_else(||vec![Scene::new(&"Scene 1", &[None])]),
tracks: if let Some(tracks) = tracks { tracks } else { vec![ tracks: if let Some(tracks) = tracks { tracks } else { vec![
Track::new("Track 1", &timebase, None, Some(vec![ Track::new("Track 1", &timebase, None, Some(vec![
@ -72,8 +73,7 @@ impl Launcher {
]))) ])))
]))?, ]))?,
] }, ] },
timebase: timebase.clone(), show_help: true,
show_help: true
}).activate(client) }).activate(client)
} }
fn cols (&self) -> usize { fn cols (&self) -> usize {
@ -181,15 +181,13 @@ pub fn render (state: &Launcher, buf: &mut Buffer, mut area: Rect) -> Usually<Re
crate::device::sequencer::draw_dub(buf, x + 26, y, state.overdub); crate::device::sequencer::draw_dub(buf, x + 26, y, state.overdub);
draw_bpm(buf, x + 33, y, state.timebase.tempo()); draw_bpm(buf, x + 33, y, state.timebase.tempo());
draw_timer(buf, x + width - 1, y, &state.timebase, state.position); draw_timer(buf, x + width - 1, y, &state.timebase, state.position);
//let separator = format!("├{}┤", "-".repeat((width - 2).into()));
//separator.blit(buf, x, y + 22, Some(Style::default().dim()));
//separator.blit(buf, x, y + 41, Some(Style::default().dim()));
let mut y = y + 1; let mut y = y + 1;
y = y + LauncherGridView::new( y = y + LauncherGridView::new(
state, buf, Rect { x, y, width, height: 8 }, state.view.is_tracks() state, buf, Rect { x, y, width, height: 8 }, state.view.is_tracks()
).draw()?.height; ).draw()?.height;
y = y + draw_section_sequencer(state, buf, Rect { x, y, width, height: 8 })?.height; y = y + draw_section_sequencer(state, buf, Rect { x, y, width, height: 8 })?.height;
y = y + draw_section_chains(state, buf, Rect { x, y, width, height: 8 })?.height; y = y + draw_section_chains(state, buf, Rect { x, y, width, height: 8 })?.height;
area.height = y;
if state.show_help { if state.show_help {
let style = Some(Style::default().bold().white().not_dim().on_black().italic()); let style = Some(Style::default().bold().white().not_dim().on_black().italic());
let hide = "[Left Right] Track [Up Down] Scene [, .] Value [F1] Toggle help "; let hide = "[Left Right] Track [Up Down] Scene [, .] Value [F1] Toggle help ";
@ -225,7 +223,8 @@ fn draw_section_sequencer (state: &Launcher, buf: &mut Buffer, area: Rect) -> Us
let view = &state.view; let view = &state.view;
match view { match view {
LauncherView::Sequencer => { LauncherView::Sequencer => {
draw_box_styled(buf, area, style); lozenge_left(buf, x, y, height, style);
lozenge_right(buf, x + width - 1, y, height, style);
}, },
_ => {}, _ => {},
}; };
@ -236,9 +235,13 @@ fn draw_section_sequencer (state: &Launcher, buf: &mut Buffer, area: Rect) -> Us
let state = track.sequencer.state(); let state = track.sequencer.state();
let zoom = state.resolution; let zoom = state.resolution;
let step = state.phrase().map(|_|tick / zoom); let steps = if let Some(_phrase) = state.phrase() {
0
} else {
0
} / 4;
crate::device::sequencer::horizontal::timer(buf, x+5, y, crate::device::sequencer::horizontal::timer(buf, x+5, y,
step.unwrap_or(0) / 4, steps,
state.steps * zoom, state.steps * zoom,
state.time_axis.0, state.time_axis.0,
state.time_axis.1 state.time_axis.1
@ -279,6 +282,14 @@ fn draw_highlight (buf: &mut Buffer, highlight: &Option<Rect>, style: Style) {
} }
fn draw_section_chains (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually<Rect> { fn draw_section_chains (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let style = Some(Style::default().green().dim()); let style = Some(Style::default().green().dim());
match state.view {
LauncherView::Chains => {
let Rect { x, y, width, height} = area;
lozenge_left(buf, x, y, height, style);
lozenge_right(buf, x + width - 1, y, height, style);
},
_ => {},
};
let chain = state.active_chain(); let chain = state.active_chain();
let plugins = if let Some(chain) = &chain { let plugins = if let Some(chain) = &chain {
let (_, plugins) = crate::device::chain::draw_as_row( let (_, plugins) = crate::device::chain::draw_as_row(
@ -294,17 +305,17 @@ fn draw_section_chains (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usual
//}, //},
//_ => {}, //_ => {},
//}; //};
draw_highlight(buf, &Some(area), match state.view { //draw_highlight(buf, &Some(area), match state.view {
LauncherView::Chains => Style::default().green().dim(), //LauncherView::Chains => Style::default().green().dim(),
_ => Style::default().dim() //_ => Style::default().dim()
}); //});
if let Some(chain) = &chain { //if let Some(chain) = &chain {
if let Some(plugin) = plugins.get(chain.focus) { //if let Some(plugin) = plugins.get(chain.focus) {
draw_highlight(buf, &Some(*plugin), match state.view { //draw_highlight(buf, &Some(*plugin), match state.view {
LauncherView::Chains => Style::default().green().not_dim(), //LauncherView::Chains => Style::default().green().not_dim(),
_ => Style::default().green().dim() //_ => Style::default().green().dim()
}); //});
} //}
} //}
Ok(area) Ok(area)
} }

35
src/layout/lozenge.rs Normal file
View file

@ -0,0 +1,35 @@
use crate::prelude::*;
const LOZENGE: [[&'static str;3];3] = [
["", "", ""],
["", " ", ""],
["", "", ""],
];
pub fn lozenge_left (buf: &mut Buffer, x: u16, y1: u16, h: u16, style: Option<Style>) {
let y2 = y1 + h;
let y3 = y2.saturating_sub(1);
for y in y1..y2 {
if y == y1 {
LOZENGE[0][0]
} else if y == y3 {
LOZENGE[2][0]
} else {
LOZENGE[1][0]
}.blit(buf, x, y, style)
}
}
pub fn lozenge_right (buf: &mut Buffer, x: u16, y1: u16, h: u16, style: Option<Style>) {
let y2 = y1 + h;
let y3 = y2.saturating_sub(1);
for y in y1..y2 {
if y == y1 {
LOZENGE[0][2]
} else if y == y3 {
LOZENGE[2][2]
} else {
LOZENGE[1][2]
}.blit(buf, x, y, style)
}
}

View file

@ -6,6 +6,8 @@ mod scroll;
pub use scroll::*; pub use scroll::*;
mod table; mod table;
pub use table::*; pub use table::*;
mod lozenge;
pub use lozenge::*;
use crate::prelude::*; use crate::prelude::*;