mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
document stuff; Thunk suffix -> prefix
This commit is contained in:
parent
f9f9051eb7
commit
9d250daa04
16 changed files with 162 additions and 125 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
use tek::*;
|
pub use tek::*;
|
||||||
use clap::{self, Parser, Subcommand};
|
pub(crate) use clap::{self, Parser, Subcommand};
|
||||||
/// Application entrypoint.
|
/// Application entrypoint.
|
||||||
pub fn main () -> Usually<()> {
|
pub fn main () -> Usually<()> {
|
||||||
TekCli::parse().run()
|
TekCli::parse().run()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,18 @@
|
||||||
|
//! The token iterator [TokenIter] allows you to get the
|
||||||
|
//! general-purpose syntactic [Token]s represented by the source text.
|
||||||
|
//!
|
||||||
|
//! Both iterators are `peek`able:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! let src = include_str!("../../tek/src/view_arranger.edn")
|
||||||
|
//! let mut view = TokenIter(src);
|
||||||
|
//! assert_eq!(view.0.0, src);
|
||||||
|
//! assert_eq!(src.peek(), src.0.peek()))
|
||||||
|
//! ```
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
/// Provides a native [Iterator] API over the [ConstIntoIter] [SourceIter]
|
||||||
|
/// [TokenIter::next] returns just the [Token] and mutates `self`,
|
||||||
|
/// instead of returning an updated version of the struct as [SourceIter::next] does.
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct TokenIter<'a>(pub SourceIter<'a>);
|
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct TokenIter<'a>(pub SourceIter<'a>);
|
||||||
impl<'a> TokenIter<'a> {
|
impl<'a> TokenIter<'a> {
|
||||||
pub const fn new (source: &'a str) -> Self { Self(SourceIter::new(source)) }
|
pub const fn new (source: &'a str) -> Self { Self(SourceIter::new(source)) }
|
||||||
|
|
@ -10,6 +24,11 @@ impl<'a> Iterator for TokenIter<'a> {
|
||||||
self.0.next().map(|(item, rest)|{self.0 = rest; item})
|
self.0.next().map(|(item, rest)|{self.0 = rest; item})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Owns a reference to the source text.
|
||||||
|
/// [SourceIter::next] emits subsequent pairs of:
|
||||||
|
/// * a [Token] and
|
||||||
|
/// * the source text remaining
|
||||||
|
/// * [ ] TODO: maybe [SourceIter::next] should wrap the remaining source in `Self` ?
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct SourceIter<'a>(pub &'a str);
|
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct SourceIter<'a>(pub &'a str);
|
||||||
const_iter!(<'a>|self: SourceIter<'a>| => Token<'a> => self.next_mut().map(|(result, _)|result));
|
const_iter!(<'a>|self: SourceIter<'a>| => Token<'a> => self.next_mut().map(|(result, _)|result));
|
||||||
impl<'a> From<&'a str> for SourceIter<'a> {fn from (source: &'a str) -> Self{Self::new(source)}}
|
impl<'a> From<&'a str> for SourceIter<'a> {fn from (source: &'a str) -> Self{Self::new(source)}}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,8 @@ mod error; pub use self::error::*;
|
||||||
mod token; pub use self::token::*;
|
mod token; pub use self::token::*;
|
||||||
mod iter; pub use self::iter::*;
|
mod iter; pub use self::iter::*;
|
||||||
mod context; pub use self::context::*;
|
mod context; pub use self::context::*;
|
||||||
//mod atom; pub use self::atom::*;
|
|
||||||
//mod atom_ref; pub use self::atom_ref::*;
|
|
||||||
//mod atom_arc; pub use self::atom_arc::*;
|
|
||||||
pub(crate) use self::Value::*;
|
pub(crate) use self::Value::*;
|
||||||
pub(crate) use self::ParseError::*;
|
pub(crate) use self::ParseError::*;
|
||||||
//pub(crate) use self::TokenKind::*;
|
|
||||||
pub(crate) use std::sync::Arc;
|
|
||||||
//pub(crate) use std::marker::ConstParamTy;
|
|
||||||
pub(crate) use itertools::join;
|
|
||||||
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
||||||
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
||||||
pub(crate) use std::error::Error;
|
pub(crate) use std::error::Error;
|
||||||
|
|
@ -81,27 +74,27 @@ pub(crate) use std::fmt::{Debug, Display, Formatter, Result as FormatResult, Err
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
//#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
||||||
let src = include_str!("../../tek/src/view_arranger.edn");
|
//// Let's pretend to render some view.
|
||||||
let mut view = SourceIter(src);
|
//let source = include_str!("../../tek/src/view_arranger.edn");
|
||||||
assert_eq!(view.0, src);
|
//// The token iterator allows you to get the tokens represented by the source text.
|
||||||
let mut expr = view.peek();
|
//let mut view = TokenIter(source);
|
||||||
assert_eq!(view.0, src);
|
//// The token iterator wraps a const token+source iterator.
|
||||||
assert_eq!(expr, Some(Token {
|
//assert_eq!(view.0.0, source);
|
||||||
source: src,
|
//let mut expr = view.peek();
|
||||||
start: 0,
|
//assert_eq!(view.0.0, source);
|
||||||
length: src.len(),
|
//assert_eq!(expr, Some(Token {
|
||||||
value: Exp(0, SourceIter(&src[1..]))
|
//source, start: 0, length: source.len() - 1, value: Exp(0, SourceIter(&source[1..]))
|
||||||
}));
|
//}));
|
||||||
//panic!("{view:?}");
|
////panic!("{view:?}");
|
||||||
//panic!("{:#?}", expr);
|
////panic!("{:#?}", expr);
|
||||||
//for example in [
|
////for example in [
|
||||||
//include_str!("../../tui/examples/edn01.edn"),
|
////include_str!("../../tui/examples/edn01.edn"),
|
||||||
//include_str!("../../tui/examples/edn02.edn"),
|
////include_str!("../../tui/examples/edn02.edn"),
|
||||||
//] {
|
////] {
|
||||||
////let items = Atom::read_all(example)?;
|
//////let items = Atom::read_all(example)?;
|
||||||
////panic!("{layout:?}");
|
//////panic!("{layout:?}");
|
||||||
////let content = <dyn ViewContext<::tek_engine::tui::Tui>>::from(&layout);
|
//////let content = <dyn ViewContext<::tek_engine::tui::Tui>>::from(&layout);
|
||||||
//}
|
////}
|
||||||
Ok(())
|
//Ok(())
|
||||||
}
|
//}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,24 @@
|
||||||
|
//! [Token]s are parsed substrings with an associated [Value].
|
||||||
|
//!
|
||||||
|
//! * [ ] FIXME: Value may be [Err] which may shadow [Result::Err]
|
||||||
|
//! * [Value::Exp] wraps an expression depth and a [SourceIter]
|
||||||
|
//! with the remaining part of the expression.
|
||||||
|
//! * expression depth other that 0 mean unclosed parenthesis.
|
||||||
|
//! * closing and unopened parenthesis panics during reading.
|
||||||
|
//! * [ ] TODO: signed depth might be interesting
|
||||||
|
//! * [Value::Sym] and [Value::Key] are stringish literals
|
||||||
|
//! with slightly different parsing rules.
|
||||||
|
//! * [Value::Num] is an unsigned integer literal.
|
||||||
|
//!```
|
||||||
|
//! let src = include_str!("../../tek/src/view_arranger.edn")
|
||||||
|
//! let mut view = TokenIter(src);
|
||||||
|
//! assert_eq!(source.peek(), Some(Token {
|
||||||
|
//! source,
|
||||||
|
//! start: 0,
|
||||||
|
//! length: source.len() - 1,
|
||||||
|
//! value: Exp(0, SourceIter(&source[1..]))
|
||||||
|
//! })))
|
||||||
|
//!```
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use self::Value::*;
|
use self::Value::*;
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'a> {
|
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'a> {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
/// [Input] state that can be matched against an [Atom].
|
/// [Input] state that can be matched against a [Value].
|
||||||
pub trait AtomInput: Input {
|
pub trait AtomInput: Input {
|
||||||
fn matches_atom (&self, token: &str) -> bool;
|
fn matches_atom (&self, token: &str) -> bool;
|
||||||
}
|
}
|
||||||
|
|
@ -222,6 +222,6 @@ impl<'a, C, T: TryFromAtom<'a, C> + Command<C>> AtomCommand<'a, C> for T {}
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
#[cfg(test)] #[test] fn test_atom_keymap () -> Usually<()> {
|
#[cfg(test)] #[test] fn test_atom_keymap () -> Usually<()> {
|
||||||
let keymap = KeyMap::new("")?;
|
let keymap = SourceIter::new("");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
mod midi_clip; pub use midi_clip::*;
|
mod midi_clip; pub use midi_clip::*;
|
||||||
mod midi_launch; pub use midi_launch::*;
|
mod midi_edit; pub use midi_edit::*;
|
||||||
mod midi_player; pub use midi_player::*;
|
|
||||||
mod midi_in; pub use midi_in::*;
|
mod midi_in; pub use midi_in::*;
|
||||||
|
mod midi_launch; pub use midi_launch::*;
|
||||||
mod midi_out; pub use midi_out::*;
|
mod midi_out; pub use midi_out::*;
|
||||||
|
|
||||||
mod midi_pitch; pub use midi_pitch::*;
|
mod midi_pitch; pub use midi_pitch::*;
|
||||||
mod midi_range; pub use midi_range::*;
|
mod midi_player; pub use midi_player::*;
|
||||||
mod midi_point; pub use midi_point::*;
|
mod midi_point; pub use midi_point::*;
|
||||||
|
mod midi_pool; pub use midi_pool::*;
|
||||||
|
mod midi_range; pub use midi_range::*;
|
||||||
mod midi_view; pub use midi_view::*;
|
mod midi_view; pub use midi_view::*;
|
||||||
|
mod piano_h; pub use self::piano_h::*;
|
||||||
mod midi_pool; pub use midi_pool::*;
|
|
||||||
mod midi_edit; pub use midi_edit::*;
|
|
||||||
mod piano_h; pub use self::piano_h::*;
|
|
||||||
|
|
||||||
pub(crate) use ::tek_time::*;
|
pub(crate) use ::tek_time::*;
|
||||||
pub(crate) use ::tek_jack::{*, jack::*};
|
pub(crate) use ::tek_jack::{*, jack::*};
|
||||||
|
|
@ -20,7 +18,6 @@ pub(crate) use ::tek_tui::{
|
||||||
tek_input::*,
|
tek_input::*,
|
||||||
tek_output::*,
|
tek_output::*,
|
||||||
tek_edn::*,
|
tek_edn::*,
|
||||||
crossterm::event::*,
|
|
||||||
ratatui::style::{Style, Stylize, Color}
|
ratatui::style::{Style, Stylize, Color}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use Value::*;
|
|
||||||
pub trait HasEditor {
|
pub trait HasEditor {
|
||||||
fn editor (&self) -> &Option<MidiEditor>;
|
fn editor (&self) -> &Option<MidiEditor>;
|
||||||
fn editor_mut (&mut self) -> &Option<MidiEditor>;
|
fn editor_mut (&mut self) -> &Option<MidiEditor>;
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ impl PianoHorizontal {
|
||||||
let note_lo = self.note_lo().get();
|
let note_lo = self.note_lo().get();
|
||||||
let note_hi = self.note_hi();
|
let note_hi = self.note_hi();
|
||||||
let buffer = self.buffer.clone();
|
let buffer = self.buffer.clone();
|
||||||
RenderThunk::new(move|to: &mut TuiOut|{
|
ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let source = buffer.read().unwrap();
|
let source = buffer.read().unwrap();
|
||||||
let [x0, y0, w, _h] = to.area().xywh();
|
let [x0, y0, w, _h] = to.area().xywh();
|
||||||
//if h as usize != note_axis {
|
//if h as usize != note_axis {
|
||||||
|
|
@ -156,7 +156,7 @@ impl PianoHorizontal {
|
||||||
let time_pos = self.time_pos();
|
let time_pos = self.time_pos();
|
||||||
let time_start = self.time_start().get();
|
let time_start = self.time_start().get();
|
||||||
let time_zoom = self.time_zoom().get();
|
let time_zoom = self.time_zoom().get();
|
||||||
RenderThunk::new(move|to: &mut TuiOut|{
|
ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let [x0, y0, w, _] = to.area().xywh();
|
let [x0, y0, w, _] = to.area().xywh();
|
||||||
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
||||||
if note == note_pos {
|
if note == note_pos {
|
||||||
|
|
@ -187,7 +187,7 @@ impl PianoHorizontal {
|
||||||
let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0)));
|
let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0)));
|
||||||
let off_style = Some(Style::default().fg(TuiTheme::g(160)));
|
let off_style = Some(Style::default().fg(TuiTheme::g(160)));
|
||||||
let on_style = Some(Style::default().fg(TuiTheme::g(255)).bg(color.base.rgb).bold());
|
let on_style = Some(Style::default().fg(TuiTheme::g(255)).bg(color.base.rgb).bold());
|
||||||
Fill::y(Fixed::x(self.keys_width, RenderThunk::new(move|to: &mut TuiOut|{
|
Fill::y(Fixed::x(self.keys_width, ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let [x, y0, _w, _h] = to.area().xywh();
|
let [x, y0, _w, _h] = to.area().xywh();
|
||||||
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
||||||
to.blit(&to_key(note), x, screen_y, key_style);
|
to.blit(&to_key(note), x, screen_y, key_style);
|
||||||
|
|
@ -203,7 +203,7 @@ impl PianoHorizontal {
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
fn timeline (&self) -> impl Content<TuiOut> + '_ {
|
fn timeline (&self) -> impl Content<TuiOut> + '_ {
|
||||||
Fill::x(Fixed::y(1, RenderThunk::new(move|to: &mut TuiOut|{
|
Fill::x(Fixed::y(1, ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let [x, y, w, _h] = to.area();
|
let [x, y, w, _h] = to.area();
|
||||||
let style = Some(Style::default().dim());
|
let style = Some(Style::default().dim());
|
||||||
let length = self.clip.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
|
let length = self.clip.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
|
||||||
|
|
|
||||||
|
|
@ -49,37 +49,5 @@ pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
|
||||||
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);
|
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);
|
||||||
}
|
}
|
||||||
#[cfg(test)] #[test] fn test_layout () -> Usually<()> {
|
#[cfg(test)] #[test] fn test_layout () -> Usually<()> {
|
||||||
use ::tek_tui::{*, tek_output::*};
|
|
||||||
let area: [u16;4] = [10, 10, 20, 20];
|
|
||||||
let unit = ();
|
|
||||||
fn test (area: [u16;4], item: &impl Content<TuiOut>, expected: [u16;4]) {
|
|
||||||
assert_eq!(Content::layout(item, area), expected);
|
|
||||||
assert_eq!(Render::layout(item, area), expected);
|
|
||||||
};
|
|
||||||
test(area, &(), [20, 20, 0, 0]);
|
|
||||||
test(area, &Fill::xy(()), area);
|
|
||||||
test(area, &Fill::x(()), [10, 20, 20, 0]);
|
|
||||||
test(area, &Fill::y(()), [20, 10, 0, 20]);
|
|
||||||
test(area, &Fixed::x(4, unit), [18, 20, 4, 0]);
|
|
||||||
test(area, &Fixed::y(4, unit), [20, 18, 0, 4]);
|
|
||||||
test(area, &Fixed::xy(4, 4, unit), [18, 18, 4, 4]);
|
|
||||||
let four = ||Fixed::<TuiOut, _, _>::xy(4, 4, unit);
|
|
||||||
test(area, &Align::nw(four()), [10, 10, 4, 4]);
|
|
||||||
test(area, &Align::n(four()), [18, 10, 4, 4]);
|
|
||||||
test(area, &Align::ne(four()), [26, 10, 4, 4]);
|
|
||||||
test(area, &Align::e(four()), [26, 18, 4, 4]);
|
|
||||||
test(area, &Align::se(four()), [26, 26, 4, 4]);
|
|
||||||
test(area, &Align::s(four()), [18, 26, 4, 4]);
|
|
||||||
test(area, &Align::sw(four()), [10, 26, 4, 4]);
|
|
||||||
test(area, &Align::w(four()), [10, 18, 4, 4]);
|
|
||||||
let two_by_four = ||Fixed::<TuiOut, _, _>::xy(4, 2, unit);
|
|
||||||
test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]);
|
|
||||||
test(area, &Align::n(two_by_four()), [18, 10, 4, 2]);
|
|
||||||
test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]);
|
|
||||||
test(area, &Align::e(two_by_four()), [26, 19, 4, 2]);
|
|
||||||
test(area, &Align::se(two_by_four()), [26, 28, 4, 2]);
|
|
||||||
test(area, &Align::s(two_by_four()), [18, 28, 4, 2]);
|
|
||||||
test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]);
|
|
||||||
test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,24 @@
|
||||||
|
//! Aligns things to the container. Comes with caveats.
|
||||||
|
//! ```
|
||||||
|
//! let four = ||Fixed::<TuiOut, _, _>::xy(4, 4, unit);
|
||||||
|
//! test(area, &Align::nw(four()), [10, 10, 4, 4]);
|
||||||
|
//! test(area, &Align::n(four()), [18, 10, 4, 4]);
|
||||||
|
//! test(area, &Align::ne(four()), [26, 10, 4, 4]);
|
||||||
|
//! test(area, &Align::e(four()), [26, 18, 4, 4]);
|
||||||
|
//! test(area, &Align::se(four()), [26, 26, 4, 4]);
|
||||||
|
//! test(area, &Align::s(four()), [18, 26, 4, 4]);
|
||||||
|
//! test(area, &Align::sw(four()), [10, 26, 4, 4]);
|
||||||
|
//! test(area, &Align::w(four()), [10, 18, 4, 4]);
|
||||||
|
//! let two_by_four = ||Fixed::<TuiOut, _, _>::xy(4, 2, unit);
|
||||||
|
//! test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]);
|
||||||
|
//! test(area, &Align::n(two_by_four()), [18, 10, 4, 2]);
|
||||||
|
//! test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]);
|
||||||
|
//! test(area, &Align::e(two_by_four()), [26, 19, 4, 2]);
|
||||||
|
//! test(area, &Align::se(two_by_four()), [26, 28, 4, 2]);
|
||||||
|
//! test(area, &Align::s(two_by_four()), [18, 28, 4, 2]);
|
||||||
|
//! test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]);
|
||||||
|
//! test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
|
||||||
|
//! ```
|
||||||
use crate::*;
|
use crate::*;
|
||||||
#[derive(Debug, Copy, Clone, Default)] pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
|
#[derive(Debug, Copy, Clone, Default)] pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
|
||||||
pub struct Align<A>(Alignment, A);
|
pub struct Align<A>(Alignment, A);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,23 @@
|
||||||
|
//! [Content] items that modify the inherent
|
||||||
|
//! dimensions of their inner [Render]ables.
|
||||||
|
//!
|
||||||
|
//! Transform may also react to the [Area] provided.
|
||||||
|
//! ```
|
||||||
|
//! use ::tek_tui::{*, tek_output::*};
|
||||||
|
//! let area: [u16;4] = [10, 10, 20, 20];
|
||||||
|
//! let unit = ();
|
||||||
|
//! fn test (area: [u16;4], item: &impl Content<TuiOut>, expected: [u16;4]) {
|
||||||
|
//! assert_eq!(Content::layout(item, area), expected);
|
||||||
|
//! assert_eq!(Render::layout(item, area), expected);
|
||||||
|
//! };
|
||||||
|
//! test(area, &(), [20, 20, 0, 0]);
|
||||||
|
//! test(area, &Fill::xy(()), area);
|
||||||
|
//! test(area, &Fill::x(()), [10, 20, 20, 0]);
|
||||||
|
//! test(area, &Fill::y(()), [20, 10, 0, 20]);
|
||||||
|
//! test(area, &Fixed::x(4, unit), [18, 20, 4, 0]);
|
||||||
|
//! test(area, &Fixed::y(4, unit), [20, 18, 0, 4]);
|
||||||
|
//! test(area, &Fixed::xy(4, 4, unit), [18, 18, 4, 4]);
|
||||||
|
//! ```
|
||||||
use crate::*;
|
use crate::*;
|
||||||
/// Defines an enum that transforms its content
|
/// Defines an enum that transforms its content
|
||||||
/// along either the X axis, the Y axis, or both.
|
/// along either the X axis, the Y axis, or both.
|
||||||
|
|
@ -5,8 +25,8 @@ macro_rules! transform_xy {
|
||||||
($x:literal $y:literal $xy:literal |$self:ident : $Enum:ident, $to:ident|$area:expr) => {
|
($x:literal $y:literal $xy:literal |$self:ident : $Enum:ident, $to:ident|$area:expr) => {
|
||||||
pub enum $Enum<T> { X(T), Y(T), XY(T) }
|
pub enum $Enum<T> { X(T), Y(T), XY(T) }
|
||||||
impl<T> $Enum<T> {
|
impl<T> $Enum<T> {
|
||||||
pub fn x (item: T) -> Self { Self::X(item) }
|
pub fn x (item: T) -> Self { Self::X(item) }
|
||||||
pub fn y (item: T) -> Self { Self::Y(item) }
|
pub fn y (item: T) -> Self { Self::Y(item) }
|
||||||
pub fn xy (item: T) -> Self { Self::XY(item) }
|
pub fn xy (item: T) -> Self { Self::XY(item) }
|
||||||
}
|
}
|
||||||
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T>
|
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T>
|
||||||
|
|
|
||||||
|
|
@ -12,39 +12,39 @@ impl<E: Output, T: Render<E>, F: Fn()->T + Send + Sync> Content<E> for Thunk<E,
|
||||||
fn content (&self) -> impl Render<E> { (self.1)() }
|
fn content (&self) -> impl Render<E> { (self.1)() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BoxThunk<'a, E: Output>(PhantomData<E>, Box<dyn Fn()->Box<dyn Render<E> + 'a> + Send + Sync + 'a>);
|
pub struct ThunkBox<'a, E: Output>(PhantomData<E>, Box<dyn Fn()->Box<dyn Render<E> + 'a> + Send + Sync + 'a>);
|
||||||
impl<'a, E: Output> BoxThunk<'a, E> {
|
impl<'a, E: Output> ThunkBox<'a, E> {
|
||||||
pub fn new (thunk: Box<dyn Fn()->Box<dyn Render<E> + 'a> + Send + Sync + 'a>) -> Self {
|
pub fn new (thunk: Box<dyn Fn()->Box<dyn Render<E> + 'a> + Send + Sync + 'a>) -> Self {
|
||||||
Self(Default::default(), thunk)
|
Self(Default::default(), thunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, E: Output> Content<E> for BoxThunk<'a, E> {
|
impl<'a, E: Output> Content<E> for ThunkBox<'a, E> {
|
||||||
fn content (&self) -> impl Render<E> { (self.1)() }
|
fn content (&self) -> impl Render<E> { (self.1)() }
|
||||||
}
|
}
|
||||||
impl<'a, E: Output, F: Fn()->T + Send + Sync + 'a, T: Render<E> + Send + Sync + 'a> From<F> for BoxThunk<'a, E> {
|
impl<'a, E: Output, F: Fn()->T + Send + Sync + 'a, T: Render<E> + Send + Sync + 'a> From<F> for ThunkBox<'a, E> {
|
||||||
fn from (f: F) -> Self {
|
fn from (f: F) -> Self {
|
||||||
Self(Default::default(), Box::new(move||f().boxed()))
|
Self(Default::default(), Box::new(move||f().boxed()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//impl<'a, E: Output, F: Fn()->Box<dyn Render<E> + 'a> + Send + Sync + 'a> From<F> for BoxThunk<'a, E> {
|
//impl<'a, E: Output, F: Fn()->Box<dyn Render<E> + 'a> + Send + Sync + 'a> From<F> for ThunkBox<'a, E> {
|
||||||
//fn from (f: F) -> Self {
|
//fn from (f: F) -> Self {
|
||||||
//Self(Default::default(), Box::new(f))
|
//Self(Default::default(), Box::new(f))
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
pub struct RenderThunk<E: Output, F: Fn(&mut E) + Send + Sync>(PhantomData<E>, F);
|
pub struct ThunkRender<E: Output, F: Fn(&mut E) + Send + Sync>(PhantomData<E>, F);
|
||||||
impl<E: Output, F: Fn(&mut E) + Send + Sync> RenderThunk<E, F> {
|
impl<E: Output, F: Fn(&mut E) + Send + Sync> ThunkRender<E, F> {
|
||||||
pub fn new (render: F) -> Self { Self(Default::default(), render) }
|
pub fn new (render: F) -> Self { Self(Default::default(), render) }
|
||||||
}
|
}
|
||||||
impl<E: Output, F: Fn(&mut E) + Send + Sync> Content<E> for RenderThunk<E, F> {
|
impl<E: Output, F: Fn(&mut E) + Send + Sync> Content<E> for ThunkRender<E, F> {
|
||||||
fn render (&self, to: &mut E) { (self.1)(to) }
|
fn render (&self, to: &mut E) { (self.1)(to) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutThunk<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync>(PhantomData<E>, F1, F2);
|
pub struct ThunkLayout<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync>(PhantomData<E>, F1, F2);
|
||||||
impl<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> LayoutThunk<E, F1, F2> {
|
impl<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> ThunkLayout<E, F1, F2> {
|
||||||
pub fn new (layout: F1, render: F2) -> Self { Self(Default::default(), layout, render) }
|
pub fn new (layout: F1, render: F2) -> Self { Self(Default::default(), layout, render) }
|
||||||
}
|
}
|
||||||
impl<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> Content<E> for LayoutThunk<E, F1, F2> {
|
impl<E: Output, F1: Fn(E::Area)->E::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> Content<E> for ThunkLayout<E, F1, F2> {
|
||||||
fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) }
|
fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) }
|
||||||
fn render (&self, to: &mut E) { (self.2)(to) }
|
fn render (&self, to: &mut E) { (self.2)(to) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -884,7 +884,7 @@ impl Sampler {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let min_db = -40.0;
|
let min_db = -40.0;
|
||||||
RenderThunk::new(move|to: &mut TuiOut|{
|
ThunkRender::new(move|to: &mut TuiOut|{
|
||||||
let [x, y, width, height] = to.area();
|
let [x, y, width, height] = to.area();
|
||||||
let area = Rect { x, y, width, height };
|
let area = Rect { x, y, width, height };
|
||||||
let (x_bounds, y_bounds, lines): ([f64;2], [f64;2], Vec<Line>) =
|
let (x_bounds, y_bounds, lines): ([f64;2], [f64;2], Vec<Line>) =
|
||||||
|
|
|
||||||
|
|
@ -487,7 +487,7 @@ impl Tek {
|
||||||
scene.clips.remove(index);
|
scene.clips.remove(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn clip_columns <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn clip_columns <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
let editing = self.is_editing();
|
let editing = self.is_editing();
|
||||||
let tracks = move||self.tracks_sizes(editing, self.editor_w());
|
let tracks = move||self.tracks_sizes(editing, self.editor_w());
|
||||||
let scenes = move||self.scenes_sizes(editing, 2, 15);
|
let scenes = move||self.scenes_sizes(editing, 2, 15);
|
||||||
|
|
@ -555,7 +555,7 @@ impl Tek {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn input_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn input_header <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
let fg = TuiTheme::g(224);
|
let fg = TuiTheme::g(224);
|
||||||
let bg = TuiTheme::g(64);
|
let bg = TuiTheme::g(64);
|
||||||
(move||Bsp::s(Fill::x(Align::w(self.button(" I ".to_string(), format!(" midi ins ({})", self.midi_ins().len())))), self.midi_ins().get(0).map(|inp|Bsp::s(
|
(move||Bsp::s(Fill::x(Align::w(self.button(" I ".to_string(), format!(" midi ins ({})", self.midi_ins().len())))), self.midi_ins().get(0).map(|inp|Bsp::s(
|
||||||
|
|
@ -564,7 +564,7 @@ impl Tek {
|
||||||
Tui::fg_bg(fg, bg, connect.info()))))),
|
Tui::fg_bg(fg, bg, connect.info()))))),
|
||||||
))).boxed()).into()
|
))).boxed()).into()
|
||||||
}
|
}
|
||||||
fn output_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn output_header <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
let fg = TuiTheme::g(224);
|
let fg = TuiTheme::g(224);
|
||||||
let bg = TuiTheme::g(64);
|
let bg = TuiTheme::g(64);
|
||||||
(move||Bsp::s(Fill::x(Align::w(self.button(" O ".to_string(), format!(" midi outs ({}) ", self.midi_outs().len())))), self.midi_outs().get(0).map(|out|Bsp::s(
|
(move||Bsp::s(Fill::x(Align::w(self.button(" O ".to_string(), format!(" midi outs ({}) ", self.midi_outs().len())))), self.midi_outs().get(0).map(|out|Bsp::s(
|
||||||
|
|
@ -573,7 +573,7 @@ impl Tek {
|
||||||
Tui::fg_bg(fg, bg, connect.info()))))),
|
Tui::fg_bg(fg, bg, connect.info()))))),
|
||||||
))).boxed()).into()
|
))).boxed()).into()
|
||||||
}
|
}
|
||||||
fn track_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn track_header <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
let add_scene = ||self.button(" C-a ".to_string(), format!(" add scene ({}/{})",
|
let add_scene = ||self.button(" C-a ".to_string(), format!(" add scene ({}/{})",
|
||||||
self.selected.scene().unwrap_or(0),
|
self.selected.scene().unwrap_or(0),
|
||||||
self.scenes().len()));
|
self.scenes().len()));
|
||||||
|
|
@ -930,7 +930,7 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
||||||
fn track_mut (&mut self) -> Option<&mut Track> {
|
fn track_mut (&mut self) -> Option<&mut Track> {
|
||||||
self.selected().track().and_then(|s|self.tracks_mut().get_mut(s))
|
self.selected().track().and_then(|s|self.tracks_mut().get_mut(s))
|
||||||
}
|
}
|
||||||
fn track_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn track_cells <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
let iter = ||self.tracks_sizes(self.is_editing(), self.editor_w());
|
let iter = ||self.tracks_sizes(self.is_editing(), self.editor_w());
|
||||||
(move||Align::x(Map::new(iter, move|(_, track, x1, x2), i| {
|
(move||Align::x(Map::new(iter, move|(_, track, x1, x2), i| {
|
||||||
let name = Push::x(1, &track.name);
|
let name = Push::x(1, &track.name);
|
||||||
|
|
@ -946,7 +946,7 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
||||||
))
|
))
|
||||||
})).boxed()).into()
|
})).boxed()).into()
|
||||||
}
|
}
|
||||||
fn input_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn input_cells <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
(move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| {
|
(move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| {
|
||||||
let w = (x2 - x1) as u16;
|
let w = (x2 - x1) as u16;
|
||||||
let color: ItemPalette = track.color.dark.into();
|
let color: ItemPalette = track.color.dark.into();
|
||||||
|
|
@ -965,7 +965,7 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
||||||
Tui::fg_bg(if mon { Color::White } else { bg }, bg, "▌"),
|
Tui::fg_bg(if mon { Color::White } else { bg }, bg, "▌"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn output_cells <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn output_cells <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
(move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| {
|
(move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| {
|
||||||
let w = (x2 - x1) as u16;
|
let w = (x2 - x1) as u16;
|
||||||
let color: ItemPalette = track.color.dark.into();
|
let color: ItemPalette = track.color.dark.into();
|
||||||
|
|
@ -1103,7 +1103,7 @@ trait HasScenes: HasSelection + HasEditor + Send + Sync {
|
||||||
fn scene_del (&mut self, index: usize) {
|
fn scene_del (&mut self, index: usize) {
|
||||||
self.selected().scene().and_then(|s|Some(self.scenes_mut().remove(index)));
|
self.selected().scene().and_then(|s|Some(self.scenes_mut().remove(index)));
|
||||||
}
|
}
|
||||||
fn scene_header <'a> (&'a self) -> BoxThunk<'a, TuiOut> {
|
fn scene_header <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||||
(move||{
|
(move||{
|
||||||
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
||||||
let selected = self.selected().scene();
|
let selected = self.selected().scene();
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ fn main () -> Usually<()> {
|
||||||
#[derive(Debug)] pub struct Example(usize, Measure<TuiOut>);
|
#[derive(Debug)] pub struct Example(usize, Measure<TuiOut>);
|
||||||
const KEYMAP: &str = "(:left prev) (:right next)";
|
const KEYMAP: &str = "(:left prev) (:right next)";
|
||||||
handle!(TuiIn: |self: Example, input|{
|
handle!(TuiIn: |self: Example, input|{
|
||||||
let keymap = KeyMap::new(KEYMAP)?;
|
let keymap = SourceIter::new(KEYMAP);
|
||||||
let command = keymap.command::<_, ExampleCommand>(self, input);
|
let command = keymap.command::<_, ExampleCommand, _>(self, input);
|
||||||
if let Some(command) = command {
|
if let Some(command) = command {
|
||||||
command.execute(self)?;
|
command.execute(self)?;
|
||||||
return Ok(Some(true))
|
return Ok(Some(true))
|
||||||
|
|
@ -46,22 +46,21 @@ const EXAMPLES: &'static [&'static str] = &[
|
||||||
include_str!("edn13.edn"),
|
include_str!("edn13.edn"),
|
||||||
];
|
];
|
||||||
view!(TuiOut: |self: Example|{
|
view!(TuiOut: |self: Example|{
|
||||||
let title = Tui::bg(Color::Rgb(60,10,10),
|
let index = self.0 + 1;
|
||||||
Push::y(1, Align::n(format!("Example {}/{} in {:?}", self.0 + 1, EXAMPLES.len(), &self.1.wh()))));
|
let wh = self.1.wh();
|
||||||
let code = Tui::bg(Color::Rgb(10,60,10),
|
let src = EXAMPLES[self.0];
|
||||||
Push::y(2, Align::n(format!("{}", EXAMPLES[self.0]))));
|
let heading = format!("Example {}/{} in {:?}", index, EXAMPLES.len(), &wh);
|
||||||
let content = Tui::bg(Color::Rgb(10,10,60),
|
let title = Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(heading)));
|
||||||
AtomView::from_source(self, EXAMPLES[self.0]));
|
let code = Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", src))));
|
||||||
|
let content = Tui::bg(Color::Rgb(10, 10, 60), View(self, SourceIter::new(src)));
|
||||||
self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content)))
|
self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content)))
|
||||||
}; {
|
}; {
|
||||||
bool {};
|
":title" => Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed(),
|
||||||
u16 {};
|
":code" => Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed(),
|
||||||
usize {};
|
":hello" => Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed(),
|
||||||
Box<dyn Render<TuiOut> + 'a> {
|
":world" => Tui::bg(Color::Rgb(100, 10, 10), "world").boxed(),
|
||||||
":title" => Tui::bg(Color::Rgb(60,10,10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed(),
|
":hello-world" => "Hello world!".boxed()
|
||||||
":code" => Tui::bg(Color::Rgb(10,60,10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed(),
|
|
||||||
":hello" => Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed(),
|
|
||||||
":world" => Tui::bg(Color::Rgb(100, 10, 10), "world").boxed(),
|
|
||||||
":hello-world" => "Hello world!".boxed()
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
provide_bool!(bool: |self: Example| {});
|
||||||
|
provide_num!(u16: |self: Example| {});
|
||||||
|
provide_num!(usize: |self: Example| {});
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
mod tui_buffer; pub use self::tui_buffer::*;
|
mod tui_buffer; pub use self::tui_buffer::*;
|
||||||
mod tui_color; pub use self::tui_color::*;
|
mod tui_color; pub use self::tui_color::*;
|
||||||
mod tui_content; pub use self::tui_content::*;
|
mod tui_content; pub use self::tui_content::*;
|
||||||
mod tui_engine; pub use self::tui_engine::*;
|
mod tui_engine; pub use self::tui_engine::*;
|
||||||
mod tui_file; pub use self::tui_file::*;
|
mod tui_file; pub use self::tui_file::*;
|
||||||
mod tui_input; pub use self::tui_input::*;
|
mod tui_input; pub use self::tui_input::*;
|
||||||
mod tui_output; pub use self::tui_output::*;
|
mod tui_output; pub use self::tui_output::*;
|
||||||
pub use ::tek_edn; pub(crate) use ::tek_edn::*;
|
pub use ::tek_edn;// pub(crate) use ::tek_edn::*;
|
||||||
pub use ::tek_time; pub(crate) use ::tek_time::*;
|
pub use ::tek_time; pub(crate) use ::tek_time::*;
|
||||||
pub use ::tek_input; pub(crate) use tek_input::*;
|
pub use ::tek_input; pub(crate) use tek_input::*;
|
||||||
pub use ::tek_output; pub(crate) use tek_output::*;
|
pub use ::tek_output; pub(crate) use tek_output::*;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue