border style macro

This commit is contained in:
🪞👃🪞 2024-07-09 19:58:13 +03:00
parent afa2a2fd2b
commit 117f4d5363
4 changed files with 123 additions and 139 deletions

View file

@ -9,21 +9,21 @@ extern crate clap;
extern crate jack as _jack; extern crate jack as _jack;
extern crate crossterm; extern crate crossterm;
pub mod cli; mod cli;
pub mod config; mod config;
pub mod control; mod control;
pub mod core; mod core;
pub mod model; mod model;
pub mod view; mod view;
pub mod jack; mod jack;
pub mod edn; mod edn;
use crate::{core::*, model::*}; use crate::{core::*, model::*};
/// Application entrypoint. /// Application entrypoint.
pub fn main () -> Usually<()> { fn main () -> Usually<()> {
let midi_from = ["nanoKEY Studio.*capture.*"]; let controller = ["nanoKEY Studio.*capture.*"];
let audio_into = ["Komplete.+:playback_FL", "Komplete.+:playback_FR"]; let soundsystem = ["Komplete.+:playback_FL", "Komplete.+:playback_FR"];
// Start main loop // Start main loop
App::new()?.run(Some(|app: Arc<RwLock<App>>|{ App::new()?.run(Some(|app: Arc<RwLock<App>>|{
let mut state = app.write().unwrap(); let mut state = app.write().unwrap();
@ -32,7 +32,7 @@ pub fn main () -> Usually<()> {
let client = jack.as_client(); let client = jack.as_client();
state.transport = Some(client.transport()); state.transport = Some(client.transport());
state.midi_in = Some(client.register_port("midi-in", MidiIn)?); state.midi_in = Some(client.register_port("midi-in", MidiIn)?);
let _ = midi_from controller
.iter() .iter()
.map(|name|client .map(|name|client
.ports(Some(name), None, PortFlags::empty()) .ports(Some(name), None, PortFlags::empty())
@ -45,7 +45,7 @@ pub fn main () -> Usually<()> {
}) })
.collect::<Usually<()>>()) .collect::<Usually<()>>())
.collect::<Usually<()>>()?; .collect::<Usually<()>>()?;
state.audio_outs = audio_into state.audio_outs = soundsystem
.iter() .iter()
.map(|name|client .map(|name|client
.ports(Some(name), None, PortFlags::empty()) .ports(Some(name), None, PortFlags::empty())

View file

@ -17,12 +17,11 @@ pub use self::sequencer::SequencerView;
use crate::{render, App, core::*}; use crate::{render, App, core::*};
render!(App |self, buf, area| { render!(App |self, buf, area| {
let track = self.track_cursor;
Split::down([ Split::down([
&TransportView::new(self), &TransportView::new(self),
&Split::down([ &Split::down([
&ArrangerView::new(&self, !self.arranger_mode), &ArrangerView::new(&self, !self.arranger_mode),
&If(track > 0, &Split::right([ &If(self.track_cursor > 0, &Split::right([
&ChainView::vertical(&self), &ChainView::vertical(&self),
&SequencerView::new(&self), &SequencerView::new(&self),
])) ]))

View file

@ -10,154 +10,139 @@ pub trait BorderStyle {
const SW: &'static str = ""; const SW: &'static str = "";
const W: &'static str = ""; const W: &'static str = "";
#[inline]
fn draw (&self, buf: &mut Buffer, area: Rect) { fn draw (&self, buf: &mut Buffer, area: Rect) {
self.draw_horizontal(buf, area); self.draw_horizontal(buf, area, None);
self.draw_vertical(buf, area); self.draw_vertical(buf, area, None);
self.draw_corners(buf, area); self.draw_corners(buf, area, None);
} }
fn draw_horizontal (&self, buf: &mut Buffer, area: Rect) { #[inline]
let style = self.style(); fn draw_horizontal (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) {
let style = style.or_else(||self.style_horizontal());
for x in area.x..(area.x+area.width).saturating_sub(1) { for x in area.x..(area.x+area.width).saturating_sub(1) {
Self::N.blit(buf, x, area.y, style); self.draw_north(buf, x, area.y, style);
Self::S.blit(buf, x, area.y + area.height - 1, style); self.draw_south(buf, x, (area.y + area.height).saturating_sub(1), style);
} }
} }
#[inline]
fn draw_north (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) {
Self::N.blit(buf, x, y, style);
}
#[inline]
fn draw_south (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) {
Self::S.blit(buf, x, y, style);
}
fn draw_vertical (&self, buf: &mut Buffer, area: Rect) { #[inline]
let style = self.style(); fn draw_vertical (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) {
let style = style.or_else(||self.style_vertical());
for y in area.y..(area.y+area.height).saturating_sub(1) { for y in area.y..(area.y+area.height).saturating_sub(1) {
Self::W.blit(buf, area.x, y, style); Self::W.blit(buf, area.x, y, style);
Self::E.blit(buf, area.x + area.width - 1, y, style); Self::E.blit(buf, area.x + area.width - 1, y, style);
} }
} }
fn draw_corners (&self, buf: &mut Buffer, area: Rect) { #[inline]
let style = self.style(); fn draw_corners (&self, buf: &mut Buffer, area: Rect, style: Option<Style>) {
let style = style.or_else(||self.style_corners());
Self::NW.blit(buf, area.x, area.y, style); Self::NW.blit(buf, area.x, area.y, style);
Self::NE.blit(buf, area.x + area.width - 1, area.y, style); Self::NE.blit(buf, area.x + area.width - 1, area.y, style);
Self::SW.blit(buf, area.x, area.y + area.height - 1, style); Self::SW.blit(buf, area.x, area.y + area.height - 1, style);
Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style); Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style);
} }
#[inline]
fn style (&self) -> Option<Style> { fn style (&self) -> Option<Style> {
None None
} }
#[inline]
fn style_horizontal (&self) -> Option<Style> {
self.style()
}
#[inline]
fn style_vertical (&self) -> Option<Style> {
self.style()
}
#[inline]
fn style_corners (&self) -> Option<Style> {
self.style()
}
}
macro_rules! border {
($($T:ty {
$nw:literal $n:literal $ne:literal $w:literal $e:literal $sw:literal $s:literal $se:literal
$($x:tt)*
}),+) => {
$(impl BorderStyle for $T {
const NW: &'static str = $nw;
const N: &'static str = $n;
const NE: &'static str = $ne;
const W: &'static str = $w;
const E: &'static str = $e;
const SW: &'static str = $sw;
const S: &'static str = $s;
const SE: &'static str = $se;
$($x)*
})+
}
} }
pub struct Lozenge(pub Style); pub struct Lozenge(pub Style);
pub struct LozengeV(pub Style);
impl BorderStyle for Lozenge { pub struct LozengeDotted(pub Style);
const N: &'static str = "";
const S: &'static str = "";
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "";
const E: &'static str = "";
const SE: &'static str = "";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
pub struct Quarter(pub Style); pub struct Quarter(pub Style);
impl BorderStyle for Quarter {
const N: &'static str = "";
const S: &'static str = "";
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "🮇";
const E: &'static str = "🮇";
const SE: &'static str = "🮇";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
pub struct QuarterV(pub Style); pub struct QuarterV(pub Style);
pub struct Chamfer(pub Style);
impl BorderStyle for QuarterV { border! {
const NW: &'static str = ""; Lozenge {
const W: &'static str = ""; "" "" ""
const SW: &'static str = ""; "" ""
const NE: &'static str = "🮇"; "" "" ""
const E: &'static str = "🮇"; fn style (&self) -> Option<Style> {
const SE: &'static str = "🮇"; Some(self.0)
}
fn style (&self) -> Option<Style> { },
Some(self.0) LozengeV {
"" "" ""
"" ""
"" "" ""
fn style (&self) -> Option<Style> {
Some(self.0)
}
},
LozengeDotted {
"" "" ""
"" ""
"" "" ""
fn style (&self) -> Option<Style> {
Some(self.0)
}
},
Quarter {
"" "" "🮇"
"" "🮇"
"" "" "🮇"
fn style (&self) -> Option<Style> {
Some(self.0)
}
},
QuarterV {
"" "" "🮇"
"" "🮇"
"" "" "🮇"
fn style (&self) -> Option<Style> {
Some(self.0)
}
},
Chamfer {
"🭂" "" "🭍"
"" "🮇"
"🭓" "" "🭞"
fn style (&self) -> Option<Style> {
Some(self.0)
}
} }
} }
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)
}
}
pub fn draw_box (buffer: &mut Buffer, area: Rect) -> Rect {
draw_box_styled(buffer, area, Some(Style::default().gray().dim()))
}
pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
"".blit(buffer, area.x, y, style);
"".blit(buffer, area.x + area.width - 1, y, style);
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y + area.height - 1, 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
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
"".blit(buffer, area.x, y, style);
"".blit(buffer, area.x + area.width - 1, y, style);
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y + area.height - 1, style);
area
}

View file

@ -97,8 +97,7 @@ impl<'a> ChainView<'a> {
} else { } else {
style style
}; };
lozenge_left(buf, x + x2, y, frame.height, style); LozengeV(style.unwrap_or(Style::default())).draw(buf, frame);
lozenge_right(buf, x + x2 + frame.width - 1, y, frame.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()));
@ -165,7 +164,8 @@ impl<'a> ChainView<'a> {
//} //}
} }
if frames.len() > 0 { if frames.len() > 0 {
draw_box_styled(buf, frames[track.device], selected); Lozenge(selected.unwrap_or(Style::default()))
.draw(buf, frames[track.device]);
} }
Ok((Rect { x, y: area.y, width: w, height: y - area.y }, frames)) Ok((Rect { x, y: area.y, width: w, height: y - area.y }, frames))