diff --git a/Justfile b/Justfile index 23af11d..83c5796 100644 --- a/Justfile +++ b/Justfile @@ -29,11 +29,9 @@ doc: CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' \ cargo doc -example-tui-00: +mode-00: cargo run --example mode_00 - -example-tui-01: +mode-01: cargo run --example mode_01 - -example-tui-02: +mode-02: cargo run --example mode_02 diff --git a/examples/mode_00.rs b/examples/mode_00.rs index 9ab858c..31b148d 100644 --- a/examples/mode_00.rs +++ b/examples/mode_00.rs @@ -1,3 +1,37 @@ -//! Mode 0: Direct draw -use ::{std::sync::{Arc, RwLock}, ratatui::style::Color, tengri::*}; -fn main () {} +//! 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 }; + () + }, + _ => {} + } + }) +}); diff --git a/examples/mode_01.rs b/examples/mode_01.rs index 0ad5241..d7ee626 100644 --- a/examples/mode_01.rs +++ b/examples/mode_01.rs @@ -1,161 +1,63 @@ -//! Mode 01 +//! Mode 01: Direct view, actions with history + 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, /** 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)); }, - _ => {} + Down | Right => Action::Next, + Up | Left => Action::Prev, + _ => { return Ok(()) } } + .apply(self)? + .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))) + 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()), + ) }); -impl Interpret for State { - fn interpret_expr (&self, to: &mut Tui, expr: &impl Language) -> Usually { - 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 { - use std::str::FromStr; - if let Some(src) = src? { - Ok(Some(u8::from_str(src)?)) - } else { - Ok(None) - } -} -impl Interpret>> for State { - fn interpret_word (&self, to: &mut Tui, sym: &impl Language) -> Perhaps> { - 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> { - 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 { - self.cursor = (self.cursor + 1) % VIEWS.len(); - Ok(Some(Action::Prev)) - } - fn prev (&mut self) -> Perhaps { - self.cursor = if self.cursor > 0 { self.cursor - 1 } else { VIEWS.len() - 1 }; - Ok(Some(Action::Next)) - } -} -#[derive(Debug)] -enum Action { + +#[derive(Debug)] enum Action { /** Increment cursor */ Next, /** Decrement cursor */ Prev, } + impl Action { - fn eval (&self, state: &mut State) -> Perhaps { + fn apply (&self, state: &mut State) -> Perhaps { use Action::*; - match self { Next => state.next(), Prev => state.prev(), } + match self { + Next => state.next(), + Prev => state.prev(), + } + } +} + +impl State { + fn next (&mut self) -> Perhaps { + self.cursor = (self.cursor + 1) % 10; + Ok(Some(Action::Prev)) + } + fn prev (&mut self) -> Perhaps { + self.cursor = if self.cursor > 0 { self.cursor - 1 } else { 10 - 1 }; + Ok(Some(Action::Next)) } } -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) {} diff --git a/examples/mode_02.rs b/examples/mode_02.rs index 40fba02..70cec30 100644 --- a/examples/mode_02.rs +++ b/examples/mode_02.rs @@ -1,107 +1,162 @@ -//! Mode 02 -use ::{std::sync::{Arc, RwLock}, ratatui::style::Color, tengri::*}; -fn main () {} +//! Mode 02: Inline Dizzle config -//#[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 + 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 + use<'_> { - //Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", VIEWS[self.0])))).boxed() - //} - //pub fn hello (&self) -> impl Content + use<'_> { - //Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed() - //} - //pub fn world (&self) -> impl Content + use<'_> { - //Tui::bg(Color::Rgb(100, 10, 10), "world").boxed() - //} - //pub fn hello_world (&self) -> impl Content + use<'_> { - //"Hello world!".boxed() - //} - //pub fn map_e (&self) -> impl Content + use<'_> { - //Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() - //} - //pub fn map_s (&self) -> impl Content + use<'_> { - //Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() - //} -//} - - //fn content (&self) -> dyn Draw { - //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(()) - ////}))))) - ////})) - //} +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, + /** 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 for State { + fn interpret_expr (&self, to: &mut Tui, expr: &impl Language) -> Usually { + 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 { + use std::str::FromStr; + if let Some(src) = src? { + Ok(Some(u8::from_str(src)?)) + } else { + Ok(None) + } +} +impl Interpret>> for State { + fn interpret_word (&self, to: &mut Tui, sym: &impl Language) -> Perhaps> { + 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> { + 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 { + self.cursor = (self.cursor + 1) % VIEWS.len(); + Ok(Some(Action::Prev)) + } + fn prev (&mut self) -> Perhaps { + 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 { + 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) {} diff --git a/examples/mode_03.rs b/examples/mode_03.rs new file mode 100644 index 0000000..30eec8c --- /dev/null +++ b/examples/mode_03.rs @@ -0,0 +1,108 @@ +//! 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 + 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 + use<'_> { + //Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", VIEWS[self.0])))).boxed() + //} + //pub fn hello (&self) -> impl Content + use<'_> { + //Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed() + //} + //pub fn world (&self) -> impl Content + use<'_> { + //Tui::bg(Color::Rgb(100, 10, 10), "world").boxed() + //} + //pub fn hello_world (&self) -> impl Content + use<'_> { + //"Hello world!".boxed() + //} + //pub fn map_e (&self) -> impl Content + use<'_> { + //Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() + //} + //pub fn map_s (&self) -> impl Content + use<'_> { + //Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() + //} +//} + + //fn content (&self) -> dyn Draw { + //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(()) + ////}))))) + ////})) + //}