mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
edn stub examples are now runnable
the Render/Content trait pair is very finicky
This commit is contained in:
parent
f1b3fc0040
commit
f6c603bf73
9 changed files with 69 additions and 56 deletions
8
Justfile
8
Justfile
|
|
@ -118,3 +118,11 @@ sampler:
|
||||||
plugin:
|
plugin:
|
||||||
reset
|
reset
|
||||||
cargo run --bin tek_plugin
|
cargo run --bin tek_plugin
|
||||||
|
|
||||||
|
edn01:
|
||||||
|
reset
|
||||||
|
cd edn && cargo run --example edn01
|
||||||
|
|
||||||
|
edn02:
|
||||||
|
reset
|
||||||
|
cd edn && cargo run --example edn02
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,16 @@ fn main () -> Usually<()> {
|
||||||
|
|
||||||
pub struct Example;
|
pub struct Example;
|
||||||
|
|
||||||
impl EdnLayout<Tui> for Example {
|
impl EdnLayout<Tui> for &Example {
|
||||||
fn get_content <'a> (&'a self, sym: &'a str) -> Box<EdnRender<'a, Tui>> {
|
fn get_content <'a> (&'a self, sym: &'a str) -> Box<EdnRender<'a, Tui>> {
|
||||||
Box::new(Thunk::new(move||if sym == ":hello" { "Hello world!" } else { "" }))
|
Box::new(Thunk::new(move||if sym == ":hello" { "Hello world!" } else { "" }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Content<Tui> for Example {
|
||||||
|
fn content (&self) -> impl Render<Tui> {
|
||||||
|
EdnView::new(self, EDN).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Handle<Tui> for Example {}
|
impl Handle<Tui> for Example {}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,16 @@ fn main () -> Usually<()> {
|
||||||
|
|
||||||
pub struct Example;
|
pub struct Example;
|
||||||
|
|
||||||
impl EdnLayout<Tui> for Example {
|
impl EdnLayout<Tui> for &Example {
|
||||||
fn get_content <'a> (&'a self, sym: &'a str) -> Box<EdnRender<'a, Tui>> {
|
fn get_content <'a> (&'a self, sym: &'a str) -> Box<EdnRender<'a, Tui>> {
|
||||||
Box::new(Thunk::new(move||if sym == ":hello" { "Hello world!" } else { "" }))
|
Box::new(Thunk::new(move||if sym == ":hello" { "Hello world!" } else { "" }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Content<Tui> for Example {
|
||||||
|
fn content (&self) -> impl Render<Tui> {
|
||||||
|
EdnView::new(self, EDN).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Handle<Tui> for Example {}
|
impl Handle<Tui> for Example {}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ impl TuiOut {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render<Tui> for &str {
|
impl Content<Tui> for &str {
|
||||||
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
||||||
to.center_xy([self.chars().count() as u16, 1])
|
to.center_xy([self.chars().count() as u16, 1])
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +74,7 @@ impl Render<Tui> for &str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render<Tui> for String {
|
impl Content<Tui> for String {
|
||||||
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
||||||
to.center_xy([self.chars().count() as u16, 1])
|
to.center_xy([self.chars().count() as u16, 1])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,8 @@ mod groovebox_audio; pub use self::groovebox_audio::*;
|
||||||
mod groovebox_command; pub use self::groovebox_command::*;
|
mod groovebox_command; pub use self::groovebox_command::*;
|
||||||
mod groovebox_tui; pub use self::groovebox_tui::*;
|
mod groovebox_tui; pub use self::groovebox_tui::*;
|
||||||
|
|
||||||
pub struct Groovebox<'a> {
|
pub struct Groovebox {
|
||||||
_jack: Arc<RwLock<JackConnection>>,
|
_jack: Arc<RwLock<JackConnection>>,
|
||||||
pub view: EdnView<'a, Tui, Self>,
|
|
||||||
|
|
||||||
pub player: MidiPlayer,
|
pub player: MidiPlayer,
|
||||||
pub pool: PoolModel,
|
pub pool: PoolModel,
|
||||||
pub editor: MidiEditor,
|
pub editor: MidiEditor,
|
||||||
|
|
@ -27,7 +25,7 @@ pub struct Groovebox<'a> {
|
||||||
pub perf: PerfModel,
|
pub perf: PerfModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Groovebox<'a> {
|
impl Groovebox {
|
||||||
pub fn new (
|
pub fn new (
|
||||||
jack: &Arc<RwLock<JackConnection>>,
|
jack: &Arc<RwLock<JackConnection>>,
|
||||||
midi_from: &[impl AsRef<str>],
|
midi_from: &[impl AsRef<str>],
|
||||||
|
|
@ -57,49 +55,44 @@ impl<'a> Groovebox<'a> {
|
||||||
midi_buf: vec![vec![];65536],
|
midi_buf: vec![vec![];65536],
|
||||||
note_buf: vec![],
|
note_buf: vec![],
|
||||||
perf: PerfModel::default(),
|
perf: PerfModel::default(),
|
||||||
|
|
||||||
view: EdnView::new(include_str!("groovebox/groovebox.edn"))?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
has_clock!(|self: Groovebox<'a>|self.player.clock());
|
has_clock!(|self: Groovebox|self.player.clock());
|
||||||
|
|
||||||
impl<'a> EdnLayout<'a, Tui> for Groovebox<'a> {
|
impl EdnLayout<Tui> for Groovebox {
|
||||||
fn get_bool (&self, item: &EdnItem<&str>) -> bool { todo!() }
|
fn get_bool (&self, item: &str) -> bool { todo!() }
|
||||||
fn get_unit (&self, item: &EdnItem<&str>) -> u16 {
|
fn get_unit (&self, item: &str) -> u16 {
|
||||||
use EdnItem::*;
|
use EdnItem::*;
|
||||||
match item {
|
match item {
|
||||||
Sym(":sample-h") => if self.compact { 0 } else { 5 },
|
":sample-h" => if self.compact { 0 } else { 5 },
|
||||||
Sym(":samples-w") => if self.compact { 4 } else { 11 },
|
":samples-w" => if self.compact { 4 } else { 11 },
|
||||||
Sym(":samples-y") => if self.compact { 1 } else { 0 },
|
":samples-y" => if self.compact { 1 } else { 0 },
|
||||||
Sym(":pool-w") => if self.compact { 5 } else {
|
":pool-w" => if self.compact { 5 } else {
|
||||||
let w = self.size.w();
|
let w = self.size.w();
|
||||||
if w > 60 { 20 } else if w > 40 { 15 } else { 10 }
|
if w > 60 { 20 } else if w > 40 { 15 } else { 10 }
|
||||||
},
|
},
|
||||||
_ => 0
|
_ => 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_content (&'a self, item: &EdnItem<&str>) -> Box<EdnRender<'a, Tui>> {
|
fn get_content <'a> (&'a self, item: &str) -> Box<EdnRender<'a, Tui>> {
|
||||||
use EdnItem::*;
|
use EdnItem::*;
|
||||||
match item {
|
match item {
|
||||||
Sym(":input-meter-l") => Box::new(Meter("L/", self.sampler.input_meter[0])),
|
":input-meter-l" => Box::new(Meter("L/", self.sampler.input_meter[0])),
|
||||||
Sym(":input-meter-r") => Box::new(Meter("R/", self.sampler.input_meter[1])),
|
":input-meter-r" => Box::new(Meter("R/", self.sampler.input_meter[1])),
|
||||||
|
|
||||||
Sym(":transport") => Box::new(TransportView::new(true, &self.player.clock)),
|
":transport" => Box::new(TransportView::new(true, &self.player.clock)),
|
||||||
Sym(":clip-play") => Box::new(ClipSelected::play_phrase(&self.player)),
|
":clip-play" => Box::new(ClipSelected::play_phrase(&self.player)),
|
||||||
Sym(":clip-next") => Box::new(ClipSelected::next_phrase(&self.player)),
|
":clip-next" => Box::new(ClipSelected::next_phrase(&self.player)),
|
||||||
Sym(":clip-edit") => Box::new(MidiEditClip(&self.editor)),
|
":clip-edit" => Box::new(MidiEditClip(&self.editor)),
|
||||||
Sym(":edit-stat") => Box::new(MidiEditStatus(&self.editor)),
|
":edit-stat" => Box::new(MidiEditStatus(&self.editor)),
|
||||||
Sym(":pool-view") => Box::new(PoolView(self.compact, &self.pool)),
|
":pool-view" => Box::new(PoolView(self.compact, &self.pool)),
|
||||||
Sym(":midi-view") => Box::new(&self.editor),
|
":midi-view" => Box::new(&self.editor),
|
||||||
|
|
||||||
Sym(":sample-view") => Box::new(SampleViewer::from_sampler(
|
":sample-view" => Box::new(SampleViewer::from_sampler(&self.sampler, self.editor.note_point())),
|
||||||
&self.sampler, self.editor.note_point())),
|
":sample-stat" => Box::new(SamplerStatus(&self.sampler, self.editor.note_point())),
|
||||||
Sym(":sample-stat") => Box::new(SamplerStatus(
|
":samples-view" => Box::new(SampleList::new(self.compact, &self.sampler, &self.editor)),
|
||||||
&self.sampler, self.editor.note_point())),
|
|
||||||
Sym(":samples-view") => Box::new(SampleList::new(
|
|
||||||
self.compact, &self.sampler, &self.editor)),
|
|
||||||
|
|
||||||
_ => Box::new(())
|
_ => Box::new(())
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +107,7 @@ pub struct GrooveboxStatus {
|
||||||
pub(crate) size: String,
|
pub(crate) size: String,
|
||||||
pub(crate) playing: bool,
|
pub(crate) playing: bool,
|
||||||
}
|
}
|
||||||
from!(|state: &Groovebox<'_>|GrooveboxStatus = {
|
from!(|state: &Groovebox|GrooveboxStatus = {
|
||||||
let samples = state.clock().chunk.load(Relaxed);
|
let samples = state.clock().chunk.load(Relaxed);
|
||||||
let rate = state.clock().timebase.sr.get();
|
let rate = state.clock().timebase.sr.get();
|
||||||
let buffer = samples as f64 / rate;
|
let buffer = samples as f64 / rate;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
audio!(|self: Groovebox<'a>, client, scope|{
|
audio!(|self: Groovebox, client, scope|{
|
||||||
let t0 = self.perf.get_t0();
|
let t0 = self.perf.get_t0();
|
||||||
if Control::Quit == ClockAudio(&mut self.player).process(client, scope) {
|
if Control::Quit == ClockAudio(&mut self.player).process(client, scope) {
|
||||||
return Control::Quit
|
return Control::Quit
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ pub enum GrooveboxCommand {
|
||||||
Sampler(SamplerCommand),
|
Sampler(SamplerCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
command!(<'a>|self: GrooveboxCommand, state: Groovebox<'a>|match self {
|
command!(|self: GrooveboxCommand, state: Groovebox|match self {
|
||||||
Self::Enqueue(phrase) => {
|
Self::Enqueue(phrase) => {
|
||||||
state.player.enqueue_next(phrase.as_ref());
|
state.player.enqueue_next(phrase.as_ref());
|
||||||
None
|
None
|
||||||
|
|
@ -46,10 +46,10 @@ command!(<'a>|self: GrooveboxCommand, state: Groovebox<'a>|match self {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
handle!(<Tui>|self: Groovebox<'static>, input|
|
handle!(<Tui>|self: Groovebox, input|
|
||||||
GrooveboxCommand::execute_with_state(self, input.event()));
|
GrooveboxCommand::execute_with_state(self, input.event()));
|
||||||
|
|
||||||
keymap!(<'a> KEYS_GROOVEBOX = |state: Groovebox<'static>, input: Event| GrooveboxCommand {
|
keymap!(<'a> KEYS_GROOVEBOX = |state: Groovebox, input: Event| GrooveboxCommand {
|
||||||
// Tab: Toggle compact mode
|
// Tab: Toggle compact mode
|
||||||
key(Tab) => Cmd::Compact(!state.compact),
|
key(Tab) => Cmd::Compact(!state.compact),
|
||||||
// q: Enqueue currently edited phrase
|
// q: Enqueue currently edited phrase
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ use std::marker::ConstParamTy;
|
||||||
use tek_engine::Render;
|
use tek_engine::Render;
|
||||||
use EdnItem::*;
|
use EdnItem::*;
|
||||||
|
|
||||||
render!(Tui: (self: Groovebox<'a>) => self.size.of(
|
render!(Tui: (self: Groovebox) => self.size.of(
|
||||||
Bsp::s(self.toolbar_view(),
|
Bsp::s(self.toolbar_view(),
|
||||||
Bsp::n(self.selector_view(),
|
Bsp::n(self.selector_view(),
|
||||||
Bsp::n(self.sample_view(),
|
Bsp::n(self.sample_view(),
|
||||||
Bsp::n(self.status_view(),
|
Bsp::n(self.status_view(),
|
||||||
Bsp::w(self.pool_view(), Fill::xy(Bsp::e(self.sampler_view(), &self.editor)))))))));
|
Bsp::w(self.pool_view(), Fill::xy(Bsp::e(self.sampler_view(), &self.editor)))))))));
|
||||||
|
|
||||||
impl<'a> Groovebox<'a> {
|
impl Groovebox {
|
||||||
fn toolbar_view (&self) -> impl Content<Tui> + use<'_> {
|
fn toolbar_view (&self) -> impl Content<Tui> + use<'_> {
|
||||||
Fill::x(Fixed::y(2, lay!(
|
Fill::x(Fixed::y(2, lay!(
|
||||||
Align::w(Meter("L/", self.sampler.input_meter[0])),
|
Align::w(Meter("L/", self.sampler.input_meter[0])),
|
||||||
|
|
|
||||||
30
src/style.rs
30
src/style.rs
|
|
@ -1,27 +1,27 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub trait TuiStyle {
|
pub trait TuiStyle {
|
||||||
fn fg <W: Content<Tui>> (color: Color, w: W) -> Foreground<W> {
|
fn fg <R: Content<Tui>> (color: Color, w: R) -> Foreground<R> {
|
||||||
Foreground(color, w)
|
Foreground(color, w)
|
||||||
}
|
}
|
||||||
fn bg <W: Content<Tui>> (color: Color, w: W) -> Background<W> {
|
fn bg <R: Content<Tui>> (color: Color, w: R) -> Background<R> {
|
||||||
Background(color, w)
|
Background(color, w)
|
||||||
}
|
}
|
||||||
fn fg_bg <W: Content<Tui>> (fg: Color, bg: Color, w: W) -> Background<Foreground<W>> {
|
fn fg_bg <R: Content<Tui>> (fg: Color, bg: Color, w: R) -> Background<Foreground<R>> {
|
||||||
Background(bg, Foreground(fg, w))
|
Background(bg, Foreground(fg, w))
|
||||||
}
|
}
|
||||||
fn bold <W: Content<Tui>> (on: bool, w: W) -> Bold<W> {
|
fn bold <R: Content<Tui>> (on: bool, w: R) -> Bold<R> {
|
||||||
Bold(on, w)
|
Bold(on, w)
|
||||||
}
|
}
|
||||||
fn border <W: Content<Tui>, S: BorderStyle> (style: S, w: W) -> Bordered<S, W> {
|
fn border <R: Content<Tui>, S: BorderStyle> (style: S, w: R) -> Bordered<S, R> {
|
||||||
Bordered(style, w)
|
Bordered(style, w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TuiStyle for Tui {}
|
impl TuiStyle for Tui {}
|
||||||
|
|
||||||
pub struct Bold<W: Content<Tui>>(pub bool, W);
|
pub struct Bold<R: Content<Tui>>(pub bool, R);
|
||||||
impl<W: Content<Tui>> Content<Tui> for Bold<W> {
|
impl<R: Content<Tui>> Content<Tui> for Bold<R> {
|
||||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||||
fn render (&self, to: &mut TuiOut) {
|
fn render (&self, to: &mut TuiOut) {
|
||||||
to.fill_bold(to.area(), self.0);
|
to.fill_bold(to.area(), self.0);
|
||||||
|
|
@ -29,8 +29,8 @@ impl<W: Content<Tui>> Content<Tui> for Bold<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Foreground<W: Content<Tui>>(pub Color, W);
|
pub struct Foreground<R: Content<Tui>>(pub Color, R);
|
||||||
impl<W: Content<Tui>> Content<Tui> for Foreground<W> {
|
impl<R: Content<Tui>> Content<Tui> for Foreground<R> {
|
||||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||||
fn render (&self, to: &mut TuiOut) {
|
fn render (&self, to: &mut TuiOut) {
|
||||||
to.fill_fg(to.area(), self.0);
|
to.fill_fg(to.area(), self.0);
|
||||||
|
|
@ -38,8 +38,8 @@ impl<W: Content<Tui>> Content<Tui> for Foreground<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Background<W: Content<Tui>>(pub Color, W);
|
pub struct Background<R: Content<Tui>>(pub Color, R);
|
||||||
impl<W: Content<Tui>> Content<Tui> for Background<W> {
|
impl<R: Content<Tui>> Content<Tui> for Background<R> {
|
||||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||||
fn render (&self, to: &mut TuiOut) {
|
fn render (&self, to: &mut TuiOut) {
|
||||||
to.fill_bg(to.area(), self.0);
|
to.fill_bg(to.area(), self.0);
|
||||||
|
|
@ -47,7 +47,7 @@ impl<W: Content<Tui>> Content<Tui> for Background<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Styled<T: Content<Tui>>(pub Option<Style>, pub T);
|
pub struct Styled<R: Content<Tui>>(pub Option<Style>, pub R);
|
||||||
impl Content<Tui> for Styled<&str> {
|
impl Content<Tui> for Styled<&str> {
|
||||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||||
fn render (&self, to: &mut TuiOut) {
|
fn render (&self, to: &mut TuiOut) {
|
||||||
|
|
@ -58,7 +58,7 @@ impl Content<Tui> for Styled<&str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub trait TuiStyle: Content<Tui> + Sized {
|
//pub trait TuiStyle: Render<Tui> + Sized {
|
||||||
//fn fg (self, color: Color) -> impl Render<Tui> {
|
//fn fg (self, color: Color) -> impl Render<Tui> {
|
||||||
//Layers::new(move |add|{ add(&Foreground(color))?; add(&self) })
|
//Layers::new(move |add|{ add(&Foreground(color))?; add(&self) })
|
||||||
//}
|
//}
|
||||||
|
|
@ -73,12 +73,12 @@ impl Content<Tui> for Styled<&str> {
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//impl<W: Content<Tui>> TuiStyle for W {}
|
//impl<R: Content<Tui>> TuiStyle for R {}
|
||||||
|
|
||||||
//impl<S: BorderStyle> Content<Tui> for Border<S> {
|
//impl<S: BorderStyle> Content<Tui> for Border<S> {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//impl<S: BorderStyle, W: Content<Tui>> Content<Tui> for Bordered<S, W> {
|
//impl<S: BorderStyle, R: Content<Tui>> Content<Tui> for Bordered<S, R> {
|
||||||
//fn content (&self) -> impl Render<Tui> {
|
//fn content (&self) -> impl Render<Tui> {
|
||||||
//let content: &dyn Content<Tui> = &self.1;
|
//let content: &dyn Content<Tui> = &self.1;
|
||||||
//lay! { content.padding_xy(1, 1), Border(self.0) }.fill_xy()
|
//lay! { content.padding_xy(1, 1), Border(self.0) }.fill_xy()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue