mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-09 05:06:43 +01:00
wip: tui cleanup
This commit is contained in:
parent
df3dac183e
commit
14d619a10a
17 changed files with 345 additions and 306 deletions
|
|
@ -5,3 +5,10 @@ pub trait Component<E: Engine>: Render<E> + Handle<E> {}
|
||||||
|
|
||||||
/// Everything that implements [Render] and [Handle] is a [Component].
|
/// Everything that implements [Render] and [Handle] is a [Component].
|
||||||
impl<E: Engine, C: Render<E> + Handle<E>> Component<E> for C {}
|
impl<E: Engine, C: Render<E> + Handle<E>> Component<E> for C {}
|
||||||
|
|
||||||
|
submod! {
|
||||||
|
collect
|
||||||
|
layered
|
||||||
|
offset
|
||||||
|
split
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pub enum Collected<'a, E: Engine> {
|
||||||
Box(Box<dyn Render<E> + 'a>),
|
Box(Box<dyn Render<E> + 'a>),
|
||||||
Ref(&'a (dyn Render<E> + 'a)),
|
Ref(&'a (dyn Render<E> + 'a)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine> Render<E> for Collected<'a, E> {
|
impl<'a, E: Engine> Render<E> for Collected<'a, E> {
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -12,14 +13,17 @@ impl<'a, E: Engine> Render<E> for Collected<'a, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Collection<'a, E: Engine>(
|
pub struct Collection<'a, E: Engine>(
|
||||||
pub Vec<Collected<'a, E>>
|
pub Vec<Collected<'a, E>>
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, E: Engine> Collection<'a, E> {
|
impl<'a, E: Engine> Collection<'a, E> {
|
||||||
pub fn new () -> Self {
|
pub fn new () -> Self {
|
||||||
Self(vec![])
|
Self(vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Collect<'a, E: Engine> {
|
pub trait Collect<'a, E: Engine> {
|
||||||
fn add_box (self, item: Box<dyn Render<E> + 'a>) -> Self;
|
fn add_box (self, item: Box<dyn Render<E> + 'a>) -> Self;
|
||||||
fn add_ref (self, item: &'a dyn Render<E>) -> Self;
|
fn add_ref (self, item: &'a dyn Render<E>) -> Self;
|
||||||
|
|
@ -29,6 +33,7 @@ pub trait Collect<'a, E: Engine> {
|
||||||
self.add_box(Box::new(item))
|
self.add_box(Box::new(item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
|
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
|
||||||
fn add_box (mut self, item: Box<dyn Render<E> + 'a>) -> Self {
|
fn add_box (mut self, item: Box<dyn Render<E> + 'a>) -> Self {
|
||||||
self.0.push(Collected::Box(item));
|
self.0.push(Collected::Box(item));
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub struct Layered<'a, E: Engine>(Collection<'a, E>);
|
pub struct Layered<'a, E: Engine>(pub Collection<'a, E>);
|
||||||
|
|
||||||
impl<'a, E: Engine> Layered<'a, E> {
|
impl<'a, E: Engine> Layered<'a, E> {
|
||||||
pub fn new () -> Self {
|
pub fn new () -> Self {
|
||||||
|
|
@ -18,13 +18,3 @@ impl<'a, E: Engine> Collect<'a, E> for Layered<'a, E> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Render<Tui> for Layered<'a, Tui> {
|
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
|
||||||
let area = to.area();
|
|
||||||
for layer in self.0.0.iter() {
|
|
||||||
layer.render(to)?;
|
|
||||||
}
|
|
||||||
Ok(Some(area))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
38
crates/tek_core/src/component/offset.rs
Normal file
38
crates/tek_core/src/component/offset.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use crate::*;
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
pub struct Offset<N>(pub N, pub N);
|
||||||
|
|
||||||
|
impl<N: Copy> From<N> for Offset<N> {
|
||||||
|
fn from (n: N) -> Self {
|
||||||
|
Self(n, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Inset<N>(pub N, pub N, pub N, pub N);
|
||||||
|
|
||||||
|
impl<N: Copy> From<N> for Inset<N> {
|
||||||
|
fn from (n: N) -> Self {
|
||||||
|
Self(n, n, n, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Copy> From<(N, N)> for Inset<N> {
|
||||||
|
fn from ((n1, n2): (N, N)) -> Self {
|
||||||
|
Self(n1, n2, n1, n2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Outset<N>(pub N, pub N, pub N, pub N);
|
||||||
|
|
||||||
|
impl<N: Copy> From<N> for Outset<N> {
|
||||||
|
fn from (n: N) -> Self {
|
||||||
|
Self(n, n, n, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Copy> From<(N, N)> for Outset<N> {
|
||||||
|
fn from ((n1, n2): (N, N)) -> Self {
|
||||||
|
Self(n1, n2, n1, n2)
|
||||||
|
}
|
||||||
|
}
|
||||||
50
crates/tek_core/src/component/split.rs
Normal file
50
crates/tek_core/src/component/split.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum Direction { Up, Down, Left, Right }
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
pub fn is_down (&self) -> bool {
|
||||||
|
match self { Self::Down => true, _ => false }
|
||||||
|
}
|
||||||
|
pub fn is_right (&self) -> bool {
|
||||||
|
match self { Self::Right => true, _ => false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Split<'a, E: Engine> {
|
||||||
|
items: Collection<'a, E>,
|
||||||
|
direction: Direction,
|
||||||
|
focus: Option<usize>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Engine> Split<'a, E> {
|
||||||
|
pub fn new (direction: Direction) -> Self {
|
||||||
|
Self {
|
||||||
|
items: Collection::new(),
|
||||||
|
direction,
|
||||||
|
focus: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn down () -> Self {
|
||||||
|
Self::new(Direction::Down)
|
||||||
|
}
|
||||||
|
pub fn right () -> Self {
|
||||||
|
Self::new(Direction::Right)
|
||||||
|
}
|
||||||
|
pub fn focus (mut self, focus: Option<usize>) -> Self {
|
||||||
|
self.focus = focus;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
|
||||||
|
fn add_box (mut self, item: Box<dyn Render<E> + 'a>) -> Self {
|
||||||
|
self.items = self.items.add_box(item);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn add_ref (mut self, item: &'a dyn Render<E>) -> Self {
|
||||||
|
self.items = self.items.add_ref(item);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,6 @@ use better_panic::{Settings, Verbosity};
|
||||||
}
|
}
|
||||||
|
|
||||||
submod! {
|
submod! {
|
||||||
collect
|
|
||||||
component
|
component
|
||||||
edn
|
edn
|
||||||
engine
|
engine
|
||||||
|
|
@ -40,11 +39,8 @@ submod! {
|
||||||
jack_event
|
jack_event
|
||||||
jack_ports
|
jack_ports
|
||||||
keymap
|
keymap
|
||||||
|
space
|
||||||
render
|
render
|
||||||
render_axis
|
|
||||||
render_buffer
|
|
||||||
render_layered
|
|
||||||
render_split
|
|
||||||
time
|
time
|
||||||
tui
|
tui
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct BigBuffer {
|
|
||||||
pub width: usize,
|
|
||||||
pub height: usize,
|
|
||||||
pub content: Vec<Cell>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BigBuffer {
|
|
||||||
pub fn new (width: usize, height: usize) -> Self {
|
|
||||||
Self { width, height, content: vec![Cell::default(); width*height] }
|
|
||||||
}
|
|
||||||
pub fn get (&self, x: usize, y: usize) -> Option<&Cell> {
|
|
||||||
let i = self.index_of(x, y);
|
|
||||||
self.content.get(i)
|
|
||||||
}
|
|
||||||
pub fn get_mut (&mut self, x: usize, y: usize) -> Option<&mut Cell> {
|
|
||||||
let i = self.index_of(x, y);
|
|
||||||
self.content.get_mut(i)
|
|
||||||
}
|
|
||||||
pub fn index_of (&self, x: usize, y: usize) -> usize {
|
|
||||||
y * self.width + x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum Direction {
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
Left,
|
|
||||||
Right
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Direction {
|
|
||||||
pub fn is_down (&self) -> bool {
|
|
||||||
match self { Self::Down => true, _ => false }
|
|
||||||
}
|
|
||||||
pub fn is_right (&self) -> bool {
|
|
||||||
match self { Self::Right => true, _ => false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Split<'a, E: Engine> {
|
|
||||||
items: Collection<'a, E>,
|
|
||||||
direction: Direction,
|
|
||||||
focus: Option<usize>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: Engine> Split<'a, E> {
|
|
||||||
pub fn new (direction: Direction) -> Self {
|
|
||||||
Self {
|
|
||||||
items: Collection::new(),
|
|
||||||
direction,
|
|
||||||
focus: None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn down () -> Self {
|
|
||||||
Self::new(Direction::Down)
|
|
||||||
}
|
|
||||||
pub fn right () -> Self {
|
|
||||||
Self::new(Direction::Right)
|
|
||||||
}
|
|
||||||
pub fn focus (mut self, focus: Option<usize>) -> Self {
|
|
||||||
self.focus = focus;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
|
|
||||||
fn add_box (mut self, item: Box<dyn Render<E> + 'a>) -> Self {
|
|
||||||
self.items = self.items.add_box(item);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn add_ref (mut self, item: &'a dyn Render<E>) -> Self {
|
|
||||||
self.items = self.items.add_ref(item);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Render<Tui> for Split<'a, Tui> {
|
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
|
||||||
Ok(None)//Rect::default())//Some(self.render_areas(to)?.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Split<'a, Tui> {
|
|
||||||
pub fn render_areas (&self, to: &mut Tui) -> Usually<(Rect, Vec<Rect>)> {
|
|
||||||
Ok((Rect::default(), vec![]))
|
|
||||||
//let Rect { mut x, mut y, mut width, mut height } = to.area;
|
|
||||||
//let TuiOutput { buffer, area } = to;
|
|
||||||
//let mut areas = vec![];
|
|
||||||
//for (index, item) in self.items.0.iter().enumerate() {
|
|
||||||
//if width == 0 || height == 0 {
|
|
||||||
//break
|
|
||||||
//}
|
|
||||||
//if let Some(result) = item.render(&mut TuiOutput {
|
|
||||||
//buffer: to.buffer,
|
|
||||||
//area: Rect { x, y, width, height }
|
|
||||||
//})? {
|
|
||||||
//match self.direction {
|
|
||||||
//Direction::Down => {
|
|
||||||
//y += result.height;
|
|
||||||
//height = height.saturating_sub(result.height);
|
|
||||||
//},
|
|
||||||
//Direction::Right => {
|
|
||||||
//x += result.width;
|
|
||||||
//width = width.saturating_sub(result.width);
|
|
||||||
//},
|
|
||||||
//_ => unimplemented!()
|
|
||||||
//};
|
|
||||||
//areas.push(result);
|
|
||||||
//if self.focus == Some(index) {
|
|
||||||
//Corners(Style::default().green().not_dim()).draw(to.buffer, result)?;
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//Ok((to.area, areas))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -31,3 +31,4 @@ impl<T: Copy> ScaledAxis<T> {
|
||||||
self.scale = cb(self.scale)
|
self.scale = cb(self.scale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub(crate) use ratatui::buffer::Cell;
|
pub(crate) use ratatui::buffer::Cell;
|
||||||
pub(crate) use crossterm::{ExecutableCommand};
|
pub(crate) use crossterm::{ExecutableCommand};
|
||||||
pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
|
pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
|
||||||
|
|
@ -11,7 +10,6 @@ use crossterm::terminal::{
|
||||||
EnterAlternateScreen, LeaveAlternateScreen,
|
EnterAlternateScreen, LeaveAlternateScreen,
|
||||||
enable_raw_mode, disable_raw_mode
|
enable_raw_mode, disable_raw_mode
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Tui {
|
pub struct Tui {
|
||||||
exited: Arc<AtomicBool>,
|
exited: Arc<AtomicBool>,
|
||||||
buffer: usize,
|
buffer: usize,
|
||||||
|
|
@ -28,11 +26,18 @@ impl Engine for Tui {
|
||||||
self.exited.fetch_and(true, Ordering::Relaxed)
|
self.exited.fetch_and(true, Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
fn setup (&mut self) -> Usually<()> {
|
fn setup (&mut self) -> Usually<()> {
|
||||||
panic_hook_setup();
|
let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler();
|
||||||
terminal_setup()
|
std::panic::set_hook(Box::new(move |info: &std::panic::PanicInfo|{
|
||||||
|
stdout().execute(LeaveAlternateScreen).unwrap();
|
||||||
|
disable_raw_mode().unwrap();
|
||||||
|
better_panic_handler(info);
|
||||||
|
}));
|
||||||
|
stdout().execute(EnterAlternateScreen)?;
|
||||||
|
enable_raw_mode().map_err(Into::into)
|
||||||
}
|
}
|
||||||
fn teardown (&mut self) -> Usually<()> {
|
fn teardown (&mut self) -> Usually<()> {
|
||||||
terminal_teardown()
|
stdout().execute(LeaveAlternateScreen)?;
|
||||||
|
disable_raw_mode().map_err(Into::into)
|
||||||
}
|
}
|
||||||
fn handle (&self, state: &mut impl Handle<Self>) -> Usually<()> {
|
fn handle (&self, state: &mut impl Handle<Self>) -> Usually<()> {
|
||||||
if ::crossterm::event::poll(self.poll).is_ok() {
|
if ::crossterm::event::poll(self.poll).is_ok() {
|
||||||
|
|
@ -49,6 +54,7 @@ impl Engine for Tui {
|
||||||
}
|
}
|
||||||
fn render (&mut self, state: &impl Render<Self>) -> Usually<()> {
|
fn render (&mut self, state: &impl Render<Self>) -> Usually<()> {
|
||||||
state.render(self).expect("render failed");
|
state.render(self).expect("render failed");
|
||||||
|
self.flip();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,10 +102,6 @@ impl Tui {
|
||||||
main_thread.join().expect("main thread failed");
|
main_thread.join().expect("main thread failed");
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
pub fn target <'a> (&'a mut self) -> impl TuiTarget + 'a {
|
|
||||||
let area = self.area();
|
|
||||||
(self.buffer(), area)
|
|
||||||
}
|
|
||||||
fn flip (&mut self) {
|
fn flip (&mut self) {
|
||||||
let previous_buffer = &self.buffers[1 - self.buffer];
|
let previous_buffer = &self.buffers[1 - self.buffer];
|
||||||
let current_buffer = &self.buffers[self.buffer];
|
let current_buffer = &self.buffers[self.buffer];
|
||||||
|
|
@ -108,6 +110,24 @@ impl Tui {
|
||||||
self.buffers[1 - self.buffer].reset();
|
self.buffers[1 - self.buffer].reset();
|
||||||
self.buffer = 1 - self.buffer;
|
self.buffer = 1 - self.buffer;
|
||||||
}
|
}
|
||||||
|
pub fn area (&self) -> Rect {
|
||||||
|
self.area
|
||||||
|
}
|
||||||
|
pub fn buffer (&mut self) -> &mut Buffer {
|
||||||
|
&mut self.buffers[self.buffer]
|
||||||
|
}
|
||||||
|
pub fn buffer_update (&mut self, area: Rect, callback: &impl Fn(&mut Cell, u16, u16)) {
|
||||||
|
let buf = self.buffer();
|
||||||
|
for row in 0..area.height {
|
||||||
|
let y = area.y + row;
|
||||||
|
for col in 0..area.width {
|
||||||
|
let x = area.x + col;
|
||||||
|
if x < buf.area.width && y < buf.area.height {
|
||||||
|
callback(buf.get_mut(x, y), col, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn fill_bg (&mut self, area: Rect, color: Color) {
|
pub fn fill_bg (&mut self, area: Rect, color: Color) {
|
||||||
self.buffer_update(area, &|cell,_,_|{cell.set_bg(color);})
|
self.buffer_update(area, &|cell,_,_|{cell.set_bg(color);})
|
||||||
}
|
}
|
||||||
|
|
@ -130,80 +150,24 @@ impl Tui {
|
||||||
cell.modifier = ratatui::style::Modifier::DIM;
|
cell.modifier = ratatui::style::Modifier::DIM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn buffer_update (&mut self, area: Rect, callback: &impl Fn(&mut Cell, u16, u16)) {
|
pub fn blit (
|
||||||
|
&mut self, text: &impl AsRef<str>, x: u16, y: u16, style: Option<Style>
|
||||||
|
) -> Perhaps<Rect> {
|
||||||
|
let text = text.as_ref();
|
||||||
let buf = self.buffer();
|
let buf = self.buffer();
|
||||||
for row in 0..area.height {
|
|
||||||
let y = area.y + row;
|
|
||||||
for col in 0..area.width {
|
|
||||||
let x = area.x + col;
|
|
||||||
if x < buf.area.width && y < buf.area.height {
|
|
||||||
callback(buf.get_mut(x, y), col, row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TuiTarget {
|
|
||||||
fn area (&self) -> Rect;
|
|
||||||
fn buffer (&mut self) -> &mut Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TuiTarget for Tui {
|
|
||||||
fn area (&self) -> Rect {
|
|
||||||
self.area
|
|
||||||
}
|
|
||||||
fn buffer (&mut self) -> &mut Buffer {
|
|
||||||
&mut self.buffers[self.buffer]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TuiTarget for (&'a mut Buffer, Rect) {
|
|
||||||
fn area (&self) -> Rect {
|
|
||||||
self.1
|
|
||||||
}
|
|
||||||
fn buffer (&mut self) -> &mut Buffer {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set up panic hook
|
|
||||||
pub fn panic_hook_setup () {
|
|
||||||
let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler();
|
|
||||||
std::panic::set_hook(Box::new(move |info: &std::panic::PanicInfo|{
|
|
||||||
stdout().execute(LeaveAlternateScreen).unwrap();
|
|
||||||
disable_raw_mode().unwrap();
|
|
||||||
better_panic_handler(info);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set up terminal
|
|
||||||
pub fn terminal_setup () -> Usually<()> {
|
|
||||||
stdout().execute(EnterAlternateScreen)?;
|
|
||||||
enable_raw_mode()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cleanup
|
|
||||||
pub fn terminal_teardown () -> Usually<()> {
|
|
||||||
stdout().execute(LeaveAlternateScreen)?;
|
|
||||||
disable_raw_mode()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simpler analog to [Render].
|
|
||||||
pub trait Blit {
|
|
||||||
// Render something to X, Y coordinates in a buffer, ignoring width/height.
|
|
||||||
fn blit (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) -> Perhaps<Rect>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Text can be rendered.
|
|
||||||
impl<T: AsRef<str>> Blit for T {
|
|
||||||
fn blit (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) -> Perhaps<Rect> {
|
|
||||||
if x < buf.area.width && y < buf.area.height {
|
if x < buf.area.width && y < buf.area.height {
|
||||||
buf.set_string(x, y, self.as_ref(), style.unwrap_or(Style::default()));
|
buf.set_string(x, y, text, style.unwrap_or(Style::default()));
|
||||||
}
|
}
|
||||||
Ok(Some(Rect { x, y, width: self.as_ref().len() as u16, height: 1 }))
|
Ok(Some(Rect { x, y, width: text.len() as u16, height: 1 }))
|
||||||
|
}
|
||||||
|
pub fn alter_area (
|
||||||
|
&mut self, alter: impl Fn(u16, u16, u16, u16)->(u16, u16, u16, u16)
|
||||||
|
) -> &mut Self {
|
||||||
|
let (x, y, width, height) = alter(
|
||||||
|
self.area.x, self.area.y, self.area.width, self.area.height
|
||||||
|
);
|
||||||
|
self.area = Rect { x, y, width, height };
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,28 +228,28 @@ pub trait BorderStyle {
|
||||||
let buf = to.buffer();
|
let buf = to.buffer();
|
||||||
let style = style.or_else(||self.style_horizontal());
|
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.draw_north(buf, x, area.y, style)?;
|
self.draw_north(to, x, area.y, style)?;
|
||||||
self.draw_south(buf, x, (area.y + area.height).saturating_sub(1), style)?;
|
self.draw_south(to, x, (area.y + area.height).saturating_sub(1), style)?;
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(area)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw_north (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) -> Perhaps<Rect> {
|
fn draw_north (&self, to: &mut Tui, x: u16, y: u16, style: Option<Style>) -> Perhaps<Rect> {
|
||||||
Self::N.blit(buf, x, y, style)
|
to.blit(&Self::N, x, y, style)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw_south (&self, buf: &mut Buffer, x: u16, y: u16, style: Option<Style>) -> Perhaps<Rect> {
|
fn draw_south (&self, to: &mut Tui, x: u16, y: u16, style: Option<Style>) -> Perhaps<Rect> {
|
||||||
Self::S.blit(buf, x, y, style)
|
to.blit(&Self::S, x, y, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw_vertical (&self, to: &mut Tui, style: Option<Style>) -> Usually<Rect> {
|
fn draw_vertical (&self, to: &mut Tui, style: Option<Style>) -> Usually<Rect> {
|
||||||
let area = to.area();
|
let area = to.area();
|
||||||
let buf = to.buffer();
|
|
||||||
let style = style.or_else(||self.style_vertical());
|
let style = style.or_else(||self.style_vertical());
|
||||||
for y in area.y..(area.y+area.height).saturating_sub(1) {
|
let Rect { x, y, width, height } = area;
|
||||||
Self::W.blit(buf, area.x, y, style)?;
|
for y in y..(y+height).saturating_sub(1) {
|
||||||
Self::E.blit(buf, area.x + area.width - 1, y, style)?;
|
to.blit(&Self::W, x, y, style)?;
|
||||||
|
to.blit(&Self::E, x + width - 1, y, style)?;
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(area)
|
||||||
}
|
}
|
||||||
|
|
@ -293,13 +257,13 @@ pub trait BorderStyle {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw_corners (&self, to: &mut Tui, style: Option<Style>) -> Usually<Rect> {
|
fn draw_corners (&self, to: &mut Tui, style: Option<Style>) -> Usually<Rect> {
|
||||||
let area = to.area();
|
let area = to.area();
|
||||||
let buf = to.buffer();
|
|
||||||
let style = style.or_else(||self.style_corners());
|
let style = style.or_else(||self.style_corners());
|
||||||
if area.width > 0 && area.height > 0 {
|
let Rect { x, y, width, height } = area;
|
||||||
Self::NW.blit(buf, area.x, area.y, style)?;
|
if width > 0 && height > 0 {
|
||||||
Self::NE.blit(buf, area.x + area.width - 1, area.y, style)?;
|
to.blit(&Self::NW, x, y, style)?;
|
||||||
Self::SW.blit(buf, area.x, area.y + area.height - 1, style)?;
|
to.blit(&Self::NE, x + width - 1, y, style)?;
|
||||||
Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style)?;
|
to.blit(&Self::SW, x, y + height - 1, style)?;
|
||||||
|
to.blit(&Self::SE, x + width - 1, y + height - 1, style)?;
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(area)
|
||||||
}
|
}
|
||||||
|
|
@ -556,3 +520,111 @@ pub const NOT_DIM_BOLD: Style = Style {
|
||||||
add_modifier: Modifier::BOLD,
|
add_modifier: Modifier::BOLD,
|
||||||
sub_modifier: Modifier::DIM,
|
sub_modifier: Modifier::DIM,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl<'a> Render<Tui> for Layered<'a, Tui> {
|
||||||
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
let area = to.area();
|
||||||
|
for layer in self.0.0.iter() {
|
||||||
|
layer.render(to)?;
|
||||||
|
}
|
||||||
|
Ok(Some(area))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Render<Tui> for Split<'a, Tui> {
|
||||||
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
Ok(Some(self.render_areas(to)?.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Split<'a, Tui> {
|
||||||
|
pub fn render_areas (&self, to: &mut Tui) -> Usually<(Rect, Vec<Rect>)> {
|
||||||
|
Ok((Rect::default(), vec![]))
|
||||||
|
//let Rect { mut x, mut y, mut width, mut height } = to.area;
|
||||||
|
//let TuiOutput { buffer, area } = to;
|
||||||
|
//let mut areas = vec![];
|
||||||
|
//for (index, item) in self.items.0.iter().enumerate() {
|
||||||
|
//if width == 0 || height == 0 {
|
||||||
|
//break
|
||||||
|
//}
|
||||||
|
//if let Some(result) = item.render(&mut TuiOutput {
|
||||||
|
//buffer: to.buffer,
|
||||||
|
//area: Rect { x, y, width, height }
|
||||||
|
//})? {
|
||||||
|
//match self.direction {
|
||||||
|
//Direction::Down => {
|
||||||
|
//y += result.height;
|
||||||
|
//height = height.saturating_sub(result.height);
|
||||||
|
//},
|
||||||
|
//Direction::Right => {
|
||||||
|
//x += result.width;
|
||||||
|
//width = width.saturating_sub(result.width);
|
||||||
|
//},
|
||||||
|
//_ => unimplemented!()
|
||||||
|
//};
|
||||||
|
//areas.push(result);
|
||||||
|
//if self.focus == Some(index) {
|
||||||
|
//Corners(Style::default().green().not_dim()).draw(to.buffer, result)?;
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//Ok((to.area, areas))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct BigBuffer {
|
||||||
|
pub width: usize,
|
||||||
|
pub height: usize,
|
||||||
|
pub content: Vec<Cell>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BigBuffer {
|
||||||
|
pub fn new (width: usize, height: usize) -> Self {
|
||||||
|
Self { width, height, content: vec![Cell::default(); width*height] }
|
||||||
|
}
|
||||||
|
pub fn get (&self, x: usize, y: usize) -> Option<&Cell> {
|
||||||
|
let i = self.index_of(x, y);
|
||||||
|
self.content.get(i)
|
||||||
|
}
|
||||||
|
pub fn get_mut (&mut self, x: usize, y: usize) -> Option<&mut Cell> {
|
||||||
|
let i = self.index_of(x, y);
|
||||||
|
self.content.get_mut(i)
|
||||||
|
}
|
||||||
|
pub fn index_of (&self, x: usize, y: usize) -> usize {
|
||||||
|
y * self.width + x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Render<Tui>> Render<Tui> for (Offset<u16>, R) {
|
||||||
|
fn render (&self, engine: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
self.1.render(engine.alter_area(|x, y, width, height|(
|
||||||
|
x + self.0.0,
|
||||||
|
y + self.0.1,
|
||||||
|
width.saturating_sub(self.0.0),
|
||||||
|
height.saturating_sub(self.0.1),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Render<Tui>> Render<Tui> for (Inset<u16>, R) {
|
||||||
|
fn render (&self, engine: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
self.1.render(engine.alter_area(|x, y, width, height|(
|
||||||
|
x + self.0.0,
|
||||||
|
y + self.0.1,
|
||||||
|
width.saturating_sub(self.0.0 + self.0.2),
|
||||||
|
height.saturating_sub(self.0.1 + self.0.3),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Render<Tui>> Render<Tui> for (Outset<u16>, R) {
|
||||||
|
fn render (&self, engine: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
self.1.render(engine.alter_area(|x, y, width, height|(
|
||||||
|
x.saturating_sub(self.0.0),
|
||||||
|
y.saturating_sub(self.0.1),
|
||||||
|
width + self.0.0 + self.0.2,
|
||||||
|
height + self.0.1 + self.0.3,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub struct Mixer<T, U> {
|
pub struct Mixer<E> {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub tracks: Vec<Track<T, U>>,
|
pub tracks: Vec<Track<E>>,
|
||||||
pub selected_track: usize,
|
pub selected_track: usize,
|
||||||
pub selected_column: usize,
|
pub selected_column: usize,
|
||||||
}
|
}
|
||||||
impl<T, U> Mixer<T, U> {
|
impl<E> Mixer<E> {
|
||||||
pub fn new (name: &str) -> Usually<Self> {
|
pub fn new (name: &str) -> Usually<Self> {
|
||||||
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
|
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
@ -21,12 +21,17 @@ impl<T, U> Mixer<T, U> {
|
||||||
self.tracks.push(track);
|
self.tracks.push(track);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
pub fn track (&self) -> Option<&Track<T, U>> {
|
pub fn track (&self) -> Option<&Track<E>> {
|
||||||
self.tracks.get(self.selected_track)
|
self.tracks.get(self.selected_track)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for Mixer<TuiOutput<'a>, Rect> {
|
impl<E> Process for Mixer<E> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn process (&mut self, _: &Client, _: &ProcessScope) -> Control {
|
||||||
|
Control::Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Render<Tui> for Mixer<Tui> {
|
||||||
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut tracks = Split::right();
|
let mut tracks = Split::right();
|
||||||
for channel in self.tracks.iter() {
|
for channel in self.tracks.iter() {
|
||||||
tracks = tracks.add_ref(channel)
|
tracks = tracks.add_ref(channel)
|
||||||
|
|
@ -34,8 +39,3 @@ impl<'a> Render<TuiOutput<'a>, Rect> for Mixer<TuiOutput<'a>, Rect> {
|
||||||
tracks.render(to)
|
tracks.render(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T, U> Process for Mixer<T, U> {
|
|
||||||
fn process (&mut self, _: &Client, _: &ProcessScope) -> Control {
|
|
||||||
Control::Continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ pub struct Plugin {
|
||||||
}
|
}
|
||||||
handle!(Plugin |self, e| handle_keymap(self, e, KEYMAP_PLUGIN));
|
handle!(Plugin |self, e| handle_keymap(self, e, KEYMAP_PLUGIN));
|
||||||
process!(Plugin = Plugin::process);
|
process!(Plugin = Plugin::process);
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for Plugin {
|
impl Render<Tui> for Plugin {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, height, .. } = to.area;
|
let area = to.area();
|
||||||
|
let Rect { x, y, height, .. } = area;
|
||||||
let mut width = 20u16;
|
let mut width = 20u16;
|
||||||
match &self.plugin {
|
match &self.plugin {
|
||||||
Some(PluginKind::LV2(LV2Plugin { port_list, instance, .. })) => {
|
Some(PluginKind::LV2(LV2Plugin { port_list, instance, .. })) => {
|
||||||
|
|
@ -35,7 +36,7 @@ impl<'a> Render<TuiOutput<'a>, Rect> for Plugin {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
} ;
|
} ;
|
||||||
label.blit(to.buffer, x + 2, y + 1 + i as u16 - start as u16, style)?;
|
label.blit(to.buffer(), x + 2, y + 1 + i as u16 - start as u16, style)?;
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -43,8 +44,8 @@ impl<'a> Render<TuiOutput<'a>, Rect> for Plugin {
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
draw_header(self, to.buffer, to.area.x, to.area.y, width)?;
|
draw_header(self, to.buffer(), area.x, area.y, width)?;
|
||||||
Ok(Some(Rect { width, ..to.area }))
|
Ok(Some(Rect { width, ..to.area() }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +58,7 @@ pub enum PluginKind {
|
||||||
VST3,
|
VST3,
|
||||||
}
|
}
|
||||||
impl Plugin {
|
impl Plugin {
|
||||||
pub fn new_lv2 <T, U> (name: &str, path: &str) -> Usually<JackDevice<T, U>> {
|
pub fn new_lv2 <E> (name: &str, path: &str) -> Usually<JackDevice<E>> {
|
||||||
let plugin = LV2Plugin::new(path)?;
|
let plugin = LV2Plugin::new(path)?;
|
||||||
jack_from_lv2(name, &plugin.plugin)?
|
jack_from_lv2(name, &plugin.plugin)?
|
||||||
.run(|ports|Box::new(Self {
|
.run(|ports|Box::new(Self {
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ process!(Sampler = Sampler::process);
|
||||||
|
|
||||||
handle!(Sampler |self, event| handle_keymap(self, event, KEYMAP_SAMPLER));
|
handle!(Sampler |self, event| handle_keymap(self, event, KEYMAP_SAMPLER));
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for Sampler {
|
impl Render<Tui> for Sampler {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, height, .. } = to.area;
|
let Rect { x, y, height, .. } = to.area();
|
||||||
let style = Style::default().gray();
|
let style = Style::default().gray();
|
||||||
let title = format!(" {} ({})", self.name, self.voices.read().unwrap().len());
|
let title = format!(" {} ({})", self.name, self.voices.read().unwrap().len());
|
||||||
title.blit(to.buffer, x+1, y, Some(style.white().bold().not_dim()))?;
|
title.blit(to.buffer(), x+1, y, Some(style.white().bold().not_dim()))?;
|
||||||
let mut width = title.len() + 2;
|
let mut width = title.len() + 2;
|
||||||
let mut y1 = 1;
|
let mut y1 = 1;
|
||||||
let mut j = 0;
|
let mut j = 0;
|
||||||
|
|
@ -36,13 +36,13 @@ impl<'a> Render<TuiOutput<'a>, Rect> for Sampler {
|
||||||
}
|
}
|
||||||
let active = j == self.cursor.0;
|
let active = j == self.cursor.0;
|
||||||
width = width.max(
|
width = width.max(
|
||||||
draw_sample(to.buffer, x, y + y1, note, &*sample.read().unwrap(), active)?
|
draw_sample(to.buffer(), x, y + y1, note, &*sample.read().unwrap(), active)?
|
||||||
);
|
);
|
||||||
y1 = y1 + 1;
|
y1 = y1 + 1;
|
||||||
j = j + 1;
|
j = j + 1;
|
||||||
}
|
}
|
||||||
let height = ((2 + y1) as u16).min(height);
|
let height = ((2 + y1) as u16).min(height);
|
||||||
Ok(Some(Rect { x, y, width: (width as u16).min(to.area.width), height }))
|
Ok(Some(Rect { x, y, width: (width as u16).min(to.area().width), height }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,7 +105,7 @@ pub const KEYMAP_SAMPLER: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Sampler {
|
impl Sampler {
|
||||||
pub fn from_edn <'e, T, U> (args: &[Edn<'e>]) -> Usually<JackDevice<T, U>> {
|
pub fn from_edn <'e, E> (args: &[Edn<'e>]) -> Usually<JackDevice<E>> {
|
||||||
let mut name = String::new();
|
let mut name = String::new();
|
||||||
let mut dir = String::new();
|
let mut dir = String::new();
|
||||||
let mut samples = BTreeMap::new();
|
let mut samples = BTreeMap::new();
|
||||||
|
|
@ -134,9 +134,9 @@ impl Sampler {
|
||||||
Self::new(&name, Some(samples))
|
Self::new(&name, Some(samples))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new <T, U> (
|
pub fn new <E> (
|
||||||
name: &str, mapped: Option<BTreeMap<u7, Arc<RwLock<Sample>>>>
|
name: &str, mapped: Option<BTreeMap<u7, Arc<RwLock<Sample>>>>
|
||||||
) -> Usually<JackDevice<T, U>> {
|
) -> Usually<JackDevice<E>> {
|
||||||
Jack::new(name)?
|
Jack::new(name)?
|
||||||
.midi_in("midi")
|
.midi_in("midi")
|
||||||
.audio_in("recL")
|
.audio_in("recL")
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@ use tek_core::edn;
|
||||||
|
|
||||||
/// A sequencer track.
|
/// A sequencer track.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Track<T, U> {
|
pub struct Track<E: Engine> {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// Inputs and outputs of 1st and last device
|
/// Inputs and outputs of 1st and last device
|
||||||
pub ports: JackPorts,
|
pub ports: JackPorts,
|
||||||
/// Device chain
|
/// Device chain
|
||||||
pub devices: Vec<JackDevice<T, U>>,
|
pub devices: Vec<JackDevice<E>>,
|
||||||
/// Device selector
|
/// Device selector
|
||||||
pub device: usize,
|
pub device: usize,
|
||||||
}
|
}
|
||||||
impl<T, U> Track<T, U> {
|
impl<E: Engine> Track<E> {
|
||||||
pub fn new (name: &str) -> Usually<Self> {
|
pub fn new (name: &str) -> Usually<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
@ -21,14 +21,14 @@ impl<T, U> Track<T, U> {
|
||||||
device: 0,
|
device: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn get_device_mut (&self, i: usize) -> Option<RwLockWriteGuard<Box<dyn Device<T, U>>>> {
|
fn get_device_mut (&self, i: usize) -> Option<RwLockWriteGuard<Box<dyn Device<E>>>> {
|
||||||
self.devices.get(i).map(|d|d.state.write().unwrap())
|
self.devices.get(i).map(|d|d.state.write().unwrap())
|
||||||
}
|
}
|
||||||
pub fn device_mut (&self) -> Option<RwLockWriteGuard<Box<dyn Device<T, U>>>> {
|
pub fn device_mut (&self) -> Option<RwLockWriteGuard<Box<dyn Device<E>>>> {
|
||||||
self.get_device_mut(self.device)
|
self.get_device_mut(self.device)
|
||||||
}
|
}
|
||||||
/// Add a device to the end of the chain.
|
/// Add a device to the end of the chain.
|
||||||
pub fn append_device (&mut self, device: JackDevice<T, U>) -> Usually<&mut JackDevice<T, U>> {
|
pub fn append_device (&mut self, device: JackDevice<E>) -> Usually<&mut JackDevice<E>> {
|
||||||
self.devices.push(device);
|
self.devices.push(device);
|
||||||
let index = self.devices.len() - 1;
|
let index = self.devices.len() - 1;
|
||||||
Ok(&mut self.devices[index])
|
Ok(&mut self.devices[index])
|
||||||
|
|
@ -54,7 +54,7 @@ impl<T, U> Track<T, U> {
|
||||||
let mut _gain = 0.0f64;
|
let mut _gain = 0.0f64;
|
||||||
let mut track = Self::new("")?;
|
let mut track = Self::new("")?;
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut devices: Vec<JackDevice<T, U>> = vec![];
|
let mut devices: Vec<JackDevice<E>> = vec![];
|
||||||
edn!(edn in args {
|
edn!(edn in args {
|
||||||
Edn::Map(map) => {
|
Edn::Map(map) => {
|
||||||
if let Some(Edn::Str(n)) = map.get(&Edn::Key(SYM_NAME)) {
|
if let Some(Edn::Str(n)) = map.get(&Edn::Key(SYM_NAME)) {
|
||||||
|
|
@ -95,7 +95,7 @@ impl<T, U> Track<T, U> {
|
||||||
}
|
}
|
||||||
Ok(track)
|
Ok(track)
|
||||||
}
|
}
|
||||||
pub fn add_device (&mut self, device: JackDevice<T, U>) {
|
pub fn add_device (&mut self, device: JackDevice<E>) {
|
||||||
self.devices.push(device);
|
self.devices.push(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use tek_core::Direction;
|
use tek_core::Direction;
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for Track<TuiOutput<'a>, Rect> {
|
impl<'a> Render<Tui> for Track<Tui> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
||||||
TrackView {
|
TrackView {
|
||||||
chain: Some(&self),
|
chain: Some(&self),
|
||||||
|
|
@ -30,15 +30,16 @@ pub struct TrackView<'a, T, U> {
|
||||||
pub focused: bool,
|
pub focused: bool,
|
||||||
pub entered: bool,
|
pub entered: bool,
|
||||||
}
|
}
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for TrackView<'a, TuiOutput<'a>, Rect> {
|
impl<'a> Render<Tui> for TrackView<'a, Tui> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
let mut area = to.area();
|
||||||
if let Some(chain) = self.chain {
|
if let Some(chain) = self.chain {
|
||||||
match self.direction {
|
match self.direction {
|
||||||
Direction::Down => to.area.width = to.area.width.min(40),
|
Direction::Down => area.width = area.width.min(40),
|
||||||
Direction::Right => to.area.width = to.area.width.min(10),
|
Direction::Right => area.width = area.width.min(10),
|
||||||
_ => { unimplemented!() },
|
_ => { unimplemented!() },
|
||||||
}
|
}
|
||||||
fill_bg(to.buffer, to.area, Nord::bg_lo(self.focused, self.entered));
|
to.fill_bg(to.area(), Nord::bg_lo(self.focused, self.entered));
|
||||||
let mut split = Split::new(self.direction);
|
let mut split = Split::new(self.direction);
|
||||||
for device in chain.devices.as_slice().iter() {
|
for device in chain.devices.as_slice().iter() {
|
||||||
split = split.add_ref(device);
|
split = split.add_ref(device);
|
||||||
|
|
@ -49,12 +50,12 @@ impl<'a> Render<TuiOutput<'a>, Rect> for TrackView<'a, TuiOutput<'a>, Rect> {
|
||||||
}
|
}
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
} else {
|
} else {
|
||||||
let Rect { x, y, width, height } = to.area;
|
let Rect { x, y, width, height } = area;
|
||||||
let label = "No chain selected";
|
let label = "No chain selected";
|
||||||
let x = x + (width - label.len() as u16) / 2;
|
let x = x + (width - label.len() as u16) / 2;
|
||||||
let y = y + height / 2;
|
let y = y + height / 2;
|
||||||
label.blit(to.buffer, x, y, Some(Style::default().dim().bold()))?;
|
label.blit(to.buffer(), x, y, Some(Style::default().dim().bold()))?;
|
||||||
Ok(Some(to.area))
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Represents the tracks and scenes of the composition.
|
/// Represents the tracks and scenes of the composition.
|
||||||
pub struct Arranger<T, U> {
|
pub struct Arranger<E: Engine> {
|
||||||
/// Name of arranger
|
/// Name of arranger
|
||||||
pub name: Arc<RwLock<String>>,
|
pub name: Arc<RwLock<String>>,
|
||||||
/// Collection of tracks.
|
/// Collection of tracks.
|
||||||
|
|
@ -14,11 +14,11 @@ pub struct Arranger<T, U> {
|
||||||
/// Display mode of arranger
|
/// Display mode of arranger
|
||||||
pub mode: ArrangerViewMode,
|
pub mode: ArrangerViewMode,
|
||||||
/// Slot for modal dialog displayed on top of app.
|
/// Slot for modal dialog displayed on top of app.
|
||||||
pub modal: Option<Box<dyn ExitableComponent<T, U>>>,
|
pub modal: Option<Box<dyn ExitableComponent<E>>>,
|
||||||
/// Whether the arranger is currently focused
|
/// Whether the arranger is currently focused
|
||||||
pub focused: bool
|
pub focused: bool
|
||||||
}
|
}
|
||||||
impl<T, U> Arranger<T, U> {
|
impl<E: Engine> Arranger<E> {
|
||||||
pub fn new (name: &str) -> Self {
|
pub fn new (name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Arc::new(RwLock::new(name.into())),
|
name: Arc::new(RwLock::new(name.into())),
|
||||||
|
|
@ -100,7 +100,7 @@ impl ArrangerViewMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Render arranger to terminal
|
/// Render arranger to terminal
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for Arranger<TuiOutput<'a>, Rect> {
|
impl Render<Tui> for Arranger<Tui> {
|
||||||
fn render (&'a self, to: &'a mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&'a self, to: &'a mut TuiOutput<'a>) -> Perhaps<Rect> {
|
||||||
let area = (|to|match self.mode {
|
let area = (|to|match self.mode {
|
||||||
ArrangerViewMode::Horizontal =>
|
ArrangerViewMode::Horizontal =>
|
||||||
|
|
@ -125,7 +125,7 @@ impl<'a> Render<TuiOutput<'a>, Rect> for Arranger<TuiOutput<'a>, Rect> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Focusable<TuiOutput<'a>, Rect> for Arranger<TuiOutput<'a>, Rect> {
|
impl Focusable<Tui> for Arranger<Tui> {
|
||||||
fn is_focused (&self) -> bool {
|
fn is_focused (&self) -> bool {
|
||||||
self.focused
|
self.focused
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::*;
|
||||||
|
|
||||||
/// Draw arranger with 1 row per scene.
|
/// Draw arranger with 1 row per scene.
|
||||||
pub fn draw_compact_1 <'a> (
|
pub fn draw_compact_1 <'a> (
|
||||||
state: &Arranger<TuiOutput<'a>, Rect>, to: &mut TuiOutput<'a>
|
state: &Arranger<Tui>, to: &mut Tui
|
||||||
) -> Perhaps<Rect> {
|
) -> Perhaps<Rect> {
|
||||||
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
||||||
let scene_rows = (0..=state.scenes.len()).map(|i|(96, 96*i)).collect::<Vec<_>>();
|
let scene_rows = (0..=state.scenes.len()).map(|i|(96, 96*i)).collect::<Vec<_>>();
|
||||||
|
|
@ -11,7 +11,7 @@ pub fn draw_compact_1 <'a> (
|
||||||
|
|
||||||
/// Draw arranger with 2 rows per scene.
|
/// Draw arranger with 2 rows per scene.
|
||||||
pub fn draw_compact_2 <'a> (
|
pub fn draw_compact_2 <'a> (
|
||||||
state: &Arranger<TuiOutput<'a>, Rect>, to: &mut TuiOutput<'a>
|
state: &Arranger<Tui>, to: &mut Tui
|
||||||
) -> Perhaps<Rect> {
|
) -> Perhaps<Rect> {
|
||||||
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
||||||
let scene_rows = (0..=state.scenes.len()).map(|i|(192, 192*i)).collect::<Vec<_>>();
|
let scene_rows = (0..=state.scenes.len()).map(|i|(192, 192*i)).collect::<Vec<_>>();
|
||||||
|
|
@ -20,7 +20,7 @@ pub fn draw_compact_2 <'a> (
|
||||||
|
|
||||||
/// Draw arranger with number of rows per scene proportional to duration of scene.
|
/// Draw arranger with number of rows per scene proportional to duration of scene.
|
||||||
pub fn draw_expanded <'a> (
|
pub fn draw_expanded <'a> (
|
||||||
state: &Arranger<TuiOutput<'a>, Rect>, to: &mut TuiOutput<'a>
|
state: &Arranger<Tui>, to: &mut Tui
|
||||||
) -> Perhaps<Rect> {
|
) -> Perhaps<Rect> {
|
||||||
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
let track_cols = track_clip_name_lengths(state.tracks.as_slice());
|
||||||
let scene_rows = scene_ppqs(state.tracks.as_slice(), state.scenes.as_slice());
|
let scene_rows = scene_ppqs(state.tracks.as_slice(), state.scenes.as_slice());
|
||||||
|
|
@ -28,8 +28,8 @@ pub fn draw_expanded <'a> (
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw <'a, 'b> (
|
pub fn draw <'a, 'b> (
|
||||||
state: &Arranger<TuiOutput<'a>, Rect>,
|
state: &Arranger<Tui>,
|
||||||
to: &mut TuiOutput<'a>,
|
to: &mut Tui,
|
||||||
cols: &'b [(usize, usize)],
|
cols: &'b [(usize, usize)],
|
||||||
rows: &'b [(usize, usize)],
|
rows: &'b [(usize, usize)],
|
||||||
) -> Perhaps<Rect> {
|
) -> Perhaps<Rect> {
|
||||||
|
|
@ -51,8 +51,8 @@ pub fn draw <'a, 'b> (
|
||||||
|
|
||||||
struct ColumnSeparators<'a>(u16, &'a [(usize, usize)]);
|
struct ColumnSeparators<'a>(u16, &'a [(usize, usize)]);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for ColumnSeparators<'a> {
|
impl<'a> Render<Tui> for ColumnSeparators<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let area = to.area;
|
let area = to.area;
|
||||||
let Self(offset, cols) = self;
|
let Self(offset, cols) = self;
|
||||||
let style = Some(Style::default().fg(Nord::SEPARATOR));
|
let style = Some(Style::default().fg(Nord::SEPARATOR));
|
||||||
|
|
@ -68,8 +68,8 @@ impl<'a> Render<TuiOutput<'a>, Rect> for ColumnSeparators<'a> {
|
||||||
|
|
||||||
struct RowSeparators<'a>(&'a [(usize, usize)]);
|
struct RowSeparators<'a>(&'a [(usize, usize)]);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for RowSeparators<'a> {
|
impl<'a> Render<Tui> for RowSeparators<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let mut area = to.area;
|
||||||
let Self(rows) = self;
|
let Self(rows) = self;
|
||||||
for (_, y) in rows.iter() {
|
for (_, y) in rows.iter() {
|
||||||
|
|
@ -91,8 +91,8 @@ struct CursorFocus<'a>(
|
||||||
ArrangerFocus, u16, &'a [(usize, usize)], &'a [(usize, usize)]
|
ArrangerFocus, u16, &'a [(usize, usize)], &'a [(usize, usize)]
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for CursorFocus<'a> {
|
impl<'a> Render<Tui> for CursorFocus<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let mut area = to.area;
|
||||||
let Self(selected, offset, cols, rows) = *self;
|
let Self(selected, offset, cols, rows) = *self;
|
||||||
let get_track_area = |t: usize| Rect {
|
let get_track_area = |t: usize| Rect {
|
||||||
|
|
@ -157,8 +157,8 @@ impl<'a> Render<TuiOutput<'a>, Rect> for CursorFocus<'a> {
|
||||||
|
|
||||||
struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer]);
|
struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer]);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for TracksHeader<'a> {
|
impl<'a> Render<Tui> for TracksHeader<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let mut area = to.area;
|
||||||
let Self(offset, track_cols, tracks) = *self;
|
let Self(offset, track_cols, tracks) = *self;
|
||||||
let Rect { y, width, .. } = area;
|
let Rect { y, width, .. } = area;
|
||||||
|
|
@ -177,8 +177,8 @@ impl<'a> Render<TuiOutput<'a>, Rect> for TracksHeader<'a> {
|
||||||
|
|
||||||
struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer], &'a[Scene]);
|
struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequencer], &'a[Scene]);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for SceneRows<'a> {
|
impl<'a> Render<Tui> for SceneRows<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let area = to.area;
|
let area = to.area;
|
||||||
let Self(offset, track_cols, scene_rows, tracks, scenes) = *self;
|
let Self(offset, track_cols, scene_rows, tracks, scenes) = *self;
|
||||||
let black = Some(Style::default().fg(Nord::SEPARATOR));
|
let black = Some(Style::default().fg(Nord::SEPARATOR));
|
||||||
|
|
@ -208,16 +208,15 @@ impl<'a> Render<TuiOutput<'a>, Rect> for SceneRows<'a> {
|
||||||
|
|
||||||
struct SceneRow<'a>(&'a[Sequencer], &'a Scene, &'a[(usize, usize)], u16);
|
struct SceneRow<'a>(&'a[Sequencer], &'a Scene, &'a[(usize, usize)], u16);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for SceneRow<'a> {
|
impl<'a> Render<Tui> for SceneRow<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let mut area = to.area();
|
||||||
let Self(tracks, scene, track_cols, offset) = self;
|
let Self(tracks, scene, track_cols, offset) = self;
|
||||||
let Rect { x, y, width, .. } = area;
|
let Rect { x, y, width, .. } = area;
|
||||||
let playing = scene.is_playing(tracks);
|
let playing = scene.is_playing(tracks);
|
||||||
(if playing { "▶" } else { " " }).blit(to.buffer, x, y, None)?;
|
(if playing { "▶" } else { " " }).blit(to.buffer(), x, y, None)?;
|
||||||
scene.name.read().unwrap().blit(to.buffer, x + 1, y, Some(Style::default().white()))?;
|
scene.name.read().unwrap().blit(to.buffer(), x + 1, y, Some(Style::default().white()))?;
|
||||||
fill_bg(to.buffer, Rect { x: x, y, width: offset.saturating_sub(1), height: area.height }, COLOR_BG1);
|
to.fill_bg(Rect { x: x, y, width: offset.saturating_sub(1), height: area.height }, COLOR_BG1);
|
||||||
|
|
||||||
for (track, (w, x)) in track_cols.iter().enumerate() {
|
for (track, (w, x)) in track_cols.iter().enumerate() {
|
||||||
let x = *x as u16 + offset;
|
let x = *x as u16 + offset;
|
||||||
if x > width {
|
if x > width {
|
||||||
|
|
@ -240,8 +239,8 @@ impl<'a> Render<TuiOutput<'a>, Rect> for SceneRow<'a> {
|
||||||
|
|
||||||
struct SceneClip<'a>(&'a Sequencer, usize);
|
struct SceneClip<'a>(&'a Sequencer, usize);
|
||||||
|
|
||||||
impl<'a> Render<TuiOutput<'a>, Rect> for SceneClip<'a> {
|
impl<'a> Render<Tui> for SceneClip<'a> {
|
||||||
fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let area = to.area;
|
let area = to.area;
|
||||||
let Self(track, clip) = self;
|
let Self(track, clip) = self;
|
||||||
let style = Some(Style::default().white());
|
let style = Some(Style::default().white());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue