mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-01-31 16:36:40 +01:00
wip: 21 errors!
This commit is contained in:
parent
694970bf0d
commit
ea5bc2e3b1
30 changed files with 392 additions and 362 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -2524,16 +2524,26 @@ dependencies = [
|
||||||
"suil-rs",
|
"suil-rs",
|
||||||
"symphonia",
|
"symphonia",
|
||||||
"tek_core",
|
"tek_core",
|
||||||
|
"tek_proc",
|
||||||
"vst",
|
"vst",
|
||||||
"wavers",
|
"wavers",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tek_proc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.60",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tek_sequencer"
|
name = "tek_sequencer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tek_core",
|
"tek_core",
|
||||||
|
"tek_proc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ pub enum Collected<'a, E: Engine> {
|
||||||
}
|
}
|
||||||
|
|
||||||
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::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
match self {
|
match self {
|
||||||
Self::Box(item) => (*item).render(to),
|
Self::Box(item) => (*item).render(to),
|
||||||
Self::Ref(item) => (*item).render(to),
|
Self::Ref(item) => (*item).render(to),
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,25 @@ pub trait App<T: Engine> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Platform backend.
|
/// Platform backend.
|
||||||
pub trait Engine {
|
pub trait Engine: Sized {
|
||||||
type Handled;
|
|
||||||
type Rendered;
|
|
||||||
fn setup (&mut self) -> Usually<()> { Ok(()) }
|
fn setup (&mut self) -> Usually<()> { Ok(()) }
|
||||||
fn teardown (&mut self) -> Usually<()> { Ok(()) }
|
|
||||||
fn handle (&self, _: &mut impl Handle<Self>) -> Usually<()> where Self: Sized;
|
|
||||||
fn render (&mut self, _: &impl Render<Self>) -> Usually<()> where Self: Sized;
|
|
||||||
fn exited (&self) -> bool;
|
fn exited (&self) -> bool;
|
||||||
|
fn teardown (&mut self) -> Usually<()> { Ok(()) }
|
||||||
|
|
||||||
|
type HandleInput;
|
||||||
|
fn handle (&self, _: &mut impl Handle<Self>) -> Usually<()> where Self: Sized;
|
||||||
|
type Handled;
|
||||||
|
|
||||||
|
type RenderInput;
|
||||||
|
fn render (&mut self, _: &impl Render<Self>) -> Usually<()> where Self: Sized;
|
||||||
|
type Rendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HandleContext {}
|
||||||
|
|
||||||
|
pub trait RenderContext {}
|
||||||
|
|
||||||
|
submod! {
|
||||||
|
render
|
||||||
|
handle
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
crates/tek_core/src/engine/handle.rs
Normal file
46
crates/tek_core/src/engine/handle.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// Handle input
|
||||||
|
pub trait Handle<E: Engine>: Send + Sync {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, E: Engine> Handle<E> for &mut H where H: Handle<E> {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
|
(*self).handle(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, E: Engine> Handle<E> for Option<H> where H: Handle<E> {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
|
if let Some(ref mut handle) = self {
|
||||||
|
handle.handle(context)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, E: Engine> Handle<E> for Mutex<H> where H: Handle<E> {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
|
self.lock().unwrap().handle(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, E: Engine> Handle<E> for Arc<Mutex<H>> where H: Handle<E> {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
|
self.lock().unwrap().handle(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, E: Engine> Handle<E> for RwLock<H> where H: Handle<E> {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
|
self.write().unwrap().handle(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, E: Engine> Handle<E> for Arc<RwLock<H>> where H: Handle<E> {
|
||||||
|
fn handle (&mut self, context: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
|
self.write().unwrap().handle(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
69
crates/tek_core/src/engine/render.rs
Normal file
69
crates/tek_core/src/engine/render.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// Render to output.
|
||||||
|
pub trait Render<E: Engine>: Send + Sync {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Options can be rendered optionally.
|
||||||
|
impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
match self {
|
||||||
|
Some(component) => component.render(to),
|
||||||
|
None => Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Boxed references can be rendered.
|
||||||
|
impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
(**self).render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Immutable references can be rendered.
|
||||||
|
impl<R, E: Engine> Render<E> for &R where R: Render<E> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
(*self).render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutable references can be rendered.
|
||||||
|
impl<R, E: Engine> Render<E> for &mut R where R: Render<E> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
(**self).render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Counted references can be rendered.
|
||||||
|
impl<R, E: Engine> Render<E> for Arc<R> where R: Render<E> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
self.as_ref().render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// References behind a [Mutex] can be rendered.
|
||||||
|
impl<R, E: Engine> Render<E> for Mutex<R> where R: Render<E> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
self.lock().unwrap().render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// References behind a [RwLock] can be rendered.
|
||||||
|
impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
self.read().unwrap().render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Boxed closures can be rendered.
|
||||||
|
///
|
||||||
|
/// Rendering unboxed closures should also be possible;
|
||||||
|
/// but in practice implementing the trait for an unboxed
|
||||||
|
/// `Fn` closure causes an impl conflict.
|
||||||
|
impl<'a, E: Engine> Render<E> for Box<dyn Fn(&mut E::RenderInput) -> Perhaps<E::Rendered> + Send + Sync + 'a> {
|
||||||
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
|
(*self)(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AppEvent {
|
|
||||||
/// Terminal input
|
|
||||||
Input(::crossterm::event::Event),
|
|
||||||
/// Update values but not the whole form.
|
|
||||||
Update,
|
|
||||||
/// Update the whole form.
|
|
||||||
Redraw,
|
|
||||||
/// Device gains focus
|
|
||||||
Focus,
|
|
||||||
/// Device loses focus
|
|
||||||
Blur,
|
|
||||||
// /// JACK notification
|
|
||||||
// Jack(JackEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,46 +1 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Handle input
|
|
||||||
pub trait Handle<E: Engine>: Send + Sync {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, E: Engine> Handle<E> for &mut H where H: Handle<E> {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled> {
|
|
||||||
(*self).handle(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, E: Engine> Handle<E> for Option<H> where H: Handle<E> {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled> {
|
|
||||||
if let Some(ref mut handle) = self {
|
|
||||||
handle.handle(context)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, E: Engine> Handle<E> for Mutex<H> where H: Handle<E> {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled> {
|
|
||||||
self.lock().unwrap().handle(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, E: Engine> Handle<E> for Arc<Mutex<H>> where H: Handle<E> {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled> {
|
|
||||||
self.lock().unwrap().handle(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, E: Engine> Handle<E> for RwLock<H> where H: Handle<E> {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled> {
|
|
||||||
self.write().unwrap().handle(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H, E: Engine> Handle<E> for Arc<RwLock<H>> where H: Handle<E> {
|
|
||||||
fn handle (&mut self, context: &E) -> Perhaps<E::Handled> {
|
|
||||||
self.write().unwrap().handle(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub trait Device<E: Engine>: Component<E> + Process {
|
||||||
impl<D, E: Engine> Device<E> for D where D: Component<E> + Process {}
|
impl<D, E: Engine> Device<E> for D where D: Component<E> + Process {}
|
||||||
|
|
||||||
impl<E: Engine> Render<E> for Box<dyn Device<E>> {
|
impl<E: Engine> Render<E> for Box<dyn Device<E>> {
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
(**self).render(to)
|
(**self).render(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ impl<E: Engine> std::fmt::Debug for JackDevice<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<E: Engine> Render<E> for JackDevice<E> {
|
impl<E: Engine> Render<E> for JackDevice<E> {
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
|
||||||
self.state.read().unwrap().render(to)
|
self.state.read().unwrap().render(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<E: Engine> Handle<E> for JackDevice<E> {
|
impl<E: Engine> Handle<E> for JackDevice<E> {
|
||||||
fn handle (&mut self, from: &E) -> Perhaps<E::Handled> {
|
fn handle (&mut self, from: &E::HandleInput) -> Perhaps<E::Handled> {
|
||||||
self.state.write().unwrap().handle(from)
|
self.state.write().unwrap().handle(from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ pub type KeyBinding<T> = (
|
||||||
pub type KeyMap<T> = [KeyBinding<T>];
|
pub type KeyMap<T> = [KeyBinding<T>];
|
||||||
|
|
||||||
pub fn handle_keymap <T> (
|
pub fn handle_keymap <T> (
|
||||||
state: &mut T, event: &AppEvent, keymap: &KeyMap<T>,
|
state: &mut T, event: &TuiEvent, keymap: &KeyMap<T>,
|
||||||
) -> Usually<bool> {
|
) -> Usually<bool> {
|
||||||
match event {
|
match event {
|
||||||
AppEvent::Input(crossterm::event::Event::Key(event)) => {
|
TuiEvent::Input(crossterm::event::Event::Key(event)) => {
|
||||||
for (code, modifiers, _, _, command) in keymap.iter() {
|
for (code, modifiers, _, _, command) in keymap.iter() {
|
||||||
if *code == event.code && modifiers.bits() == event.modifiers.bits() {
|
if *code == event.code && modifiers.bits() == event.modifiers.bits() {
|
||||||
return command(state)
|
return command(state)
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,14 @@ submod! {
|
||||||
component
|
component
|
||||||
edn
|
edn
|
||||||
engine
|
engine
|
||||||
event
|
|
||||||
exit
|
exit
|
||||||
focus
|
focus
|
||||||
handle
|
|
||||||
jack_core
|
jack_core
|
||||||
jack_device
|
jack_device
|
||||||
jack_event
|
jack_event
|
||||||
jack_ports
|
jack_ports
|
||||||
keymap
|
keymap
|
||||||
space
|
space
|
||||||
render
|
|
||||||
time
|
time
|
||||||
tui
|
tui
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Render to output.
|
|
||||||
pub trait Render<E: Engine>: Send + Sync {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Options can be rendered optionally.
|
|
||||||
impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
match self {
|
|
||||||
Some(component) => component.render(to),
|
|
||||||
None => Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Boxed references can be rendered.
|
|
||||||
impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
(**self).render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Immutable references can be rendered.
|
|
||||||
impl<R, E: Engine> Render<E> for &R where R: Render<E> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
(*self).render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutable references can be rendered.
|
|
||||||
impl<R, E: Engine> Render<E> for &mut R where R: Render<E> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
(**self).render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Counted references can be rendered.
|
|
||||||
impl<R, E: Engine> Render<E> for Arc<R> where R: Render<E> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
self.as_ref().render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// References behind a [Mutex] can be rendered.
|
|
||||||
impl<R, E: Engine> Render<E> for Mutex<R> where R: Render<E> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
self.lock().unwrap().render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// References behind a [RwLock] can be rendered.
|
|
||||||
impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
self.read().unwrap().render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Boxed closures can be rendered.
|
|
||||||
///
|
|
||||||
/// Rendering unboxed closures should also be possible;
|
|
||||||
/// but in practice implementing the trait for an unboxed
|
|
||||||
/// `Fn` closure causes an impl conflict.
|
|
||||||
impl<'a, E: Engine> Render<E> for Box<dyn Fn(&mut E) -> Perhaps<E::Rendered> + Send + Sync + 'a> {
|
|
||||||
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
|
||||||
(*self)(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,15 @@ pub struct Tui {
|
||||||
buffer: usize,
|
buffer: usize,
|
||||||
buffers: [Buffer;2],
|
buffers: [Buffer;2],
|
||||||
backend: CrosstermBackend<Stdout>,
|
backend: CrosstermBackend<Stdout>,
|
||||||
|
event: RwLock<Option<TuiEvent>>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
sleep: Duration,
|
sleep: Duration,
|
||||||
poll: Duration,
|
poll: Duration,
|
||||||
}
|
}
|
||||||
impl Engine for Tui {
|
impl Engine for Tui {
|
||||||
|
type HandleInput = Self;
|
||||||
type Handled = bool;
|
type Handled = bool;
|
||||||
|
type RenderInput = Self;
|
||||||
type Rendered = Rect;
|
type Rendered = Rect;
|
||||||
fn exited (&self) -> bool {
|
fn exited (&self) -> bool {
|
||||||
self.exited.fetch_and(true, Ordering::Relaxed)
|
self.exited.fetch_and(true, Ordering::Relaxed)
|
||||||
|
|
@ -46,10 +49,14 @@ impl Engine for Tui {
|
||||||
code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, ..
|
code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, ..
|
||||||
}) = event {
|
}) = event {
|
||||||
self.exited.store(true, Ordering::Relaxed);
|
self.exited.store(true, Ordering::Relaxed);
|
||||||
} else if let Err(e) = state.handle(self) {
|
} else {
|
||||||
|
*self.event.write().unwrap() = Some(TuiEvent::Input(event));
|
||||||
|
let result = state.handle(self);
|
||||||
|
if let Err(e) = result {
|
||||||
panic!("{e}")
|
panic!("{e}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn render (&mut self, state: &impl Render<Self>) -> Usually<()> {
|
fn render (&mut self, state: &impl Render<Self>) -> Usually<()> {
|
||||||
|
|
@ -69,6 +76,7 @@ impl Tui {
|
||||||
sleep: Duration::from_millis(20),
|
sleep: Duration::from_millis(20),
|
||||||
poll: Duration::from_millis(100),
|
poll: Duration::from_millis(100),
|
||||||
exited: Arc::new(AtomicBool::new(false)),
|
exited: Arc::new(AtomicBool::new(false)),
|
||||||
|
event: RwLock::new(None),
|
||||||
buffer: 0,
|
buffer: 0,
|
||||||
buffers: [Buffer::empty(area), Buffer::empty(area)],
|
buffers: [Buffer::empty(area), Buffer::empty(area)],
|
||||||
backend,
|
backend,
|
||||||
|
|
@ -102,6 +110,15 @@ impl Tui {
|
||||||
main_thread.join().expect("main thread failed");
|
main_thread.join().expect("main thread failed");
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
pub fn event (&self) -> TuiEvent {
|
||||||
|
self.event.read().unwrap().clone().unwrap()
|
||||||
|
}
|
||||||
|
pub fn area (&self) -> Rect {
|
||||||
|
self.area
|
||||||
|
}
|
||||||
|
pub fn buffer (&mut self) -> &mut Buffer {
|
||||||
|
&mut self.buffers[self.buffer]
|
||||||
|
}
|
||||||
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];
|
||||||
|
|
@ -110,12 +127,6 @@ 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)) {
|
pub fn buffer_update (&mut self, area: Rect, callback: &impl Fn(&mut Cell, u16, u16)) {
|
||||||
buffer_update(self.buffer(), area, callback)
|
buffer_update(self.buffer(), area, callback)
|
||||||
}
|
}
|
||||||
|
|
@ -151,15 +162,40 @@ impl Tui {
|
||||||
}
|
}
|
||||||
Ok(Some(Rect { x, y, width: text.len() as u16, height: 1 }))
|
Ok(Some(Rect { x, y, width: text.len() as u16, height: 1 }))
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
pub fn alter_area (
|
pub fn alter_area (
|
||||||
&mut self, alter: impl Fn(u16, u16, u16, u16)->(u16, u16, u16, u16)
|
&mut self, alter: impl Fn(u16, u16, u16, u16)->(u16, u16, u16, u16)
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
let (x, y, width, height) = alter(
|
let (x, y, width, height) = alter(
|
||||||
self.area.x, self.area.y, self.area.width, self.area.height
|
self.area.x, self.area.y, self.area.width, self.area.height
|
||||||
);
|
);
|
||||||
self.area = Rect { x, y, width, height };
|
self.with_area(x, y, width, height)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with_area (&mut self, x: u16, y: u16, w: u16, h: u16) -> &mut Self {
|
||||||
|
self.with_rect(Rect { x, y, width: w, height: h });
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with_rect (&mut self, area: Rect) -> &mut Self {
|
||||||
|
self.area = area;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum TuiEvent {
|
||||||
|
/// Terminal input
|
||||||
|
Input(::crossterm::event::Event),
|
||||||
|
/// Update values but not the whole form.
|
||||||
|
Update,
|
||||||
|
/// Update the whole form.
|
||||||
|
Redraw,
|
||||||
|
/// Device gains focus
|
||||||
|
Focus,
|
||||||
|
/// Device loses focus
|
||||||
|
Blur,
|
||||||
|
// /// JACK notification
|
||||||
|
// Jack(JackEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rendering unit struct to Ratatui returns zero-sized [Rect] at render coordinates.
|
/// Rendering unit struct to Ratatui returns zero-sized [Rect] at render coordinates.
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct MixerCli {
|
||||||
/// Number of tracks
|
/// Number of tracks
|
||||||
#[arg(short, long)] channels: Option<usize>,
|
#[arg(short, long)] channels: Option<usize>,
|
||||||
}
|
}
|
||||||
impl<T, U> Mixer<T, U> {
|
impl<E: Engine> Mixer<E> {
|
||||||
pub fn from_args () -> Usually<Self> {
|
pub fn from_args () -> Usually<Self> {
|
||||||
let args = MixerCli::parse();
|
let args = MixerCli::parse();
|
||||||
let mut mix = Self::new("")?;
|
let mut mix = Self::new("")?;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl <T, U> Handle for Mixer<T, U> {
|
impl Handle<Tui> for Mixer<Tui> {
|
||||||
fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
|
fn handle (&mut self, engine: &Tui) -> Perhaps<bool> {
|
||||||
if let AppEvent::Input(crossterm::event::Event::Key(event)) = event {
|
if let TuiEvent::Input(crossterm::event::Event::Key(event)) = engine.event() {
|
||||||
|
|
||||||
match event.code {
|
match event.code {
|
||||||
//KeyCode::Char('c') => {
|
//KeyCode::Char('c') => {
|
||||||
|
|
@ -13,7 +13,7 @@ impl <T, U> Handle for Mixer<T, U> {
|
||||||
KeyCode::Down => {
|
KeyCode::Down => {
|
||||||
self.selected_track = (self.selected_track + 1) % self.tracks.len();
|
self.selected_track = (self.selected_track + 1) % self.tracks.len();
|
||||||
println!("{}", self.selected_track);
|
println!("{}", self.selected_track);
|
||||||
return Ok(true)
|
return Ok(Some(true))
|
||||||
},
|
},
|
||||||
KeyCode::Up => {
|
KeyCode::Up => {
|
||||||
if self.selected_track == 0 {
|
if self.selected_track == 0 {
|
||||||
|
|
@ -22,7 +22,7 @@ impl <T, U> Handle for Mixer<T, U> {
|
||||||
self.selected_track -= 1;
|
self.selected_track -= 1;
|
||||||
}
|
}
|
||||||
println!("{}", self.selected_track);
|
println!("{}", self.selected_track);
|
||||||
return Ok(true)
|
return Ok(Some(true))
|
||||||
},
|
},
|
||||||
KeyCode::Left => {
|
KeyCode::Left => {
|
||||||
if self.selected_column == 0 {
|
if self.selected_column == 0 {
|
||||||
|
|
@ -30,7 +30,7 @@ impl <T, U> Handle for Mixer<T, U> {
|
||||||
} else {
|
} else {
|
||||||
self.selected_column -= 1;
|
self.selected_column -= 1;
|
||||||
}
|
}
|
||||||
return Ok(true)
|
return Ok(Some(true))
|
||||||
},
|
},
|
||||||
KeyCode::Right => {
|
KeyCode::Right => {
|
||||||
if self.selected_column == 6 {
|
if self.selected_column == 6 {
|
||||||
|
|
@ -38,7 +38,7 @@ impl <T, U> Handle for Mixer<T, U> {
|
||||||
} else {
|
} else {
|
||||||
self.selected_column += 1;
|
self.selected_column += 1;
|
||||||
}
|
}
|
||||||
return Ok(true)
|
return Ok(Some(true))
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
println!("\n{event:?}");
|
println!("\n{event:?}");
|
||||||
|
|
@ -46,7 +46,7 @@ impl <T, U> Handle for Mixer<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Ok(false)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,11 @@ pub struct Plugin {
|
||||||
pub mapping: bool,
|
pub mapping: bool,
|
||||||
pub ports: JackPorts,
|
pub ports: JackPorts,
|
||||||
}
|
}
|
||||||
handle!(Plugin |self, e| handle_keymap(self, e, KEYMAP_PLUGIN));
|
impl Handle<Tui> for Plugin {
|
||||||
|
fn handle (&mut self, e: &Tui) -> Perhaps<bool> {
|
||||||
|
handle_keymap(self, event, KEYMAP_PLUGIN)
|
||||||
|
}
|
||||||
|
}
|
||||||
process!(Plugin = Plugin::process);
|
process!(Plugin = Plugin::process);
|
||||||
impl Render<Tui> for Plugin {
|
impl Render<Tui> for Plugin {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
|
|
@ -36,7 +40,7 @@ impl Render<Tui> for Plugin {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
} ;
|
} ;
|
||||||
label.blit(to.buffer(), x + 2, y + 1 + i as u16 - start as u16, style)?;
|
to.blit(&label, x + 2, y + 1 + i as u16 - start as u16, style)?;
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +48,7 @@ impl Render<Tui> for Plugin {
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
draw_header(self, to.buffer(), area.x, area.y, width)?;
|
draw_header(self, to, area.x, area.y, width)?;
|
||||||
Ok(Some(Rect { width, ..to.area() }))
|
Ok(Some(Rect { width, ..to.area() }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +62,7 @@ pub enum PluginKind {
|
||||||
VST3,
|
VST3,
|
||||||
}
|
}
|
||||||
impl Plugin {
|
impl Plugin {
|
||||||
pub fn new_lv2 <E> (name: &str, path: &str) -> Usually<JackDevice<E>> {
|
pub fn new_lv2 (name: &str, path: &str) -> Usually<JackDevice<Tui>> {
|
||||||
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 {
|
||||||
|
|
@ -137,13 +141,13 @@ impl Plugin {
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn draw_header (state: &Plugin, buf: &mut Buffer, x: u16, y: u16, w: u16) -> Usually<Rect> {
|
fn draw_header (state: &Plugin, to: &mut Tui, x: u16, y: u16, w: u16) -> Usually<Rect> {
|
||||||
let style = Style::default().gray();
|
let style = Style::default().gray();
|
||||||
let label1 = format!(" {}", state.name);
|
let label1 = format!(" {}", state.name);
|
||||||
label1.blit(buf, x + 1, y, Some(style.white().bold()))?;
|
to.blit(&label1, x + 1, y, Some(style.white().bold()))?;
|
||||||
if let Some(ref path) = state.path {
|
if let Some(ref path) = state.path {
|
||||||
let label2 = format!("{}…", &path[..((w as usize - 10).min(path.len()))]);
|
let label2 = format!("{}…", &path[..((w as usize - 10).min(path.len()))]);
|
||||||
label2.blit(buf, x + 2 + label1.len() as u16, y, Some(style.not_dim()))?;
|
to.blit(&label2, x + 2 + label1.len() as u16, y, Some(style.not_dim()))?;
|
||||||
}
|
}
|
||||||
Ok(Rect { x, y, width: w, height: 1 })
|
Ok(Rect { x, y, width: w, height: 1 })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub struct LV2Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LV2Plugin {
|
impl LV2Plugin {
|
||||||
pub fn from_edn <'e, T, U> (args: &[Edn<'e>]) -> Usually<JackDevice<T, U>> {
|
pub fn from_edn <'e, E: Engine> (args: &[Edn<'e>]) -> Usually<JackDevice<E>> {
|
||||||
let mut name = String::new();
|
let mut name = String::new();
|
||||||
let mut path = String::new();
|
let mut path = String::new();
|
||||||
edn!(edn in args {
|
edn!(edn in args {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ pub struct Sampler {
|
||||||
pub modal: Arc<Mutex<Option<Box<dyn Exit + Send>>>>,
|
pub modal: Arc<Mutex<Option<Box<dyn Exit + Send>>>>,
|
||||||
pub output_gain: f32
|
pub output_gain: f32
|
||||||
}
|
}
|
||||||
impl<E: Engine> Handle<E> for Sampler {
|
impl Handle<Tui> for Sampler {
|
||||||
fn handle (&mut self, e: &E) -> Usually<E::Handled> {
|
fn handle (&mut self, e: &Tui) -> Perhaps<bool> {
|
||||||
handle_keymap(self, event, KEYMAP_SAMPLER)
|
handle_keymap(self, event, KEYMAP_SAMPLER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +69,7 @@ pub const KEYMAP_SAMPLER: &'static [KeyBinding<Sampler>] = keymap!(Sampler {
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Sampler {
|
impl Sampler {
|
||||||
pub fn from_edn <'e, E: Engine> (args: &[Edn<'e>]) -> Usually<JackDevice<E>> {
|
pub fn from_edn <'e> (args: &[Edn<'e>]) -> Usually<JackDevice<Tui>> {
|
||||||
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();
|
||||||
|
|
@ -98,9 +98,9 @@ impl Sampler {
|
||||||
Self::new(&name, Some(samples))
|
Self::new(&name, Some(samples))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new <E: Engine> (
|
pub fn new (
|
||||||
name: &str, mapped: Option<BTreeMap<u7, Arc<RwLock<Sample>>>>
|
name: &str, mapped: Option<BTreeMap<u7, Arc<RwLock<Sample>>>>
|
||||||
) -> Usually<JackDevice<E>> {
|
) -> Usually<JackDevice<Tui>> {
|
||||||
Jack::new(name)?
|
Jack::new(name)?
|
||||||
.midi_in("midi")
|
.midi_in("midi")
|
||||||
.audio_in("recL")
|
.audio_in("recL")
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl <T, U> Handle for Track<T, U> {
|
impl Handle<Tui> for Track<Tui> {
|
||||||
fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
|
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||||
match event {
|
match from.event() {
|
||||||
AppEvent::Input(crossterm::event::Event::Key(event)) => {
|
TuiEvent::Input(crossterm::event::Event::Key(event)) => {
|
||||||
for (code, modifiers, _, _, command) in [
|
for (code, modifiers, _, _, command) in [
|
||||||
key!(Up, NONE, "chain_cursor_up", "move cursor up", || {
|
key!(Up, NONE, "chain_cursor_up", "move cursor up", || {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
@ -34,9 +34,9 @@ impl <T, U> Handle for Track<T, U> {
|
||||||
return command()
|
return command()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(false)
|
return Ok(None)
|
||||||
},
|
},
|
||||||
_ => Ok(false)
|
_ => Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ impl<'a> Render<Tui> for TrackView<'a, Tui> {
|
||||||
}
|
}
|
||||||
let (area, areas) = split.render_areas(to)?;
|
let (area, areas) = split.render_areas(to)?;
|
||||||
if self.focused && self.entered && areas.len() > 0 {
|
if self.focused && self.entered && areas.len() > 0 {
|
||||||
Corners(Style::default().green().not_dim()).draw(to.buffer, areas[0])?;
|
Corners(Style::default().green().not_dim()).draw(to.with_rect(areas[0]))?;
|
||||||
}
|
}
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -54,7 +54,7 @@ impl<'a> Render<Tui> for TrackView<'a, Tui> {
|
||||||
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()))?;
|
to.blit(&label, x, y, Some(Style::default().dim().bold()))?;
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl<T, U> Handle for Arranger<T, U> {
|
impl Handle<Tui> for Arranger<Tui> {
|
||||||
fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
|
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||||
match self.modal.as_mut() {
|
if let Some(modal) = self.modal.as_mut() {
|
||||||
Some(modal) => {
|
let result = modal.handle(from)?;
|
||||||
let result = modal.handle(event)?;
|
|
||||||
if modal.exited() {
|
if modal.exited() {
|
||||||
self.modal = None;
|
self.modal = None;
|
||||||
}
|
}
|
||||||
Ok(result)
|
return Ok(result)
|
||||||
},
|
}
|
||||||
None => match event {
|
match from.event() {
|
||||||
AppEvent::Input(crossterm::event::Event::Key(event)) => {
|
TuiEvent::Input(crossterm::event::Event::Key(event)) => {
|
||||||
for (code, modifiers, _, _, command) in [
|
for (code, modifiers, _, _, command) in [
|
||||||
key!(Char('`'), NONE, "mode_switch", "switch the display mode", || {
|
key!(Char('`'), NONE, "mode_switch", "switch the display mode", || {
|
||||||
self.mode.to_next();
|
self.mode.to_next();
|
||||||
|
|
@ -62,10 +61,9 @@ impl<T, U> Handle for Arranger<T, U> {
|
||||||
return command()
|
return command()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(false)
|
return Ok(None)
|
||||||
},
|
},
|
||||||
_ => Ok(false)
|
_ => Ok(None)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl Render<Tui> for ArrangerRenameModal {
|
||||||
height: 3
|
height: 3
|
||||||
};
|
};
|
||||||
to.fill_bg(bg_area, Nord::BG0);
|
to.fill_bg(bg_area, Nord::BG0);
|
||||||
Lozenge(Style::default().bold().white().dim()).draw(to.buffer, bg_area)?;
|
Lozenge(Style::default().bold().white().dim()).draw(to.with_rect(bg_area));
|
||||||
let label = match self.target {
|
let label = match self.target {
|
||||||
ArrangerFocus::Mix => "Rename project:",
|
ArrangerFocus::Mix => "Rename project:",
|
||||||
ArrangerFocus::Track(_) => "Rename track:",
|
ArrangerFocus::Track(_) => "Rename track:",
|
||||||
|
|
@ -58,10 +58,10 @@ impl Render<Tui> for ArrangerRenameModal {
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Handle<Tui> for TransportQuantize {
|
impl Handle<Tui> for ArrangerRenameModal {
|
||||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||||
match e {
|
match from.event() {
|
||||||
AppEvent::Input(Event::Key(k)) => {
|
TuiEvent::Input(Event::Key(k)) => {
|
||||||
match k.code {
|
match k.code {
|
||||||
KeyCode::Esc => {
|
KeyCode::Esc => {
|
||||||
self.exit();
|
self.exit();
|
||||||
|
|
@ -90,9 +90,9 @@ impl Handle<Tui> for TransportQuantize {
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(Some(true))
|
||||||
},
|
},
|
||||||
_ => Ok(false),
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::*;
|
||||||
use super::Arranger;
|
use super::Arranger;
|
||||||
|
|
||||||
/// Track management methods
|
/// Track management methods
|
||||||
impl<T, U> Arranger<T, U> {
|
impl<E: Engine> Arranger<E> {
|
||||||
pub fn track (&self) -> Option<&Sequencer> {
|
pub fn track (&self) -> Option<&Sequencer> {
|
||||||
self.selected.track().map(|t|self.tracks.get(t)).flatten()
|
self.selected.track().map(|t|self.tracks.get(t)).flatten()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ impl<'a> Render<Tui> for TrackNameColumn<'a> {
|
||||||
let offset = 0; // track scroll offset
|
let offset = 0; // track scroll offset
|
||||||
for y in 0..area.height {
|
for y in 0..area.height {
|
||||||
if y == 0 {
|
if y == 0 {
|
||||||
"Mixer".blit(to.buffer, area.x + 1, area.y + y, Some(DIM))?;
|
to.blit(&"Mixer", area.x + 1, area.y + y, Some(DIM))?;
|
||||||
} else if y % 2 == 0 {
|
} else if y % 2 == 0 {
|
||||||
let index = (y as usize - 2) / 2 + offset;
|
let index = (y as usize - 2) / 2 + offset;
|
||||||
if let Some(track) = tracks.get(index) {
|
if let Some(track) = tracks.get(index) {
|
||||||
let selected = selected.track() == Some(index);
|
let selected = selected.track() == Some(index);
|
||||||
let style = if selected { yellow } else { white };
|
let style = if selected { yellow } else { white };
|
||||||
format!(" {index:>02} ").blit(to.buffer, area.x, area.y + y, style)?;
|
to.blit(&format!(" {index:>02} "), area.x, area.y + y, style)?;
|
||||||
track.name.read().unwrap().blit(to.buffer, area.x + 4, area.y + y, style)?;
|
to.blit(&*track.name.read().unwrap(), area.x + 4, area.y + y, style)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +60,7 @@ impl<'a> Render<Tui> for TrackMonitorColumn<'a> {
|
||||||
let index = (y as usize - 2) / 2;
|
let index = (y as usize - 2) / 2;
|
||||||
if let Some(track) = tracks.get(index) {
|
if let Some(track) = tracks.get(index) {
|
||||||
let style = if track.monitoring { on } else { off };
|
let style = if track.monitoring { on } else { off };
|
||||||
" MON ".blit(to.buffer, area.x, area.y + y, style)?;
|
to.blit(&" MON ", area.x, area.y + y, style)?;
|
||||||
} else {
|
} else {
|
||||||
area.height = y;
|
area.height = y;
|
||||||
break
|
break
|
||||||
|
|
@ -88,7 +88,7 @@ impl<'a> Render<Tui> for TrackRecordColumn<'a> {
|
||||||
let index = (y as usize - 2) / 2;
|
let index = (y as usize - 2) / 2;
|
||||||
if let Some(track) = tracks.get(index) {
|
if let Some(track) = tracks.get(index) {
|
||||||
let style = if track.recording { on } else { off };
|
let style = if track.recording { on } else { off };
|
||||||
" REC ".blit(to.buffer, area.x, area.y + y, style)?;
|
to.blit(&" REC ", area.x, area.y + y, style)?;
|
||||||
} else {
|
} else {
|
||||||
area.height = y;
|
area.height = y;
|
||||||
break
|
break
|
||||||
|
|
@ -115,7 +115,7 @@ impl<'a> Render<Tui> for TrackOverdubColumn<'a> {
|
||||||
} else if y % 2 == 0 {
|
} else if y % 2 == 0 {
|
||||||
let index = (y as usize - 2) / 2;
|
let index = (y as usize - 2) / 2;
|
||||||
if let Some(track) = tracks.get(index) {
|
if let Some(track) = tracks.get(index) {
|
||||||
" OVR ".blit(to.buffer, area.x, area.y + y, if track.overdub {
|
to.blit(&" OVR ", area.x, area.y + y, if track.overdub {
|
||||||
on
|
on
|
||||||
} else {
|
} else {
|
||||||
off
|
off
|
||||||
|
|
@ -203,7 +203,7 @@ impl<'a> Render<Tui> for TrackScenesColumn<'a> {
|
||||||
}
|
}
|
||||||
let name = scene.name.read().unwrap();
|
let name = scene.name.read().unwrap();
|
||||||
let mut x3 = name.len() as u16;
|
let mut x3 = name.len() as u16;
|
||||||
to.blit(&name, x + x2, y, sep)?;
|
to.blit(&*name, x + x2, y, sep)?;
|
||||||
for (i, clip) in scene.clips.iter().enumerate() {
|
for (i, clip) in scene.clips.iter().enumerate() {
|
||||||
let active_track = selected.track() == Some(i);
|
let active_track = selected.track() == Some(i);
|
||||||
if let Some(clip) = clip {
|
if let Some(clip) = clip {
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ pub fn draw <'a, 'b> (
|
||||||
cols: &'b [(usize, usize)],
|
cols: &'b [(usize, usize)],
|
||||||
rows: &'b [(usize, usize)],
|
rows: &'b [(usize, usize)],
|
||||||
) -> Perhaps<Rect> {
|
) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let mut area = to.area();
|
||||||
area.height = 2 + (rows[rows.len() - 1].1 / 96) as u16;
|
area.height = 2 + (rows[rows.len() - 1].1 / 96) as u16;
|
||||||
let offset = 3 + scene_name_max_len(state.scenes.as_ref()) as u16;
|
let offset = 3 + scene_name_max_len(state.scenes.as_ref()) as u16;
|
||||||
let tracks = state.tracks.as_ref();
|
let tracks = state.tracks.as_ref();
|
||||||
|
|
@ -53,13 +53,13 @@ struct ColumnSeparators<'a>(u16, &'a [(usize, usize)]);
|
||||||
|
|
||||||
impl<'a> Render<Tui> for ColumnSeparators<'a> {
|
impl<'a> Render<Tui> for ColumnSeparators<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> 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));
|
||||||
for (_, x) in cols.iter() {
|
for (_, x) in cols.iter() {
|
||||||
let x = offset + area.x + *x as u16 - 1;
|
let x = offset + area.x + *x as u16 - 1;
|
||||||
for y in area.y..area.height+area.y {
|
for y in area.y..area.height+area.y {
|
||||||
"▎".blit(to.buffer, x, y, style)?;
|
to.blit(&"▎", x, y, style)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
|
|
@ -70,15 +70,15 @@ struct RowSeparators<'a>(&'a [(usize, usize)]);
|
||||||
|
|
||||||
impl<'a> Render<Tui> for RowSeparators<'a> {
|
impl<'a> Render<Tui> for RowSeparators<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let area = to.area();
|
||||||
let Self(rows) = self;
|
let Self(rows) = self;
|
||||||
for (_, y) in rows.iter() {
|
for (_, y) in rows.iter() {
|
||||||
let y = area.y + (*y / 96) as u16 + 1;
|
let y = area.y + (*y / 96) as u16 + 1;
|
||||||
if y >= to.buffer.area.height {
|
if y >= to.buffer().area.height {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for x in area.x..area.width+area.y-2 {
|
for x in area.x..area.width+area.y-2 {
|
||||||
let cell = to.buffer.get_mut(x, y);
|
let cell = to.buffer().get_mut(x, y);
|
||||||
cell.modifier = Modifier::UNDERLINED;
|
cell.modifier = Modifier::UNDERLINED;
|
||||||
cell.underline_color = Nord::SEPARATOR;
|
cell.underline_color = Nord::SEPARATOR;
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ struct CursorFocus<'a>(
|
||||||
|
|
||||||
impl<'a> Render<Tui> for CursorFocus<'a> {
|
impl<'a> Render<Tui> for CursorFocus<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> 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 {
|
||||||
x: offset + area.x + cols[t].1 as u16 - 1,
|
x: offset + area.x + cols[t].1 as u16 - 1,
|
||||||
|
|
@ -118,7 +118,7 @@ impl<'a> Render<Tui> for CursorFocus<'a> {
|
||||||
let mut clip_area: Option<Rect> = None;
|
let mut clip_area: Option<Rect> = None;
|
||||||
let area = match selected {
|
let area = match selected {
|
||||||
ArrangerFocus::Mix => {
|
ArrangerFocus::Mix => {
|
||||||
fill_bg(to.buffer, area, COLOR_BG0);
|
to.fill_bg(area, COLOR_BG0);
|
||||||
area
|
area
|
||||||
},
|
},
|
||||||
ArrangerFocus::Track(t) => {
|
ArrangerFocus::Track(t) => {
|
||||||
|
|
@ -137,21 +137,21 @@ impl<'a> Render<Tui> for CursorFocus<'a> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if let Some(Rect { x, y, width, height }) = track_area {
|
if let Some(Rect { x, y, width, height }) = track_area {
|
||||||
fill_fg(to.buffer, Rect { x, y, width: 1, height }, COLOR_BG5);
|
to.fill_fg(Rect { x, y, width: 1, height }, COLOR_BG5);
|
||||||
fill_fg(to.buffer, Rect { x: x + width, y, width: 1, height }, COLOR_BG5);
|
to.fill_fg(Rect { x: x + width, y, width: 1, height }, COLOR_BG5);
|
||||||
}
|
}
|
||||||
if let Some(Rect { y, height, .. }) = scene_area {
|
if let Some(Rect { y, height, .. }) = scene_area {
|
||||||
fill_ul(to.buffer, Rect { x: area.x, y: y - 1, width: area.width, height: 1 }, COLOR_BG5);
|
to.fill_ul(Rect { x: area.x, y: y - 1, width: area.width, height: 1 }, COLOR_BG5);
|
||||||
fill_ul(to.buffer, Rect { x: area.x, y: y + height - 1, width: area.width, height: 1 }, COLOR_BG5);
|
to.fill_ul(Rect { x: area.x, y: y + height - 1, width: area.width, height: 1 }, COLOR_BG5);
|
||||||
}
|
}
|
||||||
if let Some(clip_area) = clip_area {
|
if let Some(clip_area) = clip_area {
|
||||||
fill_bg(to.buffer, clip_area, COLOR_BG0);
|
to.fill_bg(clip_area, COLOR_BG0);
|
||||||
} else if let Some(track_area) = track_area {
|
} else if let Some(track_area) = track_area {
|
||||||
fill_bg(to.buffer, track_area, COLOR_BG0);
|
to.fill_bg(track_area, COLOR_BG0);
|
||||||
} else if let Some(scene_area) = scene_area {
|
} else if let Some(scene_area) = scene_area {
|
||||||
fill_bg(to.buffer, scene_area, COLOR_BG0);
|
to.fill_bg(scene_area, COLOR_BG0);
|
||||||
}
|
}
|
||||||
Ok(area)
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,7 +159,7 @@ struct TracksHeader<'a>(u16, &'a[(usize, usize)], &'a [Sequencer]);
|
||||||
|
|
||||||
impl<'a> Render<Tui> for TracksHeader<'a> {
|
impl<'a> Render<Tui> for TracksHeader<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area;
|
let 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;
|
||||||
for (track, (w, x)) in tracks.iter().zip(track_cols) {
|
for (track, (w, x)) in tracks.iter().zip(track_cols) {
|
||||||
|
|
@ -168,8 +168,8 @@ impl<'a> Render<Tui> for TracksHeader<'a> {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
let name = track.name.read().unwrap();
|
let name = track.name.read().unwrap();
|
||||||
fill_bg(to.buffer, Rect { x: offset + x, y, width: *w as u16, height: 2 }, COLOR_BG1);
|
to.fill_bg(Rect { x: offset + x, y, width: *w as u16, height: 2 }, COLOR_BG1);
|
||||||
name.blit(to.buffer, offset + x + 1, y, Some(Style::default().white()))?;
|
to.blit(&*name, offset + x + 1, y, Some(Style::default().white()))?;
|
||||||
}
|
}
|
||||||
Ok(Some(Rect { x: area.x, y, width, height: 2 }))
|
Ok(Some(Rect { x: area.x, y, width, height: 2 }))
|
||||||
}
|
}
|
||||||
|
|
@ -179,15 +179,15 @@ struct SceneRows<'a>(u16, &'a[(usize, usize)], &'a[(usize, usize)], &'a[Sequence
|
||||||
|
|
||||||
impl<'a> Render<Tui> for SceneRows<'a> {
|
impl<'a> Render<Tui> for SceneRows<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> 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));
|
||||||
let Rect { mut y, height, .. } = area;
|
let Rect { mut y, height: _height, .. } = area;
|
||||||
for (_, x) in track_cols.iter() {
|
for (_, x) in track_cols.iter() {
|
||||||
let x = *x as u16;
|
let x = *x as u16;
|
||||||
if x > 0 {
|
if x > 0 {
|
||||||
for y in area.y-2..y-2 {
|
for y in area.y-2..y-2 {
|
||||||
"▎".blit(to.buffer, x - 1, y, black)?;
|
to.blit(&"▎", x - 1, y, black)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -196,10 +196,8 @@ impl<'a> Render<Tui> for SceneRows<'a> {
|
||||||
//break
|
//break
|
||||||
//}
|
//}
|
||||||
let h = 1.max((pulses / 96) as u16);
|
let h = 1.max((pulses / 96) as u16);
|
||||||
SceneRow(tracks, scene, track_cols, offset).render(&mut TuiOutput {
|
SceneRow(tracks, scene, track_cols, offset)
|
||||||
buffer: to.buffer,
|
.render(to.with_area(area.x, y, area.width, h))?;
|
||||||
area: Rect { x: area.x, y, width: area.width, height: h, }
|
|
||||||
})?;
|
|
||||||
y = y + h
|
y = y + h
|
||||||
}
|
}
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
|
|
@ -210,29 +208,24 @@ struct SceneRow<'a>(&'a[Sequencer], &'a Scene, &'a[(usize, usize)], u16);
|
||||||
|
|
||||||
impl<'a> Render<Tui> for SceneRow<'a> {
|
impl<'a> Render<Tui> for SceneRow<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let mut area = to.area();
|
let 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)?;
|
to.blit(&if playing { "▶" } else { " " }, x, y, None)?;
|
||||||
scene.name.read().unwrap().blit(to.buffer(), x + 1, y, Some(Style::default().white()))?;
|
to.blit(&*scene.name.read().unwrap(), x + 1, y, Some(Style::default().white()))?;
|
||||||
to.fill_bg(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 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Some(track), Some(Some(clip))) = (
|
if let (Some(track), Some(Some(clip))) = (
|
||||||
tracks.get(track), scene.clips.get(track)
|
tracks.get(track), scene.clips.get(track)
|
||||||
) {
|
) {
|
||||||
SceneClip(track, *clip).render(&mut TuiOutput {
|
SceneClip(track, *clip).render(to.with_area(x, y, *w as u16, area.height))?;
|
||||||
buffer: to.buffer,
|
|
||||||
area: Rect { x, y, width: *w as u16, height: area.height, }
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -241,20 +234,20 @@ struct SceneClip<'a>(&'a Sequencer, usize);
|
||||||
|
|
||||||
impl<'a> Render<Tui> for SceneClip<'a> {
|
impl<'a> Render<Tui> for SceneClip<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> 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());
|
||||||
if let Some(phrase) = track.phrases.get(*clip) {
|
if let Some(phrase) = track.phrases.get(*clip) {
|
||||||
let phrase = phrase.read().unwrap();
|
let phrase = phrase.read().unwrap();
|
||||||
let name = phrase.name.read().unwrap();
|
let name = phrase.name.read().unwrap();
|
||||||
format!("{clip:02} {name}").blit(to.buffer, area.x + 1, area.y, style)?;
|
to.blit(&format!("{clip:02} {name}"), area.x + 1, area.y, style)?;
|
||||||
fill_bg(to.buffer, area, if track.sequence == Some(*clip) {
|
to.fill_bg(area, if track.sequence == Some(*clip) {
|
||||||
Nord::PLAYING
|
Nord::PLAYING
|
||||||
} else {
|
} else {
|
||||||
COLOR_BG1
|
COLOR_BG1
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
fill_bg(to.buffer, area, COLOR_BG0)
|
to.fill_bg(area, COLOR_BG0)
|
||||||
}
|
}
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ pub fn scene_ppqs (tracks: &[Sequencer], scenes: &[Scene]) -> Vec<(usize, usize)
|
||||||
scenes
|
scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Arranger<T, U> {
|
impl<E: Engine> Arranger<E> {
|
||||||
pub fn scene (&self) -> Option<&Scene> {
|
pub fn scene (&self) -> Option<&Scene> {
|
||||||
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
|
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::*;
|
||||||
|
|
||||||
impl Handle<Tui> for TransportQuantize {
|
impl Handle<Tui> for TransportQuantize {
|
||||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||||
handle_keymap(self, e, KEYMAP_SEQUENCER)
|
handle_keymap(self, &from.event(), KEYMAP_SEQUENCER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,11 @@ impl Sequencer {
|
||||||
.add_ref(&SequenceRange)
|
.add_ref(&SequenceRange)
|
||||||
.add_ref(&SequenceLoopRange)
|
.add_ref(&SequenceLoopRange)
|
||||||
.add_ref(&SequenceNoteRange)
|
.add_ref(&SequenceNoteRange)
|
||||||
.render(&mut TuiOutput {
|
.render(to.with_area(area.x, area.y, area.height, 10))?;
|
||||||
buffer: to.buffer,
|
|
||||||
area: Rect {
|
|
||||||
x: area.x,
|
|
||||||
y: area.y,
|
|
||||||
height: area.height,
|
|
||||||
width: 10,
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
area.x = area.x + 10;
|
area.x = area.x + 10;
|
||||||
area.width = area.width.saturating_sub(10);
|
area.width = area.width.saturating_sub(10);
|
||||||
area.height = area.height.min(66);
|
area.height = area.height.min(66);
|
||||||
Lozenge(Style::default().fg(Nord::BG2)).draw(to.buffer, area)?;
|
Lozenge(Style::default().fg(Nord::BG2)).draw(to.with_rect(area))?;
|
||||||
area.x = area.x + 1;
|
area.x = area.x + 1;
|
||||||
area.width = area.width.saturating_sub(1);
|
area.width = area.width.saturating_sub(1);
|
||||||
Layered::new()
|
Layered::new()
|
||||||
|
|
@ -32,10 +24,7 @@ impl Sequencer {
|
||||||
.add_ref(&SequenceNotes(&self))
|
.add_ref(&SequenceNotes(&self))
|
||||||
.add_ref(&SequenceCursor(&self))
|
.add_ref(&SequenceCursor(&self))
|
||||||
.add_ref(&SequenceZoom(&self))
|
.add_ref(&SequenceZoom(&self))
|
||||||
.render(&mut TuiOutput {
|
.render(to.with_rect(area))?;
|
||||||
buffer: to.buffer,
|
|
||||||
area: area
|
|
||||||
})?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,9 +52,9 @@ impl<'a> Render<Tui> for SequenceName<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, .. } = to.area();
|
let Rect { x, y, .. } = to.area();
|
||||||
let frame = Rect { x, y, width: 10, height: 4 };
|
let frame = Rect { x, y, width: 10, height: 4 };
|
||||||
Lozenge(Style::default().fg(Nord::BG2)).draw(to.buffer, frame)?;
|
Lozenge(Style::default().fg(Nord::BG2)).draw(to.with_rect(frame))?;
|
||||||
"Name:".blit(to.buffer, x + 1, y + 1, STYLE_LABEL)?;
|
to.blit(&"Name:", x + 1, y + 1, STYLE_LABEL)?;
|
||||||
self.0.name.read().unwrap().blit(to.buffer, x + 1, y + 2, STYLE_VALUE)?;
|
to.blit(&*self.0.name.read().unwrap(), x + 1, y + 2, STYLE_VALUE)?;
|
||||||
Ok(Some(frame))
|
Ok(Some(frame))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,11 +65,11 @@ impl<'a> Render<Tui> for SequenceRange {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, .. } = to.area();
|
let Rect { x, y, .. } = to.area();
|
||||||
let frame = Rect { x, y, width: 10, height: 6 };
|
let frame = Rect { x, y, width: 10, height: 6 };
|
||||||
Lozenge(Style::default().fg(Nord::BG2)).draw(to.buffer, frame)?;
|
Lozenge(Style::default().fg(Nord::BG2)).draw(to.with_rect(frame))?;
|
||||||
"Start: ".blit(to.buffer, x + 1, y + 1, STYLE_LABEL)?;
|
to.blit(&"Start: ", x + 1, y + 1, STYLE_LABEL)?;
|
||||||
" 1.1.1".blit(to.buffer, x + 1, y + 2, STYLE_VALUE)?;
|
to.blit(&" 1.1.1", x + 1, y + 2, STYLE_VALUE)?;
|
||||||
"End: ".blit(to.buffer, x + 1, y + 3, STYLE_LABEL)?;
|
to.blit(&"End: ", x + 1, y + 3, STYLE_LABEL)?;
|
||||||
" 2.1.1".blit(to.buffer, x + 1, y + 4, STYLE_VALUE)?;
|
to.blit(&" 2.1.1", x + 1, y + 4, STYLE_VALUE)?;
|
||||||
Ok(Some(frame))
|
Ok(Some(frame))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,12 +80,12 @@ impl<'a> Render<Tui> for SequenceLoopRange {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, .. } = to.area();
|
let Rect { x, y, .. } = to.area();
|
||||||
let range = Rect { x, y, width: 10, height: 7 };
|
let range = Rect { x, y, width: 10, height: 7 };
|
||||||
Lozenge(Style::default().fg(Nord::BG2)).draw(to.buffer, range)?;
|
Lozenge(Style::default().fg(Nord::BG2)).draw(to.with_rect(range))?;
|
||||||
"Loop [ ]".blit(to.buffer, x + 1, y + 1, STYLE_LABEL)?;
|
to.blit(&"Loop [ ]", x + 1, y + 1, STYLE_LABEL)?;
|
||||||
"From: ".blit(to.buffer, x + 1, y + 2, STYLE_LABEL)?;
|
to.blit(&"From: ", x + 1, y + 2, STYLE_LABEL)?;
|
||||||
" 1.1.1".blit(to.buffer, x + 1, y + 3, STYLE_VALUE)?;
|
to.blit(&" 1.1.1", x + 1, y + 3, STYLE_VALUE)?;
|
||||||
"Length: ".blit(to.buffer, x + 1, y + 4, STYLE_LABEL)?;
|
to.blit(&"Length: ", x + 1, y + 4, STYLE_LABEL)?;
|
||||||
" 1.0.0".blit(to.buffer, x + 1, y + 5, STYLE_VALUE)?;
|
to.blit(&" 1.0.0", x + 1, y + 5, STYLE_VALUE)?;
|
||||||
Ok(Some(range))
|
Ok(Some(range))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -107,15 +96,15 @@ impl<'a> Render<Tui> for SequenceNoteRange {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, .. } = to.area();
|
let Rect { x, y, .. } = to.area();
|
||||||
let range = Rect { x, y, width: 10, height: 9 };
|
let range = Rect { x, y, width: 10, height: 9 };
|
||||||
Lozenge(Style::default().fg(Nord::BG2)).draw(to.buffer, range)?;
|
Lozenge(Style::default().fg(Nord::BG2)).draw(to.with_rect(range))?;
|
||||||
"Notes: ".blit(to.buffer, x + 1, y + 1, STYLE_LABEL)?;
|
to.blit(&"Notes: ", x + 1, y + 1, STYLE_LABEL)?;
|
||||||
"C#0-C#9 ".blit(to.buffer, x + 1, y + 2, STYLE_VALUE)?;
|
to.blit(&"C#0-C#9 ", x + 1, y + 2, STYLE_VALUE)?;
|
||||||
"[ /2 ]".blit(to.buffer, x + 1, y + 3, STYLE_LABEL)?;
|
to.blit(&"[ /2 ]", x + 1, y + 3, STYLE_LABEL)?;
|
||||||
"[ x2 ]".blit(to.buffer, x + 1, y + 4, STYLE_LABEL)?;
|
to.blit(&"[ x2 ]", x + 1, y + 4, STYLE_LABEL)?;
|
||||||
"[ Rev ]".blit(to.buffer, x + 1, y + 5, STYLE_LABEL)?;
|
to.blit(&"[ Rev ]", x + 1, y + 5, STYLE_LABEL)?;
|
||||||
"[ Inv ]".blit(to.buffer, x + 1, y + 6, STYLE_LABEL)?;
|
to.blit(&"[ Inv ]", x + 1, y + 6, STYLE_LABEL)?;
|
||||||
"[ Dup ]".blit(to.buffer, x + 1, y + 7, STYLE_LABEL)?;
|
to.blit(&"[ Dup ]", x + 1, y + 7, STYLE_LABEL)?;
|
||||||
Ok(Some(to.area))
|
Ok(Some(to.area()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,22 +112,23 @@ struct SequenceKeys<'a>(&'a Sequencer);
|
||||||
|
|
||||||
impl<'a> Render<Tui> for SequenceKeys<'a> {
|
impl<'a> Render<Tui> for SequenceKeys<'a> {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
if to.area.height < 2 {
|
let area = to.area();
|
||||||
return Ok(Some(to.area))
|
if area.height < 2 {
|
||||||
|
return Ok(Some(area))
|
||||||
}
|
}
|
||||||
let area = Rect {
|
let area = Rect {
|
||||||
x: to.area.x,
|
x: area.x,
|
||||||
y: to.area.y + 1,
|
y: area.y + 1,
|
||||||
width: 5,
|
width: 5,
|
||||||
height: to.area.height - 2
|
height: area.height - 2
|
||||||
};
|
};
|
||||||
buffer_update(to.buffer, area, &|cell, x, y|{
|
buffer_update(to.buffer(), area, &|cell, x, y|{
|
||||||
let y = y + self.0.note_axis.start as u16;
|
let y = y + self.0.note_axis.start as u16;
|
||||||
if x < self.0.keys.area.width && y < self.0.keys.area.height {
|
if x < self.0.keys.area.width && y < self.0.keys.area.height {
|
||||||
*cell = self.0.keys.get(x, y).clone()
|
*cell = self.0.keys.get(x, y).clone()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Ok(Some(to.area))
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +185,7 @@ impl<'a> Render<Tui> for SequenceZoom<'a> {
|
||||||
let quant = ppq_to_name(self.0.time_axis.scale);
|
let quant = ppq_to_name(self.0.time_axis.scale);
|
||||||
let quant_x = area.x + area.width - 1 - quant.len() as u16;
|
let quant_x = area.x + area.width - 1 - quant.len() as u16;
|
||||||
let quant_y = area.y + area.height - 2;
|
let quant_y = area.y + area.height - 2;
|
||||||
buffer.blit(&quant, quant_x, quant_y, self.0.style_focus())
|
to.blit(&quant, quant_x, quant_y, self.0.style_focus())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ impl Handle<Tui> for TransportToolbar {
|
||||||
|
|
||||||
impl Handle<Tui> for TransportPlayPauseButton {
|
impl Handle<Tui> for TransportPlayPauseButton {
|
||||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||||
Ok(false)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ impl Handle<Tui> for TransportBPM {
|
||||||
//TransportFocus::BPM => {
|
//TransportFocus::BPM => {
|
||||||
//transport.timebase.bpm.fetch_sub(1.0, Ordering::Relaxed);
|
//transport.timebase.bpm.fetch_sub(1.0, Ordering::Relaxed);
|
||||||
//},
|
//},
|
||||||
Ok(false)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ impl Handle<Tui> for TransportQuantize {
|
||||||
//TransportFocus::Quant => {
|
//TransportFocus::Quant => {
|
||||||
//transport.quant.value = prev_note_length(transport.quant);
|
//transport.quant.value = prev_note_length(transport.quant);
|
||||||
//},
|
//},
|
||||||
Ok(false)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,6 +50,7 @@ impl Handle<Tui> for TransportSync {
|
||||||
//TransportFocus::Sync => {
|
//TransportFocus::Sync => {
|
||||||
//transport.sync.value = prev_note_length(transport.sync);
|
//transport.sync.value = prev_note_length(transport.sync);
|
||||||
//},
|
//},
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +62,6 @@ impl Handle<Tui> for TransportClock {
|
||||||
//TransportFocus::Sync => {
|
//TransportFocus::Sync => {
|
||||||
//transport.sync.value = prev_note_length(transport.sync);
|
//transport.sync.value = prev_note_length(transport.sync);
|
||||||
//},
|
//},
|
||||||
Ok(false)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,12 @@ impl Render<Tui> for TransportBPM {
|
||||||
|
|
||||||
impl Render<Tui> for TransportQuantize {
|
impl Render<Tui> for TransportQuantize {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let area = to.area();
|
let Rect { x, y, .. } = to.area();
|
||||||
let Rect { x, y, .. } = to.area;
|
|
||||||
let Self { value, focused } = self;
|
let Self { value, focused } = self;
|
||||||
"QUANT".blit(to.buffer, x, y, Some(NOT_DIM))?;
|
to.blit(&"QUANT", x, y, Some(NOT_DIM))?;
|
||||||
let width = ppq_to_name(*value as usize).blit(to.buffer, x, y + 1, Some(NOT_DIM_BOLD))?.width;
|
let name = ppq_to_name(*value as usize);
|
||||||
|
let width = name.len() as u16;
|
||||||
|
to.blit(&name, x, y + 1, Some(NOT_DIM_BOLD))?;
|
||||||
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
||||||
if *focused {
|
if *focused {
|
||||||
let area = Rect { x: area.x - 1, width: area.width - 1, ..area };
|
let area = Rect { x: area.x - 1, width: area.width - 1, ..area };
|
||||||
|
|
@ -88,11 +89,12 @@ impl Render<Tui> for TransportQuantize {
|
||||||
|
|
||||||
impl Render<Tui> for TransportSync {
|
impl Render<Tui> for TransportSync {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let area = to.area();
|
let Rect { x, y, .. } = to.area();
|
||||||
let Rect { x, y, .. } = to.area;
|
|
||||||
let Self { value, focused } = self;
|
let Self { value, focused } = self;
|
||||||
"SYNC".blit(to.buffer, x, y, Some(NOT_DIM))?;
|
to.blit(&"SYNC", x, y, Some(NOT_DIM))?;
|
||||||
let width = ppq_to_name(*value as usize).blit(to.buffer, x, y + 1, Some(NOT_DIM_BOLD))?.width;
|
let name = ppq_to_name(*value as usize);
|
||||||
|
let width = name.len() as u16;
|
||||||
|
to.blit(&name, x, y + 1, Some(NOT_DIM_BOLD))?;
|
||||||
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
let area = Rect { x, y, width: (width + 2).max(10), height: 2 };
|
||||||
if *focused {
|
if *focused {
|
||||||
let area = Rect { x: area.x - 1, width: area.width - 1, ..area };
|
let area = Rect { x: area.x - 1, width: area.width - 1, ..area };
|
||||||
|
|
@ -106,7 +108,7 @@ impl Render<Tui> for TransportSync {
|
||||||
impl Render<Tui> for TransportClock {
|
impl Render<Tui> for TransportClock {
|
||||||
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
fn render (&self, to: &mut Tui) -> Perhaps<Rect> {
|
||||||
let Rect { x, y, width, .. } = to.area();
|
let Rect { x, y, width, .. } = to.area();
|
||||||
let Self { frame, pulse, ppq, usecs, focused } = self;
|
let Self { frame: _frame, pulse, ppq, usecs, focused } = self;
|
||||||
let (beats, pulses) = if *ppq > 0 { (pulse / ppq, pulse % ppq) } else { (0, 0) };
|
let (beats, pulses) = if *ppq > 0 { (pulse / ppq, pulse % ppq) } else { (0, 0) };
|
||||||
let (bars, beats) = ((beats / 4) + 1, (beats % 4) + 1);
|
let (bars, beats) = ((beats / 4) + 1, (beats % 4) + 1);
|
||||||
let (seconds, msecs) = (usecs / 1000000, usecs / 1000 % 1000);
|
let (seconds, msecs) = (usecs / 1000000, usecs / 1000 % 1000);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue