mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
lozenges
This commit is contained in:
parent
3886e34519
commit
de2e2a2124
7 changed files with 119 additions and 65 deletions
|
|
@ -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()));
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
35
src/layout/lozenge.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue