mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
wip: big flat pt.8: wh -> xy
This commit is contained in:
parent
da25b28ebf
commit
e958b4a2d2
27 changed files with 117 additions and 117 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
|
@ -1263,10 +1263,8 @@ version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic_float",
|
"atomic_float",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"better-panic",
|
|
||||||
"clap",
|
"clap",
|
||||||
"clojure-reader",
|
"clojure-reader",
|
||||||
"crossterm",
|
|
||||||
"jack",
|
"jack",
|
||||||
"livi",
|
"livi",
|
||||||
"midly",
|
"midly",
|
||||||
|
|
@ -1274,9 +1272,8 @@ dependencies = [
|
||||||
"palette",
|
"palette",
|
||||||
"quanta",
|
"quanta",
|
||||||
"rand",
|
"rand",
|
||||||
"ratatui",
|
|
||||||
"symphonia",
|
"symphonia",
|
||||||
"tek_engine",
|
"tek_layout",
|
||||||
"toml",
|
"toml",
|
||||||
"uuid",
|
"uuid",
|
||||||
"wavers",
|
"wavers",
|
||||||
|
|
@ -1285,6 +1282,18 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tek_engine"
|
name = "tek_engine"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
dependencies = [
|
||||||
|
"better-panic",
|
||||||
|
"crossterm",
|
||||||
|
"ratatui",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tek_layout"
|
||||||
|
version = "0.2.0"
|
||||||
|
dependencies = [
|
||||||
|
"tek_engine",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ edition = "2021"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tek_engine = { path = "./engine" }
|
|
||||||
tek_layout = { path = "./layout" }
|
tek_layout = { path = "./layout" }
|
||||||
|
|
||||||
atomic_float = "1.0.0"
|
atomic_float = "1.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
//use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
/// Rendering target
|
/// Rendering target
|
||||||
pub trait Output<E: Engine> {
|
pub trait Output<E: Engine> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ pub(crate) use better_panic::{Settings, Verbosity};
|
||||||
pub use ::crossterm;
|
pub use ::crossterm;
|
||||||
pub(crate) use crossterm::{
|
pub(crate) use crossterm::{
|
||||||
ExecutableCommand,
|
ExecutableCommand,
|
||||||
event::*,
|
|
||||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode},
|
terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode},
|
||||||
event::{KeyCode, KeyModifiers, KeyEvent, KeyEventKind, KeyEventState},
|
event::{KeyCode, KeyModifiers, KeyEvent, KeyEventKind, KeyEventState},
|
||||||
};
|
};
|
||||||
|
|
@ -115,7 +114,7 @@ impl<T: Render<Tui> + Handle<Tui> + Sized + 'static> TuiRun<T> for Arc<RwLock<Tu
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if ::crossterm::event::poll(poll).is_ok() {
|
if ::crossterm::event::poll(poll).is_ok() {
|
||||||
let event = TuiEvent::Input(::crossterm::event::read().unwrap());
|
let event = ::crossterm::event::read().unwrap();
|
||||||
match event {
|
match event {
|
||||||
key_pat!(Ctrl-KeyCode::Char('c')) => {
|
key_pat!(Ctrl-KeyCode::Char('c')) => {
|
||||||
exited.store(true, Relaxed);
|
exited.store(true, Relaxed);
|
||||||
|
|
@ -161,20 +160,15 @@ impl<T: Render<Tui> + Handle<Tui> + Sized + 'static> TuiRun<T> for Arc<RwLock<Tu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct TuiInput {
|
pub struct TuiInput {
|
||||||
pub(crate) exited: Arc<AtomicBool>,
|
pub(crate) exited: Arc<AtomicBool>,
|
||||||
pub(crate) event: TuiEvent,
|
pub(crate) event: crossterm::event::Event,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum TuiEvent {
|
|
||||||
/// Terminal input
|
|
||||||
Input(Event),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input<Tui> for TuiInput {
|
impl Input<Tui> for TuiInput {
|
||||||
type Event = TuiEvent;
|
type Event = crossterm::event::Event;
|
||||||
fn event (&self) -> &TuiEvent {
|
fn event (&self) -> &crossterm::event::Event {
|
||||||
&self.event
|
&self.event
|
||||||
}
|
}
|
||||||
fn is_done (&self) -> bool {
|
fn is_done (&self) -> bool {
|
||||||
|
|
@ -190,30 +184,30 @@ impl Input<Tui> for TuiInput {
|
||||||
(Ctrl-$code:pat) => { key_event_pat!($code, KeyModifiers::CONTROL) };
|
(Ctrl-$code:pat) => { key_event_pat!($code, KeyModifiers::CONTROL) };
|
||||||
(Alt-$code:pat) => { key_event_pat!($code, KeyModifiers::ALT) };
|
(Alt-$code:pat) => { key_event_pat!($code, KeyModifiers::ALT) };
|
||||||
(Shift-$code:pat) => { key_event_pat!($code, KeyModifiers::SHIFT) };
|
(Shift-$code:pat) => { key_event_pat!($code, KeyModifiers::SHIFT) };
|
||||||
($code:pat) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
($code:pat) => { crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
})) };
|
}) };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export] macro_rules! key_event_pat {
|
#[macro_export] macro_rules! key_event_pat {
|
||||||
($code:pat) => {
|
($code:pat) => {
|
||||||
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
}))
|
})
|
||||||
};
|
};
|
||||||
($code:pat, $modifiers: pat) => {
|
($code:pat, $modifiers: pat) => {
|
||||||
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
modifiers: $modifiers,
|
modifiers: $modifiers,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
}))
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,20 +230,20 @@ impl Input<Tui> for TuiInput {
|
||||||
|
|
||||||
#[macro_export] macro_rules! key_event_expr {
|
#[macro_export] macro_rules! key_event_expr {
|
||||||
($code:expr, $modifiers: expr) => {
|
($code:expr, $modifiers: expr) => {
|
||||||
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
modifiers: $modifiers,
|
modifiers: $modifiers,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
}))
|
})
|
||||||
};
|
};
|
||||||
($code:expr) => {
|
($code:expr) => {
|
||||||
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
}))
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ fn main () -> Usually<()> {
|
||||||
|
|
||||||
pub struct BspDemo<E: Engine>(std::marker::PhantomData<E>);
|
pub struct BspDemo<E: Engine>(std::marker::PhantomData<E>);
|
||||||
|
|
||||||
render!(<Tui>|self:BspDemo<Tui>|Fill::wh(Align::c(
|
render!(<Tui>|self:BspDemo<Tui>|Fill::xy(Align::c(
|
||||||
Bsp::n(Bsp::s(Bsp::e(Bsp::w("00", "11"), "22"), "33"), "44")
|
Bsp::n(Bsp::s(Bsp::e(Bsp::w("00", "11"), "22"), "33"), "44")
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
pub use ::tek_engine;
|
pub use ::tek_engine;
|
||||||
pub(crate) use ::tek_engine::*;
|
pub(crate) use ::tek_engine::*;
|
||||||
|
|
||||||
pub(crate) use std::ops::{Add, Sub, Mul, Div};
|
|
||||||
pub(crate) use std::fmt::{Display, Debug};
|
|
||||||
pub(crate) use std::marker::PhantomData;
|
pub(crate) use std::marker::PhantomData;
|
||||||
pub(crate) use std::sync::atomic::Ordering::*;
|
pub(crate) use std::sync::atomic::Ordering::*;
|
||||||
|
|
||||||
mod collection; pub use self::collection::*;
|
mod collection; pub use self::collection::*;
|
||||||
mod direction; pub use self::direction::*;
|
mod direction; pub use self::direction::*;
|
||||||
mod layers; pub use self::layers::*;
|
|
||||||
mod logic; pub use self::logic::*;
|
mod logic; pub use self::logic::*;
|
||||||
mod space; pub use self::space::*;
|
mod space; pub use self::space::*;
|
||||||
mod transform; pub use self::transform::*;
|
mod transform; pub use self::transform::*;
|
||||||
|
|
|
||||||
|
|
@ -111,13 +111,13 @@ render!(<Tui>|self: ArrangerTui|{
|
||||||
let with_size = |x|lay!([&self.size, x]);
|
let with_size = |x|lay!([&self.size, x]);
|
||||||
let arranger = ||lay!(|add|{
|
let arranger = ||lay!(|add|{
|
||||||
let color = self.color;
|
let color = self.color;
|
||||||
add(&Fill::wh(Tui::bg(color.darkest.rgb, "")))?;
|
add(&Fill::xy(Tui::bg(color.darkest.rgb, "")))?;
|
||||||
add(&Fill::wh(Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb))))?;
|
add(&Fill::xy(Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb))))?;
|
||||||
add(&Self::render_mode(self))
|
add(&Self::render_mode(self))
|
||||||
});
|
});
|
||||||
Some(with_size(with_status(with_editbar(with_pool(with_transport(col!([
|
Some(with_size(with_status(with_editbar(with_pool(with_transport(col!([
|
||||||
Fill::w(Fixed::h(20, arranger())),
|
Fill::x(Fixed::y(20, arranger())),
|
||||||
Fill::wh(&self.editor),
|
Fill::xy(&self.editor),
|
||||||
])))))))
|
])))))))
|
||||||
});
|
});
|
||||||
audio!(|self: ArrangerTui, client, scope|{
|
audio!(|self: ArrangerTui, client, scope|{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use ClockCommand::{Play, Pause};
|
use ClockCommand::{Play, Pause};
|
||||||
use KeyCode::{Char, Delete, Tab, Up, Down, Left, Right};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)] pub enum ArrangerCommand {
|
#[derive(Clone, Debug)] pub enum ArrangerCommand {
|
||||||
History(isize),
|
History(isize),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from!(<'a>|args:(&'a ArrangerTui, usize)|ArrangerVClips<'a> = Self {
|
||||||
rows: ArrangerScene::ppqs(&args.0.scenes, args.1),
|
rows: ArrangerScene::ppqs(&args.0.scenes, args.1),
|
||||||
});
|
});
|
||||||
|
|
||||||
render!(<Tui>|self: ArrangerVClips<'a>|Fill::wh(
|
render!(<Tui>|self: ArrangerVClips<'a>|Fill::xy(
|
||||||
col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => {
|
col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => {
|
||||||
Self::format_scene(self.tracks, scene, pulses)
|
Self::format_scene(self.tracks, scene, pulses)
|
||||||
})
|
})
|
||||||
|
|
@ -27,7 +27,7 @@ impl<'a> ArrangerVClips<'a> {
|
||||||
) -> impl Render<Tui> + use<'a> {
|
) -> impl Render<Tui> + use<'a> {
|
||||||
let height = 1.max((pulses / PPQ) as u16);
|
let height = 1.max((pulses / PPQ) as u16);
|
||||||
let playing = scene.is_playing(tracks);
|
let playing = scene.is_playing(tracks);
|
||||||
Fixed::h(height, row!([
|
Fixed::y(height, row!([
|
||||||
Tui::bg(scene.color.base.rgb,
|
Tui::bg(scene.color.base.rgb,
|
||||||
if playing { "▶ " } else { " " }),
|
if playing { "▶ " } else { " " }),
|
||||||
Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
||||||
|
|
@ -40,7 +40,7 @@ impl<'a> ArrangerVClips<'a> {
|
||||||
fn format_clip (
|
fn format_clip (
|
||||||
scene: &'a ArrangerScene, index: usize, track: &'a ArrangerTrack, w: u16, h: u16
|
scene: &'a ArrangerScene, index: usize, track: &'a ArrangerTrack, w: u16, h: u16
|
||||||
) -> impl Render<Tui> + use<'a> {
|
) -> impl Render<Tui> + use<'a> {
|
||||||
Fixed::wh(w, h, Layers::new(move |add|{
|
Fixed::xy(w, h, Layers::new(move |add|{
|
||||||
if let Some(Some(phrase)) = scene.clips.get(index) {
|
if let Some(Some(phrase)) = scene.clips.get(index) {
|
||||||
let mut bg = TuiTheme::border_bg();
|
let mut bg = TuiTheme::border_bg();
|
||||||
let name = &(phrase as &Arc<RwLock<MidiClip>>).read().unwrap().name.to_string();
|
let name = &(phrase as &Arc<RwLock<MidiClip>>).read().unwrap().name.to_string();
|
||||||
|
|
@ -53,7 +53,7 @@ impl<'a> ArrangerVClips<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
add(&Tui::bg(bg,
|
add(&Tui::bg(bg,
|
||||||
Push::x(1, Fixed::w(w, &name.as_str()[0..max_w])))
|
Push::x(1, Fixed::x(w, &name.as_str()[0..max_w])))
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ render!(<Tui>|self: ArrangerVHead<'a>|Push::x(self.scenes_w, row!(
|
||||||
Tui::fg(color.lightest.rgb, field)
|
Tui::fg(color.lightest.rgb, field)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
Tui::bg(color.base.rgb, Min::xy(w as u16, h, Fixed::wh(w as u16, 5, col!([
|
Tui::bg(color.base.rgb, Min::xy(w as u16, h, Fixed::xy(w as u16, 5, col!([
|
||||||
row(color, &Self::format_name(track, w)),
|
row(color, &Self::format_name(track, w)),
|
||||||
row(color, &Self::format_input(track)?),
|
row(color, &Self::format_input(track)?),
|
||||||
row(color, &Self::format_output(track)?),
|
row(color, &Self::format_output(track)?),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::*;
|
||||||
pub struct Bordered<S: BorderStyle, W: Render<Tui>>(pub S, pub W);
|
pub struct Bordered<S: BorderStyle, W: Render<Tui>>(pub S, pub W);
|
||||||
|
|
||||||
render!(<Tui>|self: Bordered<S: BorderStyle, W: Render<Tui>>|{
|
render!(<Tui>|self: Bordered<S: BorderStyle, W: Render<Tui>>|{
|
||||||
Fill::wh(lay!([Border(self.0), Padding::xy(1, 1, &self.1)]))
|
Fill::xy(lay!([Border(self.0), Padding::xy(1, 1, &self.1)]))
|
||||||
});
|
});
|
||||||
|
|
||||||
pub struct Border<S: BorderStyle>(pub S);
|
pub struct Border<S: BorderStyle>(pub S);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use rand::{thread_rng, distributions::uniform::UniformSampler};
|
use rand::{thread_rng, distributions::uniform::UniformSampler};
|
||||||
pub use ratatui::prelude::Color;
|
|
||||||
|
|
||||||
pub trait HasColor {
|
pub trait HasColor {
|
||||||
fn color (&self) -> ItemColor;
|
fn color (&self) -> ItemColor;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
mod content; pub use self::content::*;
|
|
||||||
mod render; pub use self::render::*;
|
|
||||||
mod handle; pub use self::handle::*;
|
|
||||||
20
src/focus.rs
20
src/focus.rs
|
|
@ -40,17 +40,16 @@ pub enum FocusCommand<T: Send + Sync> {
|
||||||
|
|
||||||
impl<F: HasFocus + HasEnter + FocusGrid + FocusOrder> Command<F> for FocusCommand<F::Item> {
|
impl<F: HasFocus + HasEnter + FocusGrid + FocusOrder> Command<F> for FocusCommand<F::Item> {
|
||||||
fn execute (self, state: &mut F) -> Perhaps<FocusCommand<F::Item>> {
|
fn execute (self, state: &mut F) -> Perhaps<FocusCommand<F::Item>> {
|
||||||
use FocusCommand::*;
|
|
||||||
match self {
|
match self {
|
||||||
Next => { state.focus_next(); },
|
Self::Next => { state.focus_next(); },
|
||||||
Prev => { state.focus_prev(); },
|
Self::Prev => { state.focus_prev(); },
|
||||||
Up => { state.focus_up(); },
|
Self::Up => { state.focus_up(); },
|
||||||
Down => { state.focus_down(); },
|
Self::Down => { state.focus_down(); },
|
||||||
Left => { state.focus_left(); },
|
Self::Left => { state.focus_left(); },
|
||||||
Right => { state.focus_right(); },
|
Self::Right => { state.focus_right(); },
|
||||||
Enter => { state.focus_enter(); },
|
Self::Enter => { state.focus_enter(); },
|
||||||
Exit => { state.focus_exit(); },
|
Self::Exit => { state.focus_exit(); },
|
||||||
Set(to) => { state.set_focused(to); },
|
Self::Set(to) => { state.set_focused(to); },
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +247,6 @@ pub trait FocusWrap<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_focus_command <T: Send + Sync> (input: &TuiInput) -> Option<FocusCommand<T>> {
|
pub fn to_focus_command <T: Send + Sync> (input: &TuiInput) -> Option<FocusCommand<T>> {
|
||||||
use KeyCode::{Tab, BackTab, Up, Down, Left, Right, Enter, Esc};
|
|
||||||
Some(match input.event() {
|
Some(match input.event() {
|
||||||
key_pat!(Tab) => FocusCommand::Next,
|
key_pat!(Tab) => FocusCommand::Next,
|
||||||
key_pat!(Shift-Tab) => FocusCommand::Prev,
|
key_pat!(Shift-Tab) => FocusCommand::Prev,
|
||||||
|
|
|
||||||
|
|
@ -120,23 +120,23 @@ render!(<Tui>|self:Groovebox|{
|
||||||
let color = self.player.play_phrase().as_ref()
|
let color = self.player.play_phrase().as_ref()
|
||||||
.and_then(|(_,p)|p.as_ref().map(|p|p.read().unwrap().color))
|
.and_then(|(_,p)|p.as_ref().map(|p|p.read().unwrap().color))
|
||||||
.clone();
|
.clone();
|
||||||
let transport = Fixed::h(3, row!([
|
let transport = Fixed::y(3, row!([
|
||||||
PlayPause(self.clock().is_rolling()),
|
PlayPause(self.clock().is_rolling()),
|
||||||
TransportView::new(self, color, true),
|
TransportView::new(self, color, true),
|
||||||
]));
|
]));
|
||||||
let selector = Push::x(sampler_w, Fixed::h(1, row!(![
|
let selector = Push::x(sampler_w, Fixed::y(1, row!(![
|
||||||
PhraseSelector::play_phrase(&self.player),
|
PhraseSelector::play_phrase(&self.player),
|
||||||
PhraseSelector::next_phrase(&self.player),
|
PhraseSelector::next_phrase(&self.player),
|
||||||
])));
|
])));
|
||||||
let pool = move|x|Split::w(false, pool_w, Pull::y(1, Fill::h(Align::e(PoolView(&self.pool)))), x);
|
let pool = move|x|Split::w(false, pool_w, Pull::y(1, Fill::y(Align::e(PoolView(&self.pool)))), x);
|
||||||
let sampler = move|x|Split::e(false, sampler_w, Fill::wh(col!([
|
let sampler = move|x|Split::e(false, sampler_w, Fill::xy(col!([
|
||||||
Meters(self.sampler.input_meter.as_ref()),
|
Meters(self.sampler.input_meter.as_ref()),
|
||||||
GrooveboxSamples(self)
|
GrooveboxSamples(self)
|
||||||
])), x);
|
])), x);
|
||||||
let status = EditStatus(&self.sampler, &self.editor, note_pt, pool(sampler(&self.editor)));
|
let status = EditStatus(&self.sampler, &self.editor, note_pt, pool(sampler(&self.editor)));
|
||||||
Fill::wh(lay!([
|
Fill::xy(lay!([
|
||||||
&self.size,
|
&self.size,
|
||||||
Fill::wh(Align::s(Fixed::h(2, GrooveboxStatus::from(self)))),
|
Fill::xy(Align::s(Fixed::y(2, GrooveboxStatus::from(self)))),
|
||||||
Shrink::y(2, col!(![transport, selector, status]))
|
Shrink::y(2, col!(![transport, selector, status]))
|
||||||
]))
|
]))
|
||||||
});
|
});
|
||||||
|
|
@ -154,7 +154,7 @@ impl<'a, T: Render<Tui>> Content<Tui> for EditStatus<'a, T> {
|
||||||
}),
|
}),
|
||||||
lay!([
|
lay!([
|
||||||
Outer(Style::default().fg(TuiTheme::g(128))),
|
Outer(Style::default().fg(TuiTheme::g(128))),
|
||||||
Fill::w(Fixed::h(8, if let Some((_, sample)) = &self.0.recording {
|
Fill::x(Fixed::y(8, if let Some((_, sample)) = &self.0.recording {
|
||||||
SampleViewer(Some(sample.clone()))
|
SampleViewer(Some(sample.clone()))
|
||||||
} else if let Some(sample) = &self.0.mapped[self.2] {
|
} else if let Some(sample) = &self.0.mapped[self.2] {
|
||||||
SampleViewer(Some(sample.clone()))
|
SampleViewer(Some(sample.clone()))
|
||||||
|
|
@ -171,7 +171,7 @@ render!(<Tui>|self: GrooveboxSamples<'a>|{
|
||||||
let note_lo = self.0.editor.note_lo().load(Relaxed);
|
let note_lo = self.0.editor.note_lo().load(Relaxed);
|
||||||
let note_pt = self.0.editor.note_point();
|
let note_pt = self.0.editor.note_point();
|
||||||
let note_hi = self.0.editor.note_hi();
|
let note_hi = self.0.editor.note_hi();
|
||||||
Fill::wh(col!(note in (note_lo..=note_hi).rev() => {
|
Fill::xy(col!(note in (note_lo..=note_hi).rev() => {
|
||||||
let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset };
|
let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset };
|
||||||
let mut fg = TuiTheme::g(160);
|
let mut fg = TuiTheme::g(160);
|
||||||
if let Some((index, _)) = self.0.sampler.recording {
|
if let Some((index, _)) = self.0.sampler.recording {
|
||||||
|
|
|
||||||
31
src/lib.rs
31
src/lib.rs
|
|
@ -1,18 +1,30 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
|
|
||||||
pub use ::tek_engine::*;
|
pub use ::tek_layout;
|
||||||
pub(crate) use ::tek_engine::{
|
pub use ::tek_layout::tek_engine;
|
||||||
|
|
||||||
|
pub(crate) use ::tek_layout::{
|
||||||
|
*,
|
||||||
|
tek_engine::{
|
||||||
|
Usually, Perhaps,
|
||||||
|
Engine, Size, Area,
|
||||||
|
Content, Render, render,
|
||||||
|
Handle, handle, kexp, key_pat, key_event_pat, key_event_expr,
|
||||||
|
Tui, TuiInput, TuiOutput,
|
||||||
crossterm::{
|
crossterm::{
|
||||||
ExecutableCommand,
|
self,
|
||||||
EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode};
|
event::{
|
||||||
KeyCode, KeyModifiers, KeyEvent, KeyEventKind, KeyEventState
|
KeyEvent, KeyEventKind, KeyEventState, KeyModifiers,
|
||||||
|
KeyCode::{self, *},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ratatui::{
|
ratatui::{
|
||||||
prelude::{Style, Buffer},
|
self,
|
||||||
style::{Stylize, Modifier},
|
prelude::{Color, Style, Buffer, Modifier},
|
||||||
backend::{Backend, CrosstermBackend, ClearType}
|
buffer::Cell,
|
||||||
},
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use std::cmp::{Ord, Eq, PartialEq};
|
pub(crate) use std::cmp::{Ord, Eq, PartialEq};
|
||||||
|
|
@ -33,7 +45,6 @@ pub mod arranger; pub use self::arranger::*;
|
||||||
pub mod border; pub use self::border::*;
|
pub mod border; pub use self::border::*;
|
||||||
pub mod color; pub use self::color::*;
|
pub mod color; pub use self::color::*;
|
||||||
pub mod command; pub use self::command::*;
|
pub mod command; pub use self::command::*;
|
||||||
pub mod engine; pub use self::engine::*;
|
|
||||||
pub mod event; pub use self::event::*;
|
pub mod event; pub use self::event::*;
|
||||||
pub mod file; pub use self::file::*;
|
pub mod file; pub use self::file::*;
|
||||||
pub mod focus; pub use self::focus::*;
|
pub mod focus; pub use self::focus::*;
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ render!(<Tui>|self: PianoHorizontal|{
|
||||||
|
|
||||||
let cursor = move||PianoHorizontalCursor(self);
|
let cursor = move||PianoHorizontalCursor(self);
|
||||||
|
|
||||||
let border = Fill::wh(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb)));
|
let border = Fill::xy(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb)));
|
||||||
let with_border = |x|lay!([border, Padding::xy(0, 0, &x)]);
|
let with_border = |x|lay!([border, Padding::xy(0, 0, &x)]);
|
||||||
|
|
||||||
with_border(lay!([
|
with_border(lay!([
|
||||||
|
|
@ -86,18 +86,18 @@ render!(<Tui>|self: PianoHorizontal|{
|
||||||
field("Length:", length.to_string()), " ",
|
field("Length:", length.to_string()), " ",
|
||||||
field("Loop:", looped.to_string())
|
field("Loop:", looped.to_string())
|
||||||
])),
|
])),
|
||||||
Padding::xy(0, 1, Fill::wh(Bsp::s(
|
Padding::xy(0, 1, Fill::xy(Bsp::s(
|
||||||
Fixed::h(1, Bsp::e(
|
Fixed::y(1, Bsp::e(
|
||||||
Fixed::w(self.keys_width, ""),
|
Fixed::x(self.keys_width, ""),
|
||||||
Fill::w(timeline()),
|
Fill::w(timeline()),
|
||||||
)),
|
)),
|
||||||
Bsp::e(
|
Bsp::e(
|
||||||
Fixed::w(self.keys_width, keys()),
|
Fixed::x(self.keys_width, keys()),
|
||||||
Fill::wh(lay!([
|
Fill::xy(lay!([
|
||||||
&self.size,
|
&self.size,
|
||||||
Fill::wh(lay!([
|
Fill::xy(lay!([
|
||||||
Fill::wh(notes()),
|
Fill::xy(notes()),
|
||||||
Fill::wh(cursor()),
|
Fill::xy(cursor()),
|
||||||
]))
|
]))
|
||||||
])),
|
])),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
16
src/pool.rs
16
src/pool.rs
|
|
@ -208,9 +208,9 @@ render!(<Tui>|self: PoolView<'a>|{
|
||||||
let upper_right = format!("({})", phrases.len());
|
let upper_right = format!("({})", phrases.len());
|
||||||
let color = self.0.phrase().read().unwrap().color;
|
let color = self.0.phrase().read().unwrap().color;
|
||||||
Tui::bg(bg, lay!(move|add|{
|
Tui::bg(bg, lay!(move|add|{
|
||||||
add(&Fill::wh(Outer(Style::default().fg(color.base.rgb).bg(bg))))?;
|
add(&Fill::xy(Outer(Style::default().fg(color.base.rgb).bg(bg))))?;
|
||||||
//add(&Lozenge(Style::default().bg(border_bg).fg(border_color)))?;
|
//add(&Lozenge(Style::default().bg(border_bg).fg(border_color)))?;
|
||||||
add(&Padding::xy(0, 1, Fill::wh(col!(move|add|match mode {
|
add(&Padding::xy(0, 1, Fill::xy(col!(move|add|match mode {
|
||||||
Some(PoolMode::Import(_, ref file_picker)) => add(file_picker),
|
Some(PoolMode::Import(_, ref file_picker)) => add(file_picker),
|
||||||
Some(PoolMode::Export(_, ref file_picker)) => add(file_picker),
|
Some(PoolMode::Export(_, ref file_picker)) => add(file_picker),
|
||||||
_ => Ok(for (i, phrase) in phrases.iter().enumerate() {
|
_ => Ok(for (i, phrase) in phrases.iter().enumerate() {
|
||||||
|
|
@ -223,10 +223,10 @@ render!(<Tui>|self: PoolView<'a>|{
|
||||||
length.focus = Some(*focus);
|
length.focus = Some(*focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add(&Tui::bg(color.base.rgb, Fill::w(col!([
|
add(&Tui::bg(color.base.rgb, Fill::x(col!([
|
||||||
Fill::w(lay!(|add|{
|
Fill::x(lay!(|add|{
|
||||||
add(&Fill::w(Align::w(format!(" {i}"))))?;
|
add(&Fill::x(Align::w(format!(" {i}"))))?;
|
||||||
add(&Fill::w(Align::e(Pull::x(1, length.clone()))))
|
add(&Fill::x(Align::e(Pull::x(1, length.clone()))))
|
||||||
})),
|
})),
|
||||||
Tui::bold(true, {
|
Tui::bold(true, {
|
||||||
let mut row2 = format!(" {name}");
|
let mut row2 = format!(" {name}");
|
||||||
|
|
@ -245,8 +245,8 @@ render!(<Tui>|self: PoolView<'a>|{
|
||||||
}))?;
|
}))?;
|
||||||
})
|
})
|
||||||
}))))?;
|
}))))?;
|
||||||
add(&Fill::w(Align::nw(Push::x(1, Tui::fg(title_color, upper_left.to_string())))))?;
|
add(&Fill::x(Align::nw(Push::x(1, Tui::fg(title_color, upper_left.to_string())))))?;
|
||||||
add(&Fill::w(Align::ne(Pull::x(1, Tui::fg(title_color, upper_right.to_string())))))?;
|
add(&Fill::x(Align::ne(Pull::x(1, Tui::fg(title_color, upper_right.to_string())))))?;
|
||||||
add(&self.0.size)
|
add(&self.0.size)
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct PhraseSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Display phrases always in order of appearance
|
// TODO: Display phrases always in order of appearance
|
||||||
render!(<Tui>|self: PhraseSelector|Fixed::wh(24, 1, row!([
|
render!(<Tui>|self: PhraseSelector|Fixed::xy(24, 1, row!([
|
||||||
Tui::fg(self.color.lightest.rgb, Tui::bold(true, &self.title)),
|
Tui::fg(self.color.lightest.rgb, Tui::bold(true, &self.title)),
|
||||||
Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!([
|
Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!([
|
||||||
format!("{:8}", &self.name[0..8.min(self.name.len())]),
|
format!("{:8}", &self.name[0..8.min(self.name.len())]),
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,14 @@ render!(<Tui>|self: SamplerTui|{
|
||||||
let keys = move||"";//SamplerKeys(self);
|
let keys = move||"";//SamplerKeys(self);
|
||||||
let fg = self.color.base.rgb;
|
let fg = self.color.base.rgb;
|
||||||
let bg = self.color.darkest.rgb;
|
let bg = self.color.darkest.rgb;
|
||||||
let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg)));
|
let border = Fill::xy(Outer(Style::default().fg(fg).bg(bg)));
|
||||||
let with_border = |x|lay!([border, Fill::wh(&x)]);
|
let with_border = |x|lay!([border, Fill::xy(&x)]);
|
||||||
let with_size = |x|lay!([self.size, x]);
|
let with_size = |x|lay!([self.size, x]);
|
||||||
Tui::bg(bg, Fill::wh(with_border(Bsp::s(
|
Tui::bg(bg, Fill::xy(with_border(Bsp::s(
|
||||||
Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler")),
|
Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler")),
|
||||||
with_size(Shrink::y(1, Bsp::e(
|
with_size(Shrink::y(1, Bsp::e(
|
||||||
Fixed::w(keys_width, keys()),
|
Fixed::x(keys_width, keys()),
|
||||||
Fill::wh(render(|to: &mut TuiOutput|Ok({
|
Fill::xy(render(|to: &mut TuiOutput|Ok({
|
||||||
let x = to.area.x();
|
let x = to.area.x();
|
||||||
let bg_base = self.color.darkest.rgb;
|
let bg_base = self.color.darkest.rgb;
|
||||||
let bg_selected = self.color.darker.rgb;
|
let bg_selected = self.color.darker.rgb;
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,13 @@ render!(<Tui>|self: SequencerTui|{
|
||||||
let w = self.size.w();
|
let w = self.size.w();
|
||||||
let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
||||||
let pool_w = if self.phrases.visible { phrase_w } else { 0 };
|
let pool_w = if self.phrases.visible { phrase_w } else { 0 };
|
||||||
let pool = Pull::y(1, Fill::h(Align::e(PoolView(&self.phrases))));
|
let pool = Pull::y(1, Fill::y(Align::e(PoolView(&self.phrases))));
|
||||||
let with_pool = move|x|Split::w(false, pool_w, pool, x);
|
let with_pool = move|x|Split::w(false, pool_w, pool, x);
|
||||||
let status = SequencerStatus::from(self);
|
let status = SequencerStatus::from(self);
|
||||||
let with_status = |x|Split::n(false, if self.status { 2 } else { 0 }, status, x);
|
let with_status = |x|Split::n(false, if self.status { 2 } else { 0 }, status, x);
|
||||||
let with_editbar = |x|Split::n(false, 1, MidiEditStatus(&self.editor), x);
|
let with_editbar = |x|Split::n(false, 1, MidiEditStatus(&self.editor), x);
|
||||||
let with_size = |x|lay!([self.size, x]);
|
let with_size = |x|lay!([self.size, x]);
|
||||||
let editor = with_editbar(with_pool(Fill::wh(&self.editor)));
|
let editor = with_editbar(with_pool(Fill::xy(&self.editor)));
|
||||||
|
|
||||||
let color = self.player.play_phrase().as_ref().map(|(_,p)|
|
let color = self.player.play_phrase().as_ref().map(|(_,p)|
|
||||||
p.as_ref().map(|p|p.read().unwrap().color)
|
p.as_ref().map(|p|p.read().unwrap().color)
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ from!(|state:&ArrangerTui|ArrangerStatus = {
|
||||||
size: format!("{}x{}│", width, state.size.h()),
|
size: format!("{}x{}│", width, state.size.h()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
render!(<Tui>|self: ArrangerStatus|Fixed::h(2, lay!([
|
render!(<Tui>|self: ArrangerStatus|Fixed::y(2, lay!([
|
||||||
Self::help(),
|
Self::help(),
|
||||||
Fill::wh(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
|
Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
|
||||||
])));
|
])));
|
||||||
impl ArrangerStatus {
|
impl ArrangerStatus {
|
||||||
fn help () -> impl Render<Tui> {
|
fn help () -> impl Render<Tui> {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ render!(<Tui>|self:MidiEditStatus<'a>|{
|
||||||
|
|
||||||
let bg = color.darkest.rgb;
|
let bg = color.darkest.rgb;
|
||||||
let fg = color.lightest.rgb;
|
let fg = color.lightest.rgb;
|
||||||
Tui::bg(bg, Fill::w(Tui::fg(fg, row!([
|
Tui::bg(bg, Fill::x(Tui::fg(fg, row!([
|
||||||
field(" Time", format!("{}/{}-{} ({}*{}) {}",
|
field(" Time", format!("{}/{}-{} ({}*{}) {}",
|
||||||
self.0.time_point(), self.0.time_start().get(), self.0.time_end(),
|
self.0.time_point(), self.0.time_start().get(), self.0.time_end(),
|
||||||
self.0.time_axis().get(), self.0.time_zoom().get(),
|
self.0.time_axis().get(), self.0.time_zoom().get(),
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ from!(|state: &Groovebox|GrooveboxStatus = {
|
||||||
size: format!("{}x{}│", width, state.size.h()),
|
size: format!("{}x{}│", width, state.size.h()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
render!(<Tui>|self: GrooveboxStatus|Fixed::h(2, lay!([
|
render!(<Tui>|self: GrooveboxStatus|Fixed::y(2, lay!([
|
||||||
Self::help(),
|
Self::help(),
|
||||||
Fill::wh(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
|
Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
|
||||||
])));
|
])));
|
||||||
impl GrooveboxStatus {
|
impl GrooveboxStatus {
|
||||||
fn help () -> impl Render<Tui> {
|
fn help () -> impl Render<Tui> {
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ from!(|state:&SequencerTui|SequencerStatus = {
|
||||||
size: format!("{}x{}│", width, state.size.h()),
|
size: format!("{}x{}│", width, state.size.h()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
render!(<Tui>|self: SequencerStatus|Fixed::h(2, lay!([
|
render!(<Tui>|self: SequencerStatus|Fixed::y(2, lay!([
|
||||||
Self::help(),
|
Self::help(),
|
||||||
Fill::wh(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
|
Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
|
||||||
])));
|
])));
|
||||||
impl SequencerStatus {
|
impl SequencerStatus {
|
||||||
fn help () -> impl Render<Tui> {
|
fn help () -> impl Render<Tui> {
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ has_clock!(|self: TransportTui|&self.clock);
|
||||||
audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope));
|
audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope));
|
||||||
handle!(<Tui>|self: TransportTui, from|TransportCommand::execute_with_state(self, from));
|
handle!(<Tui>|self: TransportTui, from|TransportCommand::execute_with_state(self, from));
|
||||||
render!(<Tui>|self: TransportTui|row!([
|
render!(<Tui>|self: TransportTui|row!([
|
||||||
Fixed::wh(5, 3, PlayPause(false)),
|
Fixed::xy(5, 3, PlayPause(false)),
|
||||||
Fixed::h(3, TransportView::new(self, None, true))
|
Fixed::y(3, TransportView::new(self, None, true))
|
||||||
]));
|
]));
|
||||||
impl std::fmt::Debug for TransportTui {
|
impl std::fmt::Debug for TransportTui {
|
||||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||||
|
|
@ -87,7 +87,7 @@ impl TransportView {
|
||||||
}
|
}
|
||||||
render!(<Tui>|self: TransportView|{
|
render!(<Tui>|self: TransportView|{
|
||||||
let color = self.color;
|
let color = self.color;
|
||||||
Fixed::h(3, Tui::bg(color.base.rgb, Fill::w(row!([
|
Fixed::y(3, Tui::bg(color.base.rgb, Fill::x(row!([
|
||||||
//PlayPause(self.started), " ",
|
//PlayPause(self.started), " ",
|
||||||
col!([
|
col!([
|
||||||
TransportField(" Beat", self.beat.as_str(), &color),
|
TransportField(" Beat", self.beat.as_str(), &color),
|
||||||
|
|
@ -114,7 +114,7 @@ render!(<Tui>|self: TransportField<'a>|row!([
|
||||||
pub struct PlayPause(pub bool);
|
pub struct PlayPause(pub bool);
|
||||||
render!(<Tui>|self: PlayPause|Tui::bg(
|
render!(<Tui>|self: PlayPause|Tui::bg(
|
||||||
if self.0{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)},
|
if self.0{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)},
|
||||||
Fixed::w(5, col!(|add|if self.0 {
|
Fixed::x(5, col!(|add|if self.0 {
|
||||||
add(&Tui::fg(Color::Rgb(0, 255, 0), col!([
|
add(&Tui::fg(Color::Rgb(0, 255, 0), col!([
|
||||||
" 🭍🭑🬽 ",
|
" 🭍🭑🬽 ",
|
||||||
" 🭞🭜🭘 ",
|
" 🭞🭜🭘 ",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue