Compare commits

..

No commits in common. "94c26f06ccf77bfd6dbe55665f58e87d0b0b2216" and "8b24b052caac078f6d0a9d8fde1afa1fbd3b3f56" have entirely different histories.

25 changed files with 402 additions and 565 deletions

View file

@ -29,9 +29,11 @@ doc:
CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' \
cargo doc
mode-00:
cargo run --example mode_00
mode-01:
cargo run --example mode_01
mode-02:
cargo run --example mode_02
example-tui-00:
cargo run --example mode_0
example-tui-01:
cargo run --example mode_1
example-tui-02:
cargo run --example mode_2

2
dizzle

@ -1 +1 @@
Subproject commit 0f06571f7fc7e5f87aadb82d531726d24bf769e8
Subproject commit 4424ef7fc3fd8bfbea1fb55b4922f7a8cfd2a8ef

View file

@ -1,37 +1,3 @@
//! Mode 00: Direct draw, direct control
use ::std::sync::{Arc, RwLock};
use ::crossterm::event::{Event::*, KeyEvent, KeyCode::*};
use ::ratatui::style::Color;
use ::tengri::{*, lang::*};
tui_app!(State {
/** User-controllable value. */
cursor: usize,
});
tui_view!(self: State {
thunk(|to: &mut Tui|{
let cursor = format!("Cursor: {}", self.cursor);
let _ = "DEMO [MODE 00]".align_sw().draw(to);
let _ = ShowSize.align_se().draw(to);
let _ = format!("Cursor: {}", self.cursor).align_c().draw(to);
Ok(Some(to.area()))
})
});
tui_keys!(self: State, input {
Ok(if let Key(KeyEvent { code, .. }) = input.0 {
match code {
Up | Right => {
self.cursor = (self.cursor + 1) % 10;
()
},
Down | Left => {
self.cursor = if self.cursor > 0 { self.cursor - 1 } else { 10 - 1 };
()
},
_ => {}
}
})
});
//! Mode 0: Direct draw
use ::{std::sync::{Arc, RwLock}, ratatui::style::Color, tengri::*};
fn main () {}

View file

@ -1,63 +1,153 @@
//! Mode 01: Direct view, actions with history
//! Mode 01
use ::std::sync::{Arc, RwLock};
use ::crossterm::event::{Event::*, KeyEvent, KeyCode::*};
use ::ratatui::style::Color;
use ::tengri::{*, lang::*};
use itertools::Itertools;
tui_app!(State {
/** Command history (undo/redo). */
history: Vec<Action>,
/** User-controllable value. */
cursor: usize,
/** Rendered window size. */
size: Sizer,
});
tui_keys!(self: State, input {
Ok(if let Key(KeyEvent { code, .. }) = input.0 {
match code {
Down | Right => Action::Next,
Up | Left => Action::Prev,
_ => { return Ok(()) }
Up | Right => { self.next()?.map(|x|self.history.push(x)); },
Down | Left => { self.prev()?.map(|x|self.history.push(x)); },
_ => {}
}
.apply(self)?
.map(|x|self.history.push(x));
})
});
tui_view!(self: State {
let title = "Demo Mode 00";
let items = self.history.iter().take(10).map(|x|format!("{x:?}")).join("\n");
let history = format!("History: {}\n{items}", self.history.len());
let cursor = format!("Cursor: {}", self.cursor);
north(
east(title.align_sw(), ShowSize.align_se()),
east(history.align_c(), cursor.align_c()),
)
let index = self.cursor + 1;
let wh = (self.size.w(), self.size.h());
let src = VIEWS.get(self.cursor).unwrap_or(&"");
let heading = format!("State {}/{} in {:?}", index, VIEWS.len(), &wh);
let title = bg(Color::Rgb(60, 10, 10), heading.align_n().push_y(1));
let code = bg(Color::Rgb(10, 60, 10), format!("{}", src).align_n().push_y(2));
let widget = thunk(move|to: &mut Tui|self.interpret(to, &src));
self.size.of(south(title, north(code, widget)))
});
#[derive(Debug)] enum Action {
/** Increment cursor */ Next,
/** Decrement cursor */ Prev,
}
impl Action {
fn apply (&self, state: &mut State) -> Perhaps<Self> {
use Action::*;
match self {
Next => state.next(),
Prev => state.prev(),
impl Interpret<Tui, Color> for State {
fn interpret_expr (&self, to: &mut Tui, expr: &impl Language) -> Usually<Color> {
let expr = expr.expr()?;
match expr.head()? {
Some("g") if let Some(tail) = expr.tail()? => {
Color::new_g(tail.head()?, try_to_u8)
},
Some("rgb") if let Some(tail) = expr.tail()? => {
Color::new_rgb(tail.head()?)
},
_ => Err(format!("not a color").into())
}
}
}
impl Interpret<Tui, Option<XYWH<u16>>> for State {
fn interpret_word (&self, to: &mut Tui, sym: &impl Language) -> Perhaps<XYWH<u16>> {
match sym.src()? {
Some(":foo") => "foo".draw(to),
Some(":bar") => "bar".draw(to),
Some(":foobar") => "FOOBAR".draw(to),
_ => todo!()
}
}
fn interpret_expr (&self, to: &mut Tui, src: &impl Expression) -> Perhaps<XYWH<u16>> {
Ok(Some(if let Some(area) = eval_view(self, to, src)? {
area
} else if let Some(area) = eval_view_tui(self, to, src)? {
area
} else {
return Err(format!("App::interpret_expr: unexpected: {src:?}").into())
}))
}
}
impl State {
fn next (&mut self) -> Perhaps<Action> {
self.cursor = (self.cursor + 1) % 10;
self.cursor = (self.cursor + 1) % VIEWS.len();
Ok(Some(Action::Prev))
}
fn prev (&mut self) -> Perhaps<Action> {
self.cursor = if self.cursor > 0 { self.cursor - 1 } else { 10 - 1 };
self.cursor = if self.cursor > 0 { self.cursor - 1 } else { VIEWS.len() - 1 };
Ok(Some(Action::Next))
}
}
#[derive(Debug)]
enum Action {
/** Increment cursor */ Next,
/** Decrement cursor */ Prev,
}
impl Action {
fn eval (&self, state: &mut State) -> Perhaps<Self> {
use Action::*;
match self { Next => state.next(), Prev => state.prev(), }
}
}
const VIEWS: &'static [&'static str] = &[
stringify! { :foobar },
stringify! { (bg (g 8) :foobar) },
stringify! { (fill/xy :foobar) },
stringify! { (bsp/s :foo :bar) },
stringify! { (fixed/xy 20 10 :foobar) },
stringify! { (bsp/s (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/e (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/n (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/w (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/a (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/b (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! {
(bsp/s
(bsp/e (align/nw (fixed/xy 5 3 :foo))
(bsp/e (align/n (fixed/xy 5 3 :foo))
(align/ne (fixed/xy 5 3 :foo))))
(bsp/s
(bsp/e (align/w (fixed/xy 5 3 :foo))
(bsp/e (align/c (fixed/xy 5 3 :foo))
(align/e (fixed/xy 5 3 :foo))))
(bsp/e (align/sw (fixed/xy 5 3 :foo))
(bsp/e (align/s (fixed/xy 5 3 :foo))
(align/se (fixed/xy 5 3 :foo))))))
},
stringify! {
(bsp/s
(bsp/e (fixed/xy 8 5 (align/nw :foo))
(bsp/e (fixed/xy 8 5 (align/n :foo))
(fixed/xy 8 5 (align/ne :foo))))
(bsp/s
(bsp/e (fixed/xy 8 5 (align/w :foo))
(bsp/e (fixed/xy 8 5 (align/c :foo))
(fixed/xy 8 5 (align/e :foo))))
(bsp/e (fixed/xy 8 5 (align/sw :foo))
(bsp/e (fixed/xy 8 5 (align/s :foo))
(fixed/xy 8 5 (align/se :foo))))))
},
stringify! {
(bsp/s
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/nw :foo)))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/n :foo)))
(grow/xy 1 1 (fixed/xy 8 5 (align/ne :foo)))))
(bsp/s
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/w :foo)))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/c :foo)))
(grow/xy 1 1 (fixed/xy 8 5 (align/e :foo)))))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/sw :foo)))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/s :foo)))
(grow/xy 1 1 (fixed/xy 8 5 (align/se :foo)))))))
},
stringify! { :map-e },
stringify! { (align/c :map-e) },
stringify! { :map-s },
stringify! { (align/c :map-s) },
stringify! {
(align/c (bg/behind :bg0 (margin/xy 1 1 (col
(bg/behind :bg1 (border/around :border1 (margin/xy 2 1 :label1)))
(bg/behind :bg2 (border/around :border2 (margin/xy 4 2 :label2)))
(bg/behind :bg3 (border/around :border3 (margin/xy 6 3 :label3)))))))
},
];
//handle!(TuiIn: |self: State, input|Action::from(input).eval(self).map(|_|None));
//view!(State: Tui: [ evaluate_output_expression, evaluate_output_expression_tui ]);
//draw!(State: Tui: [ draw_example ]);
//impl_from!(Action: |input: &TuiIn| todo!());
//fn draw_example (state: &State, to: &mut Tui) {}

View file

@ -1,162 +1,107 @@
//! Mode 02: Inline Dizzle config
//! Mode 02
use ::{std::sync::{Arc, RwLock}, ratatui::style::Color, tengri::*};
fn main () {}
use ::std::sync::{Arc, RwLock};
use ::crossterm::event::{Event::*, KeyEvent, KeyCode::*};
use ::ratatui::style::Color;
use ::tengri::{*, lang::*};
tui_app!(State {
/** Command history (undo/redo). */
history: Vec<Action>,
/** User-controllable value. */
cursor: usize,
/** Rendered window size. */
size: Sizer,
});
tui_keys!(self: State, input {
Ok(if let Key(KeyEvent { code, .. }) = input.0 {
match code {
Up | Right => { self.next()?.map(|x|self.history.push(x)); },
Down | Left => { self.prev()?.map(|x|self.history.push(x)); },
_ => {}
}
})
});
tui_view!(self: State {
let index = self.cursor + 1;
let wh = (self.size.w(), self.size.h());
let src = VIEWS.get(self.cursor).unwrap_or(&"");
let heading = format!("State {}/{} in {:?}", index, VIEWS.len(), &wh);
let title = bg(Color::Rgb(60, 10, 10), heading.align_n().push_y(1));
let code = bg(Color::Rgb(10, 60, 10), format!("{}", src).align_n().push_y(2));
let widget = thunk(move|to: &mut Tui|self.interpret(to, &src));
self.size.of(south(title, north(code, widget)))
});
impl Interpret<Tui, Color> for State {
fn interpret_expr (&self, to: &mut Tui, expr: &impl Language) -> Usually<Color> {
let expr = expr.expr()?;
match expr.head()? {
Some("g") if let Some(tail) = expr.tail()? => {
Color::new_g(tail.head()?, try_to_u8)
},
Some("rgb") if let Some(tail) = expr.tail()? => {
Color::new_rgb(tail.head()?, try_to_u8)
},
_ => Err(format!("not a color").into())
}
}
}
fn try_to_u8 (src: Perhaps<&str>) -> Perhaps<u8> {
use std::str::FromStr;
if let Some(src) = src? {
Ok(Some(u8::from_str(src)?))
} else {
Ok(None)
}
}
impl Interpret<Tui, Option<XYWH<u16>>> for State {
fn interpret_word (&self, to: &mut Tui, sym: &impl Language) -> Perhaps<XYWH<u16>> {
match sym.src()? {
Some(":foo") => "foo".draw(to),
Some(":bar") => "bar".draw(to),
Some(":foobar") => "FOOBAR".draw(to),
_ => todo!()
}
}
fn interpret_expr (&self, to: &mut Tui, src: &impl Expression) -> Perhaps<XYWH<u16>> {
Ok(Some(if let Some(area) = eval_view(self, to, src)? {
area
} else if let Some(area) = eval_view_tui(self, to, src)? {
area
} else {
return Err(format!("App::interpret_expr: unexpected: {src:?}").into())
}))
}
}
impl State {
fn next (&mut self) -> Perhaps<Action> {
self.cursor = (self.cursor + 1) % VIEWS.len();
Ok(Some(Action::Prev))
}
fn prev (&mut self) -> Perhaps<Action> {
self.cursor = if self.cursor > 0 { self.cursor - 1 } else { VIEWS.len() - 1 };
Ok(Some(Action::Next))
}
}
#[derive(Debug)]
enum Action {
/** Increment cursor */ Next,
/** Decrement cursor */ Prev,
}
impl Action {
fn eval (&self, state: &mut State) -> Perhaps<Self> {
use Action::*;
match self { Next => state.next(), Prev => state.prev(), }
}
}
const VIEWS: &'static [&'static str] = &[
stringify! { :foobar },
stringify! { (bg (g 8) :foobar) },
stringify! { (fill/xy :foobar) },
stringify! { (bsp/s :foo :bar) },
stringify! { (fixed/xy 20 10 :foobar) },
stringify! { (bsp/s (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/e (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/n (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/w (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/a (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! { (bsp/b (fixed/xy 5 6 :foo) (fixed/xy 7 8 :bar)) },
stringify! {
(bsp/s
(bsp/e (align/nw (fixed/xy 5 3 :foo))
(bsp/e (align/n (fixed/xy 5 3 :foo))
(align/ne (fixed/xy 5 3 :foo))))
(bsp/s
(bsp/e (align/w (fixed/xy 5 3 :foo))
(bsp/e (align/c (fixed/xy 5 3 :foo))
(align/e (fixed/xy 5 3 :foo))))
(bsp/e (align/sw (fixed/xy 5 3 :foo))
(bsp/e (align/s (fixed/xy 5 3 :foo))
(align/se (fixed/xy 5 3 :foo))))))
},
stringify! {
(bsp/s
(bsp/e (fixed/xy 8 5 (align/nw :foo))
(bsp/e (fixed/xy 8 5 (align/n :foo))
(fixed/xy 8 5 (align/ne :foo))))
(bsp/s
(bsp/e (fixed/xy 8 5 (align/w :foo))
(bsp/e (fixed/xy 8 5 (align/c :foo))
(fixed/xy 8 5 (align/e :foo))))
(bsp/e (fixed/xy 8 5 (align/sw :foo))
(bsp/e (fixed/xy 8 5 (align/s :foo))
(fixed/xy 8 5 (align/se :foo))))))
},
stringify! {
(bsp/s
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/nw :foo)))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/n :foo)))
(grow/xy 1 1 (fixed/xy 8 5 (align/ne :foo)))))
(bsp/s
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/w :foo)))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/c :foo)))
(grow/xy 1 1 (fixed/xy 8 5 (align/e :foo)))))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/sw :foo)))
(bsp/e (grow/xy 1 1 (fixed/xy 8 5 (align/s :foo)))
(grow/xy 1 1 (fixed/xy 8 5 (align/se :foo)))))))
},
stringify! { :map-e },
stringify! { (align/c :map-e) },
stringify! { :map-s },
stringify! { (align/c :map-s) },
stringify! {
(align/c (bg/behind :bg0 (margin/xy 1 1 (col
(bg/behind :bg1 (border/around :border1 (margin/xy 2 1 :label1)))
(bg/behind :bg2 (border/around :border2 (margin/xy 4 2 :label2)))
(bg/behind :bg3 (border/around :border3 (margin/xy 6 3 :label3)))))))
},
];
//handle!(TuiIn: |self: State, input|Action::from(input).eval(self).map(|_|None));
//view!(State: Tui: [ evaluate_output_expression, evaluate_output_expression_tui ]);
//draw!(State: Tui: [ draw_example ]);
//impl_from!(Action: |input: &TuiIn| todo!());
//fn draw_example (state: &State, to: &mut Tui) {}
//#[tengri_proc::expose]
//impl Example {
//fn _todo_u16_stub (&self) -> u16 { todo!() }
//fn _todo_bool_stub (&self) -> bool { todo!() }
//fn _todo_usize_stub (&self) -> usize { todo!() }
////[bool] => {}
////[u16] => {}
////[usize] => {}
//}
//#[tengri_proc::view(TuiOut)]
//impl Example {
//pub fn title (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, VIEWS.len())))).boxed()
//}
//pub fn code (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", VIEWS[self.0])))).boxed()
//}
//pub fn hello (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed()
//}
//pub fn world (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(100, 10, 10), "world").boxed()
//}
//pub fn hello_world (&self) -> impl Content<TuiOut> + use<'_> {
//"Hello world!".boxed()
//}
//pub fn map_e (&self) -> impl Content<TuiOut> + use<'_> {
//Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
//}
//pub fn map_s (&self) -> impl Content<TuiOut> + use<'_> {
//Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
//}
//}
//fn content (&self) -> dyn Draw<Engine = Tui> {
//let border_style = Style::default().fg(Color::Rgb(0,0,0));
//Align::Center(Layers::new(move|add|{
//add(&Background(Color::Rgb(0,128,128)))?;
//add(&Margin::XY(1, 1, Stack::down(|add|{
//add(&Layers::new(|add|{
//add(&Background(Color::Rgb(128,96,0)))?;
//add(&Border(Square(border_style)))?;
//add(&Margin::XY(2, 1, "..."))?;
//Ok(())
//}).debug())?;
//add(&Layers::new(|add|{
//add(&Background(Color::Rgb(128,64,0)))?;
//add(&Border(Lozenge(border_style)))?;
//add(&Margin::XY(4, 2, "---"))?;
//Ok(())
//}).debug())?;
//add(&Layers::new(|add|{
//add(&Background(Color::Rgb(96,64,0)))?;
//add(&Border(SquareBold(border_style)))?;
//add(&Margin::XY(6, 3, "~~~"))?;
//Ok(())
//}).debug())?;
//Ok(())
//})).debug())?;
//Ok(())
//}))
////Align::Center(Margin::X(1, Layers::new(|add|{
////add(&Background(Color::Rgb(128,0,0)))?;
////add(&Stack::down(|add|{
////add(&Margin::Y(1, Layers::new(|add|{
////add(&Background(Color::Rgb(0,128,0)))?;
////add(&Align::Center("12345"))?;
////add(&Align::Center("FOO"))
////})))?;
////add(&Margin::XY(1, 1, Layers::new(|add|{
////add(&Align::Center("1234567"))?;
////add(&Align::Center("BAR"))?;
////add(&Background(Color::Rgb(0,0,128)))
////})))
////}))
////})))
////Align::Y(Layers::new(|add|{
////add(&Background(Color::Rgb(128,0,0)))?;
////add(&Margin::X(1, Align::Center(Stack::down(|add|{
////add(&Align::X(Margin::Y(1, Layers::new(|add|{
////add(&Background(Color::Rgb(0,128,0)))?;
////add(&Align::Center("12345"))?;
////add(&Align::Center("FOO"))
////})))?;
////add(&Margin::XY(1, 1, Layers::new(|add|{
////add(&Align::Center("1234567"))?;
////add(&Align::Center("BAR"))?;
////add(&Background(Color::Rgb(0,0,128)))
////})))?;
////Ok(())
////})))))
////}))
//}

View file

@ -1,108 +0,0 @@
//! Mode 03: Hot reloaded Dizzle config
use ::{std::sync::{Arc, RwLock}, ratatui::style::Color, tengri::*};
fn main () {}
//#[tengri_proc::expose]
//impl Example {
//fn _todo_u16_stub (&self) -> u16 { todo!() }
//fn _todo_bool_stub (&self) -> bool { todo!() }
//fn _todo_usize_stub (&self) -> usize { todo!() }
////[bool] => {}
////[u16] => {}
////[usize] => {}
//}
//#[tengri_proc::view(TuiOut)]
//impl Example {
//pub fn title (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, VIEWS.len())))).boxed()
//}
//pub fn code (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", VIEWS[self.0])))).boxed()
//}
//pub fn hello (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed()
//}
//pub fn world (&self) -> impl Content<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(100, 10, 10), "world").boxed()
//}
//pub fn hello_world (&self) -> impl Content<TuiOut> + use<'_> {
//"Hello world!".boxed()
//}
//pub fn map_e (&self) -> impl Content<TuiOut> + use<'_> {
//Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
//}
//pub fn map_s (&self) -> impl Content<TuiOut> + use<'_> {
//Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
//}
//}
//fn content (&self) -> dyn Draw<Engine = Tui> {
//let border_style = Style::default().fg(Color::Rgb(0,0,0));
//Align::Center(Layers::new(move|add|{
//add(&Background(Color::Rgb(0,128,128)))?;
//add(&Margin::XY(1, 1, Stack::down(|add|{
//add(&Layers::new(|add|{
//add(&Background(Color::Rgb(128,96,0)))?;
//add(&Border(Square(border_style)))?;
//add(&Margin::XY(2, 1, "..."))?;
//Ok(())
//}).debug())?;
//add(&Layers::new(|add|{
//add(&Background(Color::Rgb(128,64,0)))?;
//add(&Border(Lozenge(border_style)))?;
//add(&Margin::XY(4, 2, "---"))?;
//Ok(())
//}).debug())?;
//add(&Layers::new(|add|{
//add(&Background(Color::Rgb(96,64,0)))?;
//add(&Border(SquareBold(border_style)))?;
//add(&Margin::XY(6, 3, "~~~"))?;
//Ok(())
//}).debug())?;
//Ok(())
//})).debug())?;
//Ok(())
//}))
////Align::Center(Margin::X(1, Layers::new(|add|{
////add(&Background(Color::Rgb(128,0,0)))?;
////add(&Stack::down(|add|{
////add(&Margin::Y(1, Layers::new(|add|{
////add(&Background(Color::Rgb(0,128,0)))?;
////add(&Align::Center("12345"))?;
////add(&Align::Center("FOO"))
////})))?;
////add(&Margin::XY(1, 1, Layers::new(|add|{
////add(&Align::Center("1234567"))?;
////add(&Align::Center("BAR"))?;
////add(&Background(Color::Rgb(0,0,128)))
////})))
////}))
////})))
////Align::Y(Layers::new(|add|{
////add(&Background(Color::Rgb(128,0,0)))?;
////add(&Margin::X(1, Align::Center(Stack::down(|add|{
////add(&Align::X(Margin::Y(1, Layers::new(|add|{
////add(&Background(Color::Rgb(0,128,0)))?;
////add(&Align::Center("12345"))?;
////add(&Align::Center("FOO"))
////})))?;
////add(&Margin::XY(1, 1, Layers::new(|add|{
////add(&Align::Center("1234567"))?;
////add(&Align::Center("BAR"))?;
////add(&Background(Color::Rgb(0,0,128)))
////})))?;
////Ok(())
////})))))
////}))
//}

View file

@ -13,20 +13,16 @@ use crate::*;
/// }
/// impl Screen for TestOut {
/// type Unit = u16;
/// fn show (&mut self, _: impl Draw<Self>) -> Perhaps<XYWH<u16>> {
/// println!("placed");
/// Ok(None)
/// }
/// fn area (&self) -> XYWH<Self::Unit> {
/// Default::default()
/// }
/// fn show (&mut self, _: impl Draw<Self>) -> Perhaps<XYWH<u16>>
/// { println!("placed"); Ok(None) }
/// fn area (&self) -> XYWH<Self::Unit>
/// { Default::default() }
/// fn clip <T> (
/// &mut self,
/// area: impl Into<Option<XYWH<u16>>>,
/// draw: impl FnOnce(&mut Self)->T
/// ) -> T {
/// draw(self)
/// }
/// ) -> T
/// { draw(self }
/// }
///
/// impl_draw!(|self: String, to: TestOut|{
@ -154,6 +150,7 @@ features! {
layout,
lrtb,
sizer,
space,
split,
thunk,
xywh

View file

@ -22,7 +22,7 @@ pub trait Coord: Send + Sync + Copy
+ From<u16> + Into<u16>
+ Into<usize>
+ Into<f64>
//+ std::iter::Step
+ std::iter::Step
{
/// Zero in own type.
fn zero () -> Self { 0.into() }

View file

@ -1,5 +1,3 @@
#![allow(unused)]
use crate::*;
impl<S: Screen, T: Draw<S>> Layout<S> for T {}
@ -160,14 +158,10 @@ pub trait Layout<S: Screen>: Draw<S> + Sized {
/// Use whole drawing area along one or both axes.
///
/// ```
/// # fn doctest_layout_full () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(0u16, 0, 80, 25);
/// assert_eq!("1".layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// assert_eq!("1".full_w().layout(area)?, Some(XYWH(0u16, 0, 80, 1)));
/// assert_eq!("1".full_h().layout(area)?, Some(XYWH(0u16, 0, 1, 25)));
/// assert_eq!("1".full_wh().layout(area)?, Some(XYWH(0u16, 0, 80, 25)));
/// # Ok(()) }
/// use tengri::Layout;
/// let _ = "".full_w();
/// let _ = "".full_h();
/// let _ = "".full_wh();
/// ```
pub enum Full<T: Screen, I: Draw<T>> {
__(PhantomData<T>),
@ -175,6 +169,7 @@ pub enum Full<T: Screen, I: Draw<T>> {
H(I),
WH(I),
}
impl_draw!(<T: Screen, I: Draw<T>,>|self: Full<T, I>, to: T|{
let XYWH(x0, y0, w0, h0) = to.area();
match self {
@ -200,14 +195,10 @@ impl_draw!(<T: Screen, I: Draw<T>,>|self: Full<T, I>, to: T|{
/// Move content in the positive direction of one or both axes.
///
/// ```
/// # fn doctest_layout_push () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(0u16, 0, 80, 25);
/// assert_eq!("1".layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// assert_eq!("1".push_x(1).layout(area)?, Some(XYWH(1u16, 0, 1, 1)));
/// assert_eq!("1".push_y(1).layout(area)?, Some(XYWH(0u16, 1, 1, 1)));
/// assert_eq!("1".push_xy(1, 1).layout(area)?, Some(XYWH(1u16, 1, 1, 1)));
/// # Ok(()) }
/// use tengri::Layout;
/// let _ = "".push_x(1);
/// let _ = "".push_y(1);
/// let _ = "".push_xy(1, 1);
/// ```
pub enum Push<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
@ -215,6 +206,7 @@ pub enum Push<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
Y(I, X),
XY(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Push<T, I, X>, to: T|{
match self {
Self::__(_) => unreachable!(),
@ -240,14 +232,10 @@ impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Push<T, I, X
/// Move content in the negative direction of one or both axes.
///
/// ```
/// # fn doctest_layout_pull () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(1u16, 1, 80, 25);
/// assert_eq!("1".layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// assert_eq!("1".pull_x(1).layout(area)?, Some(XYWH(0u16, 1, 1, 1)));
/// assert_eq!("1".pull_y(1).layout(area)?, Some(XYWH(1u16, 0, 1, 1)));
/// assert_eq!("1".pull_xy(1, 1).layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// # Ok(()) }
/// use tengri::Layout;
/// let _ = "".pull_x(1);
/// let _ = "".pull_y(1);
/// let _ = "".pull_xy(1, 1);
/// ```
pub enum Pull<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
@ -255,6 +243,7 @@ pub enum Pull<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
Y(I, X),
XY(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Pull<T, I, X>, _to: T|{
todo!()
});
@ -262,14 +251,10 @@ impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Pull<T, I, X
/// Only draw content if area is above a certain size.
///
/// ```
/// # fn doctest_layout_min () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(1u16, 1, 80, 25);
/// assert_eq!("1".min_w(5).layout(area)?, Some(XYWH(1u16, 1, 5, 1)));
/// assert_eq!("1".min_h(5).layout(area)?, Some(XYWH(1u16, 1, 1, 5)));
/// assert_eq!("1".min_wh(5, 5).layout(area)?, Some(XYWH(1u16, 1, 5, 5)));
/// assert_eq!("123456".min_w(5).layout(area)?, Some(XYWH(1u16, 1, 6, 1)));
/// # Ok(()) }
/// use tengri::Layout;
/// let _ = "".min_w(1);
/// let _ = "".min_h(1);
/// let _ = "".min_wh(1, 1);
/// ```
pub enum Min<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
@ -277,6 +262,7 @@ pub enum Min<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Min<T, I, X>, _to: T|{
todo!()
});
@ -284,13 +270,10 @@ impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Min<T, I, X>
/// Set maximum size of of drawing area.
///
/// ```
/// # fn doctest_layout_max () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(1u16, 1, 80, 25);
/// assert_eq!("12345".max_w(1).layout(area)?, Some(XYWH(1u16, 1, 1, 1)));
/// assert_eq!("12345".max_h(1).layout(area)?, Some(XYWH(1u16, 1, 1, 1)));
/// assert_eq!("12345".max_wh(1, 1).layout(area)?, Some(XYWH(1u16, 1, 5, 1)));
/// # Ok(()) }
/// use tengri::Layout;
/// let _ = "".max_w(1);
/// let _ = "".max_h(1);
/// let _ = "".max_wh(1, 1);
/// ```
pub enum Max<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
@ -298,6 +281,7 @@ pub enum Max<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Max<T, I, X>, to: T|{
let area: XYWH<T::Unit> = to.area();
let (item, area) = match self {
@ -332,6 +316,7 @@ pub enum Exact<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Exact<T, I, X>, to: T|{
let area: XYWH<T::Unit> = to.area();
let (item, area) = match self {
@ -360,27 +345,29 @@ pub enum Pad<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Pad<T, I, X>, _to: T|{
todo!()
});
pub struct Align<T>(Option<Azimuth>, T);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Align<T>, to: S|{
use Azimuth::*;
let XYWH(x0, y0, w0, h0) = to.area();
if let Some(XYWH(x, y, w, h)) = self.1.layout(to.area())? {
to.clip(match self.0 {
Some(NW) => XYWH(x0, y0, w, h),
Some(N) => XYWH(x0 + w0.minus(w) / 2.into(), y0, w, h),
Some(NE) => XYWH((x0 + w0).minus(w), y0, w, h),
Some(W) => XYWH(x0, y0 + h0.minus(h) / 2.into(), w, h),
Some(C) => XYWH(x0 + w0.minus(w) / 2.into(), y0 + h0.minus(h) / 2.into(), w, h),
Some(E) => XYWH((x0 + w0).minus(w), y0 + h0.minus(h) / 2.into(), w, h),
Some(SW) => XYWH(x0, (y0 + h0).minus(h), w, h),
Some(S) => XYWH(x0 + w0.minus(w) / 2.into(), (y0 + h0).minus(h), w, h),
Some(SE) => XYWH((x0 + w0).minus(w), (y0 + h0).minus(h), w, h),
Some(X) => XYWH(x0 + w0.minus(w) / 2.into(), y, w, h),
Some(Y) => XYWH(x, y0 + h0.minus(h) / 2.into(), w, h),
Some(NW) => XYWH(x0, y0, w, h),
Some(N) => XYWH(x0 + w0.sub(w) / 2.into(), y0, w, h),
Some(NE) => XYWH((x0 + w0).sub(w), y0, w, h),
Some(W) => XYWH(x0, y0 + h0.sub(h) / 2.into(), w, h),
Some(C) => XYWH(x0 + w0.sub(w) / 2.into(), y0 + h0.sub(h) / 2.into(), w, h),
Some(E) => XYWH((x0 + w0).sub(w), y0 + h0.sub(h) / 2.into(), w, h),
Some(SW) => XYWH(x0, (y0 + h0).sub(h), w, h),
Some(S) => XYWH(x0 + w0.sub(w) / 2.into(), (y0 + h0).sub(h), w, h),
Some(SE) => XYWH((x0 + w0).sub(w), (y0 + h0).sub(h), w, h),
Some(X) => XYWH(x0 + w0.sub(w) / 2.into(), y, w, h),
Some(Y) => XYWH(x, y0 + h0.sub(h) / 2.into(), w, h),
None => to.area()
}, |to|self.1.draw(to))
} else {
@ -416,11 +403,13 @@ pub struct Area<S: Screen, T: Draw<S>>(
pub Option<XYWH<S::Unit>>,
pub T
);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Area<S, T>, to: S|{
to.clip(self.0, |to|self.1.draw(to))
});
pub struct Origin<T>(Option<Azimuth>, T);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Origin<T>, _to: S|{
todo!()
});

View file

@ -8,7 +8,7 @@ pub trait Lrtb<N: Coord>: Xywh<N> {
// FIXME: factor origin
[self.x(), self.y(), self.x()+self.w(), self.y()+self.h()]
}
fn iter_x (&self) -> std::ops::Range<N> where Self: HasOrigin {
fn iter_x (&self) -> impl Iterator<Item = N> where Self: HasOrigin {
self.x_west()..self.x_east()
}
fn x_west (&self) -> N where Self: HasOrigin {
@ -26,7 +26,7 @@ pub trait Lrtb<N: Coord>: Xywh<N> {
fn x_center (&self) -> N where Self: HasOrigin {
todo!()
}
fn iter_y (&self) -> std::ops::Range<N> where Self: HasOrigin {
fn iter_y (&self) -> impl Iterator<Item = N> where Self: HasOrigin {
self.y_north()..self.y_south()
}
fn y_north (&self) -> N where Self: HasOrigin {

View file

@ -29,17 +29,3 @@ impl Sizer {
})
}
}
pub struct ShowSize;
impl Draw<Tui> for ShowSize {
fn layout (&self, area: XYWH<u16>) -> Perhaps<XYWH<u16>> {
let info = format!("{area:?}");
Ok(Some(XYWH(area.0, area.1, info.len() as u16, 1)))
}
fn draw (self, to: &mut Tui) -> Drawn<u16> {
let area = to.area();
let info = format!("{area:?}");
to.text(&info, area.0, area.1, info.len() as u16)
}
}

2
src/draw/space.rs Normal file
View file

@ -0,0 +1,2 @@
use crate::*;

View file

@ -190,11 +190,18 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
/// use tengri::{*, lang::*, ratatui::prelude::Color};
///
/// #[namespace(bool)]
/// #[namespace(u8)]
/// #[namespace(u16)]
/// #[namespace(Color get_color)]
/// #[namespace(u8 try_to_u8)]
/// #[namespace(u16 try_to_u16)]
/// #[namespace(Color try_to_color)]
/// #[interpret(Tui -> Option<XYWH<u16>>: try_eval_tui)]
/// struct State;
///
/// tengri::lang::primitive!(u8: try_to_u8);
/// tengri::lang::primitive!(u16: try_to_u16);
/// tengri::lang::interpret!(|self: State, context: Tui, lang|->Option<XYWH<u16>>{
/// expression = {
/// "text" (...rest) => { todo!() }
/// }
/// });
/// impl Interpret<Tui, Option<XYWH<u16>>> for State {
/// fn interpret_expr <'a> (&'a self, _: &mut Tui, lang: &'a impl Expression)
/// -> Usually<Option<XYWH<u16>>>
@ -203,36 +210,6 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
/// }
/// }
///
/// fn get_color (state: &State, src: impl Language) -> Perhaps<Color> {
/// if let Some(expr) = src.expr()? {
/// match (expr.head()?, expr.tail()?) {
/// (Some("g"), Some(tail)) => {
/// let n: u8 = state.namespace(tail.head().map_err(Into::into))?.ok_or(LanguageError::Domain("not gray"))?;
/// Ok(Some(Color::Rgb(n, n, n)))
/// },
/// (Some("rgb"), Some(tail)) => {
/// let r: u8 = state.namespace(tail.head().map_err(Into::into))?
/// .ok_or(LanguageError::Domain("not red"))?;
/// let g: u8 = state.namespace(tail.tail().head().map_err(Into::into))?
/// .ok_or(LanguageError::Domain("not green"))?;
/// let b: u8 = state.namespace(tail.tail().tail().head().map_err(Into::into))?
/// .ok_or(LanguageError::Domain("not blue"))?;
/// Ok(Some(Color::Rgb(r, g, b)))
/// },
/// (Some(_), _) => return Err(format!("not a color expression: {expr}").into()),
/// (None, _) => return Err(format!("not a color expression: {expr}").into()),
/// }
/// } else if let Ok(Some(sym)) = src.word() {
/// Ok(match sym {
/// ":color/bg" => Some(Color::Rgb(28, 32, 36)),
/// ":color/fg" => Some(Color::Rgb(98, 92, 96)),
/// _ => return Err(format!("not a color: {sym}").into())
/// })
/// } else {
/// return Err(format!("not a color: {:?}", src.src()?).into())
/// }
/// }
///
/// # fn main () -> tengri::Usually<()> {
/// let state = State;
/// let mut out = Tui::new(80, 25);
@ -244,7 +221,7 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
/// # Ok(()) }
/// ```
pub fn eval_view_tui <'a, S> (
state: &S, to: &mut Tui, expr: impl Expression + 'a
state: &S, output: &mut Tui, expr: impl Expression + 'a
) -> Perhaps<XYWH<u16>> where
S: Interpret<Tui, Option<XYWH<u16>>>
+ for<'b>Namespace<'b, bool>
@ -262,7 +239,7 @@ pub fn eval_view_tui <'a, S> (
match frags.next() {
Some("text") => {
if let Some(src) = args?.src()? {
to.show(src)
output.show(src)
} else {
return Ok(None)
}
@ -271,10 +248,11 @@ pub fn eval_view_tui <'a, S> (
Some("fg") => {
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
if let Some(color) = Namespace::namespace(state, arg0)? {
fg(color, thunk(move|to: &mut Tui|{
state.interpret(to, &arg1)?;
Ok(Some(to.area().into())) // FIXME?: don't max out the used area?
})).draw(to)
output.show(fg(color, thunk(move|output: &mut Tui|{
state.interpret(output, &arg1)?;
// FIXME?: don't max out the used area?
Ok(Some(output.area().into()))
})))
} else {
return Err(format!("fg: {arg0:?}: not a color").into())
}
@ -283,10 +261,11 @@ pub fn eval_view_tui <'a, S> (
Some("bg") => {
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
if let Some(color) = Namespace::namespace(state, arg0)? {
bg(color, thunk(move|to: &mut Tui|{
state.interpret(to, &arg1)?;
Ok(Some(to.area().into())) // FIXME?: don't max out the used area?
})).draw(to)
output.show(bg(color, thunk(move|output: &mut Tui|{
state.interpret(output, &arg1)?;
// FIXME?: don't max out the used area?
Ok(Some(output.area().into()))
})))
} else {
return Err(format!("bg: {arg0:?}: not a color").into())
}

View file

@ -1,11 +1,11 @@
//#![feature(anonymous_lifetime_in_impl_trait)]
#![feature(anonymous_lifetime_in_impl_trait)]
//#![feature(associated_type_defaults)]
//#![feature(const_default)]
//#![feature(const_option_ops)]
//#![feature(const_precise_live_drops)]
//#![feature(const_trait_impl)]
#![feature(const_precise_live_drops)]
#![feature(const_trait_impl)]
//#![feature(impl_trait_in_assoc_type)]
//#![feature(step_trait)]
#![feature(step_trait)]
//#![feature(trait_alias)]
//#![feature(type_alias_impl_trait)]
//#![feature(type_changing_struct_update)]

View file

@ -803,7 +803,7 @@ pub trait AddMidiOut {
/// Port connection manager.
///
/// ```
/// let connect = tengri::Connect::default();
/// let connect = tek::Connect::default();
/// ```
#[derive(Clone, Debug, Default)]
pub struct Connect {
@ -814,6 +814,7 @@ pub struct Connect {
}
impl Connect {
pub fn new <T: AsRef<str>> (
exact: Option<impl Iterator<Item = T>>,
re: Option<impl Iterator<Item = T>>,
@ -826,6 +827,62 @@ impl Connect {
connections
}
pub fn midi_ins <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
midi_from: &[T],
midi_from_re: Option<&[T]>,
) -> Usually<Vec<MidiInput>> {
Ok(Connect::new(
Some(midi_from.into_iter()),
Some([].into_iter()),
midi_from_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.midi_in(&format!("{}/{index}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
pub fn midi_outs <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
midi_to: &[T],
midi_to_re: Option<&[T]>,
) -> Usually<Vec<MidiOutput>> {
Ok(Connect::new(
Some(midi_to.into_iter()),
Some([].into_iter()),
midi_to_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.midi_out(&format!("{index}/{}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
pub fn audio_ins <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
audio_from: &[T],
audio_from_re: Option<&[T]>,
) -> Usually<Vec<AudioInput>> {
Ok(Connect::new(
Some(audio_from.into_iter()),
Some([].into_iter()),
audio_from_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.audio_in(&format!("{}/{index}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
pub fn audio_outs <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
audio_to: &[T],
audio_to_re: Option<&[T]>,
) -> Usually<Vec<AudioOutput>> {
Ok(Connect::new(
Some(audio_to.into_iter()),
Some([].into_iter()),
audio_to_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.audio_out(&format!("{index}/{}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
/// Connect to this exact port
pub fn exact (name: impl AsRef<str>) -> Self {
let info = format!("=:{}", name.as_ref()).into();
@ -866,59 +923,3 @@ impl Connect {
}).into()
}
}
pub fn connect_midi_ins <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
midi_from: &[T],
midi_from_re: Option<&[T]>,
) -> Usually<Vec<MidiInput>> {
Ok(Connect::new(
Some(midi_from.into_iter()),
Some([].into_iter()),
midi_from_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.midi_in(&format!("{}/{index}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
pub fn connect_midi_outs <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
midi_to: &[T],
midi_to_re: Option<&[T]>,
) -> Usually<Vec<MidiOutput>> {
Ok(Connect::new(
Some(midi_to.into_iter()),
Some([].into_iter()),
midi_to_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.midi_out(&format!("{index}/{}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
pub fn connect_audio_ins <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
audio_from: &[T],
audio_from_re: Option<&[T]>,
) -> Usually<Vec<AudioInput>> {
Ok(Connect::new(
Some(audio_from.into_iter()),
Some([].into_iter()),
audio_from_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.audio_in(&format!("{}/{index}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}
pub fn connect_audio_outs <T: AsRef<str>> (
jack: &Jack<'static>,
name: &T,
audio_to: &[T],
audio_to_re: Option<&[T]>,
) -> Usually<Vec<AudioOutput>> {
Ok(Connect::new(
Some(audio_to.into_iter()),
Some([].into_iter()),
audio_to_re.map(|x|x.into_iter())).iter().enumerate()
.map(|(index, connect)|jack.audio_out(&format!("{index}/{}", name.as_ref()), &[connect.clone()]))
.collect::<Result<_, _>>()?)
}

0
src/sing/jack.rs Normal file
View file

0
src/sing/jack_event.rs Normal file
View file

0
src/sing/jack_perf.rs Normal file
View file

View file

@ -1,4 +1,5 @@
use crate::lang::*;
use crate::*;
use crate::{*, lang::*, draw::*, task::*, exit::*};
use ::ratatui::buffer::Cell;
/// TUI buffer sized by `usize` instead of `u16`.

View file

@ -1,6 +1,6 @@
use crate::*;
use ratatui::prelude::Color;
use dizzle::{Expression, LanguageError::*};
use dizzle::{Ostensibly, Expression, LanguageError::*};
pub trait ColorDsl<T>: Sized {
fn new_g (expr: T, try_to_u8: impl Fn(Perhaps<&str>)->Perhaps<u8>) -> Usually<Self>;

View file

@ -1,5 +1,10 @@
use ::dizzle::{Language, Symbol, Usually};
use ::crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
use crate::{task::Task, term::TuiEvent};
use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}};
use ::std::time::Duration;
use ::dizzle::{Language, Symbol, Usually, Apply};
use ::crossterm::event::{
read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState
};
/// TUI key spec.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]

View file

@ -1,3 +1,5 @@
use crate::*;
/// Stackably padded.
///
/// ```

View file

@ -1,5 +1,5 @@
use crate::*;
use ratatui::{prelude::{Position}};
use ratatui::{prelude::{Style, Position, Backend, Color}};
pub const fn x_repeat (c: &str) -> impl Draw<Tui> {
thunk(move|to: &mut Tui|{

View file

@ -1,5 +1,5 @@
use crate::*;
use ratatui::{prelude::{Position}};
use ratatui::{prelude::{Style, Position, Backend, Color}};
pub const ICON_DEC_V: &[char] = &['▲'];
pub const ICON_INC_V: &[char] = &['▼'];
@ -7,7 +7,7 @@ pub const ICON_DEC_H: &[char] = &[' ', '🞀', ' '];
pub const ICON_INC_H: &[char] = &[' ', '🞂', ' '];
pub fn x_scroll () -> impl Draw<Tui> {
thunk(|Tui(buf, XYWH(x1, y1, w, _h)): &mut Tui|{
thunk(|Tui(buf, XYWH(x1, y1, w, h)): &mut Tui|{
let x2 = *x1 + *w;
for (i, x) in (*x1..=x2).enumerate() {
if let Some(cell) = buf.cell_mut(Position::from((x, *y1))) {
@ -35,7 +35,7 @@ pub fn x_scroll () -> impl Draw<Tui> {
}
pub fn y_scroll () -> impl Draw<Tui> {
thunk(|Tui(buf, XYWH(x1, y1, _w, h)): &mut Tui|{
thunk(|Tui(buf, XYWH(x1, y1, w, h)): &mut Tui|{
let y2 = *y1 + *h;
for (i, y) in (*y1..=y2).enumerate() {
if let Some(cell) = buf.cell_mut(Position::from((*x1, y))) {

View file

@ -1,36 +1,18 @@
#![allow(unused)]
use crate::*;
pub(crate) use ::unicode_width::*;
#[cfg(feature = "term")] mod impl_term {
use super::*;
use crate::*;
use ratatui::prelude::Position;
impl_draw!(|self: String, to: Tui|{self.as_str().draw(to)});
impl_draw!(|self: std::sync::Arc<str>, to: Tui|{self.as_ref().draw(to)});
impl_draw!(|self: &std::sync::Arc<str>, to: Tui|{self.as_ref().draw(to)});
impl Draw<Tui> for &str {
fn layout (&self, area: XYWH<u16>) -> Perhaps<XYWH<u16>> {
let XYWH(x, y, ..) = area;
let mut max_w = 0u16;
let mut max_h = 0u16;
for line in self.split("\n") {
max_h += 1;
max_w = max_w.max(line.len() as u16);
}
Ok(Some(XYWH(x, y, max_w, max_h)))
}
fn draw (self, to: &mut Tui) -> Drawn<u16> {
let area = self.layout(to.area())?.unwrap();
////let info = format!("{area:?}");
//to.text(&self, area.0, area.1, self.len() as u16)
for (index, line) in self.split("\n").enumerate() {
let _ = to.text(&line, area.0, area.1 + index as u16, width_chars_max(area.2, line) as u16)?;
}
Ok(Some(area))
}
}
impl_draw!(|self: &str, to: Tui|{
let XYWH(x, y, w, ..) = to.1.centered_xy([width_chars_max(to.w(), self), 1]);
to.text(&self, x, y, w)
});
impl_draw!(<T: AsRef<str>,>|self: TrimString<T>, to: Tui|{self.as_ref().draw(to)});
impl_draw!(<T: AsRef<str>,>|self: TrimStringRef<'_, T>, to: Tui|{
@ -98,9 +80,7 @@ pub fn trim_string (max_width: usize, input: impl AsRef<str>) -> String {
pub struct TrimString<T: AsRef<str>>(pub u16, pub T);
impl<T: AsRef<str>> AsRef<str> for TrimString<T> { fn as_ref (&self) -> &str { self.1.as_ref() } }
impl<'a, T: AsRef<str>> TrimString<T> {
fn to_ref (&self) -> TrimStringRef<'_, T> {
TrimStringRef(self.0, &self.1)
}
fn to_ref (&self) -> TrimStringRef<'_, T> { TrimStringRef(self.0, &self.1) }
}
/// Displays a borrowed [str]-like with fixed maximum width