move test crate into core

This commit is contained in:
🪞👃🪞 2024-09-12 22:31:51 +03:00
parent 02db343574
commit 0a842b607a
12 changed files with 523 additions and 507 deletions

571
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,5 @@ resolver = "2"
members = [
"crates/tek_core",
"crates/tek_mixer",
"crates/tek_sequencer",
"crates/tek_test",
"crates/tek_sequencer"
]

View file

@ -16,3 +16,7 @@ once_cell = "1.19.0"
ratatui = { version = "0.26.3", features = [ "unstable-widget-ref", "underline-color" ] }
toml = "0.8.12"
#no_deadlocks = "1.3.2"
[dev-dependencies]
tek_mixer = { version = "0.1.0", path = "../tek_mixer" }
tek_sequencer = { version = "0.1.0", path = "../tek_sequencer" }

View file

@ -0,0 +1,75 @@
use tek_core::*;
use tek_core::jack::*;
fn main () -> Usually<()> {
Tui::run(Arc::new(RwLock::new(Demo::new())))?;
Ok(())
}
pub struct Demo<E: Engine> {
index: usize,
items: Vec<Box<dyn Widget<Engine = E>>>
}
impl Demo<Tui> {
fn new () -> Self {
Self {
index: 0,
items: vec![
Box::new(tek_sequencer::TransportPlayPauseButton {
_engine: Default::default(),
transport: None,
value: Some(TransportState::Stopped),
focused: true
}),
Box::new(tek_sequencer::TransportPlayPauseButton {
_engine: Default::default(),
transport: None,
value: Some(TransportState::Rolling),
focused: false
}),
]
}
}
}
impl Content for Demo<Tui> {
type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> {
Align::Center(Fixed::XY(10, 10, Layers::new(|add|{
add(&FillBg(Color::Rgb(128,0,0)))?;
add(&Split::down(|add|{
add(&Layers::new(|add|{
add(&FillBg(Color::Rgb(0,128,0)))?;
add(&Align::Center("12345"))?;
add(&Align::Center("FOO"))
}))?;
add(&Layers::new(|add|{
add(&FillBg(Color::Rgb(0,0,128)))?;
add(&Align::Center("1234567"))?;
add(&Align::Center("BAR"))
}))?;
Ok(())
}))
})))
}
}
impl Handle<Tui> for Demo<Tui> {
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
match from.event() {
key!(KeyCode::PageUp) => {
self.index = (self.index + 1) % self.items.len();
},
key!(KeyCode::PageDown) => {
self.index = if self.index > 1 {
self.index - 1
} else {
self.items.len() - 1
};
},
_ => return Ok(None)
}
Ok(Some(true))
}
}

View file

View file

@ -388,20 +388,16 @@ impl<T> Align<T> {
/// Enforce fixed size of drawing area
pub enum Fixed<U: Number, T> {
/// Enforce fixed width
W(U, T),
X(U, T),
/// Enforce fixed height
H(U, T),
Y(U, T),
/// Enforce fixed width and height
WH(U, U, T),
XY(U, U, T),
}
impl<N: Number, T> Fixed<N, T> {
pub fn inner (&self) -> &T {
match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}
match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, }
}
}
@ -415,7 +411,7 @@ pub enum Min<U: Number, T> {
XY(U, U, T),
}
impl<N: Number, T> Min<N, T> {
fn inner (&self) -> &T {
pub fn inner (&self) -> &T {
match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, }
}
}
@ -423,16 +419,12 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Min<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(match self {
Self::X(w, _) => (to.w() < *w).then(||{
[to.x() + *w, to.y(), to.w() - *w, to.h()]
}),
Self::Y(h, _) => (to.h() < *h).then(||{
[to.x(), to.y() + *h, to.w(), to.h() - *h]
}),
Self::XY(w, h, _) => (to.w() < *w || to.h() < *h).then(||{
[to.x() + *w, to.y() + *h, to.w() - *w, to.h() - *h]
})
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
Self::X(w, _) => (to.w() < *w).then(||[to.x() + *w, to.y(), to.w() - *w, to.h()]),
Self::Y(h, _) => (to.h() < *h).then(||[to.x(), to.y() + *h, to.w(), to.h() - *h]),
Self::XY(w, h, _) => (to.w() < *w || to.h() < *h).then(||[
to.x() + *w, to.y() + *h, to.w() - *w, to.h() - *h
])
}.map(|stretched|self.inner().layout(stretched.into())).transpose()?.flatten())
}
// TODO: 🡘 🡙 ←🡙→
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -458,18 +450,14 @@ impl<N: Number, T> Max<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Max<E:: Unit, T> {
type Engine = E;
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(match self {
Self::X(w, _) => (area.w() < *w).then(||{
[area.x(), area.y(), area.w().min(*w), area.h()]
}),
Self::Y(h, _) => (area.h() < *h).then(||{
[area.x(), area.y(), area.w(), area.h().min(*h)]
}),
Self::XY(w, h, _) => (area.w() < *w || area.h() < *h).then(||{
[area.x(), area.y(), area.w().min(*w), area.h().min(*h)]
})
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
Self::X(w, _) => (*w <= to.w()).then(||[to.x(), to.y(), to.w().min(*w), to.h()]),
Self::Y(h, _) => (*h <= to.h()).then(||[to.x(), to.y(), to.w(), to.h().min(*h)]),
Self::XY(w, h, _) => (*w <= to.w() || *h <= to.h()).then(||[
to.x(), to.y(), to.w().min(*w), to.h().min(*h)
])
}.map(|clamped|self.inner().layout(clamped.into())).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
@ -494,18 +482,14 @@ impl<N: Number, T> Outset<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
type Engine = E;
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(match self {
Self::X(w, _) => (area.w() < *w).then(||{
[area.x() - *w, area.y(), area.w() + *w + *w, area.h()]
}),
Self::Y(h, _) => (area.h() < *h).then(||{
[area.x(), area.y() - *h, area.w(), area.h() + *h + *h]
}),
Self::XY(w, h, _) => (area.w() < *w || area.h() < *h).then(||{
[area.x()- *w, area.y() - *h, area.w() + *w + *w, area.h() + *h + *h]
})
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
Self::X(w, _) => (*w <= to.w()).then(||[to.x() - *w, to.y(), to.w() + *w + *w, to.h()]),
Self::Y(h, _) => (*h <= to.h()).then(||[to.x(), to.y() - *h, to.w(), to.h() + *h + *h]),
Self::XY(w, h, _) => (*w <= to.w() || *h <= to.h()).then(||[
to.x()- *w, to.y() - *h, to.w() + *w + *w, to.h() + *h + *h
])
}.map(|grown|self.inner().layout(grown.into())).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
@ -530,18 +514,14 @@ impl<N: Number, T: Widget> Inset<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
type Engine = E;
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(match self {
Self::X(w, _) => (area.w() < *w).then(||{
[area.x() + *w, area.y(), area.w() - *w, area.h()]
}),
Self::Y(h, _) => (area.h() < *h).then(||{
[area.x(), area.y() + *h, area.w(), area.h() - *h]
}),
Self::XY(w, h, _) => (area.w() < *w || area.h() < *h).then(||{
[area.x() - *w, area.y() - *h, area.w() + *w, area.h() + *h]
})
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
Self::X(w, _) => (*w <= to.w()).then(||[to.x() + *w, to.y(), to.w() - *w, to.h()]),
Self::Y(h, _) => (*h <= to.h()).then(||[to.x(), to.y() + *h, to.w(), to.h() - *h]),
Self::XY(w, h, _) => (*w <= to.w() || *h <= to.h()).then(||[
to.x() - *w, to.y() - *h, to.w() + *w, to.h() + *h
])
}.map(|shrunk|self.inner().layout(shrunk.into())).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
@ -562,22 +542,24 @@ impl<N: Number, T: Widget> Offset<N, T> {
fn inner (&self) -> &T {
match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, }
}
fn x (&self) -> N {
match self { Self::X(x, _) => *x, Self::Y(_, _) => N::default(), Self::XY(x, _, _) => *x }
}
fn y (&self) -> N {
match self { Self::X(_, _) => N::default(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y }
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Offset<E::Unit, T> {
type Engine = E;
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(match self {
Self::X(w, _) => (area.w() < *w).then(||{
[area.x() + *w, area.y(), area.w() - *w, area.h()]
}),
Self::Y(h, _) => (area.h() < *h).then(||{
[area.x(), area.y() + *h, area.w(), area.h() - *h]
}),
Self::XY(w, h, _) => (area.w() < *w || area.h() < *h).then(||{
[area.x() + *w, area.y() + *h, area.w() - *w, area.h() - *h]
})
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
Self::X(w, _) => (*w <= to.w()).then(||[to.x() + *w, to.y(), to.w() - *w, to.h()]),
Self::Y(h, _) => (*h <= to.h()).then(||[to.x(), to.y() + *h, to.w(), to.h() - *h]),
Self::XY(w, h, _) => (*w <= to.w() || *h <= to.h()).then(||[
to.x() + *w, to.y() + *h, to.w() - *w, to.h() - *h
])
}.map(|shifted|self.inner().layout(shifted.into())).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())

View file

@ -25,11 +25,16 @@ use std::fmt::{Debug, Display};
($($name:ident)*) => { $(mod $name; pub use self::$name::*;)* };
}
/// Define and reexport public modules.
/// Define public modules.
#[macro_export] macro_rules! pubmod {
($($name:ident)*) => { $(pub mod $name;)* };
}
/// Define test modules.
#[macro_export] macro_rules! testmod {
($($name:ident)*) => { $(#[cfg(test)] mod $name;)* };
}
submod! {
audio
edn
@ -39,6 +44,10 @@ submod! {
tui
}
testmod! {
test
}
/// Standard result type.
pub type Usually<T> = Result<T, Box<dyn Error>>;
@ -52,7 +61,7 @@ pub trait Number: Send + Sync + Copy
+ Mul<Self, Output=Self>
+ Div<Self, Output=Self>
+ Ord + PartialEq + Eq
+ Debug + Display {}
+ Debug + Display + Default {}
impl<T> Number for T where
T: Send + Sync + Copy
@ -61,5 +70,5 @@ impl<T> Number for T where
+ Mul<Self, Output=Self>
+ Div<Self, Output=Self>
+ Ord + PartialEq + Eq
+ Debug + Display
+ Debug + Display + Default
{}

View file

@ -0,0 +1,75 @@
use crate::*;
#[test]
fn test_offset () -> Usually<()> {
let area: [u16;4] = [50, 50, 100, 100];
assert_eq!(Offset::X(1, "1").layout(area)?, Some([51, 50, 1, 1]));
assert_eq!(Offset::Y(1, "1").layout(area)?, Some([50, 51, 1, 1]));
assert_eq!(Offset::XY(1, 1, "1").layout(area)?, Some([51, 51, 1, 1]));
Ok(())
}
#[test]
fn test_outset () -> Usually<()> {
let area: [u16;4] = [50, 50, 100, 100];
assert_eq!(Outset::X(1, "1").layout(area)?, Some([49, 50, 3, 1]));
assert_eq!(Outset::Y(1, "1").layout(area)?, Some([50, 49, 1, 3]));
assert_eq!(Outset::XY(1, 1, "1").layout(area)?, Some([49, 49, 3, 3]));
Ok(())
}
#[test]
fn test_stuff () -> Usually<()> {
let area: [u16;4] = [0, 0, 100, 100];
assert_eq!("1".layout(area)?,
Some([0, 0, 1, 1]));
assert_eq!("333".layout(area)?,
Some([0, 0, 3, 1]));
assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?,
Some([0, 0, 3, 1]));
assert_eq!(Split::down(|add|{add(&"1")?;add(&"333")}).layout(area)?,
Some([0, 0, 3, 2]));
assert_eq!(Split::right(|add|{add(&"1")?;add(&"333")}).layout(area)?,
Some([0, 0, 4, 1]));
assert_eq!(Split::down(|add|{
add(&Split::right(|add|{add(&"1")?;add(&"333")}))?;
add(&"55555")
}).layout(area)?,
Some([0, 0, 5, 2]));
let area: [u16;4] = [1, 1, 100, 100];
assert_eq!(Outset::X(1, Split::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
Some([0, 1, 6, 1]));
assert_eq!(Outset::Y(1, Split::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
Some([1, 0, 4, 3]));
assert_eq!(Outset::XY(1, 1, Split::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
Some([0, 0, 6, 3]));
assert_eq!(Split::down(|add|{
add(&Outset::XY(1, 1, "1"))?;
add(&Outset::XY(1, 1, "333"))
}).layout(area)?,
Some([1, 1, 5, 6]));
let area: [u16;4] = [1, 1, 95, 100];
assert_eq!(Align::Center(Split::down(|add|{
add(&Outset::XY(1, 1, "1"))?;
add(&Outset::XY(1, 1, "333"))
})).layout(area)?,
Some([46, 48, 5, 6]));
assert_eq!(Align::Center(Split::down(|add|{
add(&Layers::new(|add|{
//add(&Outset::XY(1, 1, FillBg(Color::Rgb(0,128,0))))?;
add(&Outset::XY(1, 1, "1"))?;
add(&Outset::XY(1, 1, "333"))?;
//add(&FillBg(Color::Rgb(0,128,0)))?;
Ok(())
}))?;
add(&Layers::new(|add|{
//add(&Outset::XY(1, 1, FillBg(Color::Rgb(0,0,128))))?;
add(&Outset::XY(1, 1, "555"))?;
add(&Outset::XY(1, 1, "777777"))?;
//add(&FillBg(Color::Rgb(0,0,128)))?;
Ok(())
}))
})).layout(area)?,
Some([46, 48, 5, 6]));
Ok(())
}

View file

@ -454,18 +454,14 @@ pub const NOT_DIM_BOLD: Style = Style {
impl<T: Widget<Engine = Tui>> Widget for Fixed<u16, T> {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
Ok(match self {
Self::W(w, item) => if area.w() < *w { None } else {
item.layout(area)?.map(|[x, y, _, h]|[x, y, *w, h])
},
Self::H(h, item) => if area.w() < *h { None } else {
item.layout(area)?.map(|[x, y, w, _]|[x, y, w, *h])
},
Self::WH(w, h, item) => if area.w() < *w || area.h() < *h { None } else {
item.layout(area)?.map(|[x, y, _, _]|[x, y, *w, *h])
}
})
Self::X(w, _) => (to.w() < *w).then(||[to.x() + *w, to.y(), to.w() - *w, to.h()]),
Self::Y(h, _) => (to.h() < *h).then(||[to.x(), to.y() + *h, to.w(), to.h() - *h]),
Self::XY(w, h, _) => (to.w() < *w || to.h() < *h).then(||[
to.x() + *w, to.y() + *h, to.w() - *w, to.h() - *h
])
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
// 🡘 🡙 ←🡙→
@ -504,9 +500,8 @@ where
if w >= to.w() {
return Ok(())
}
if let Some([_, _, width, height]) = Offset::X(
w, component as &dyn Widget<Engine = Tui>
).layout(to)? {
let area = Offset::X(w, component as &dyn Widget<Engine = Tui>).layout(to)?;
if let Some([_, _, width, height]) = area {
w += width;
h = h.max(height)
}
@ -527,9 +522,8 @@ where
if h >= area.h() {
return Ok(())
}
if let Some([_, _, width, height]) = Offset::Y(
h, component as &dyn Widget<Engine = Tui>
).render(to)? {
let area = Offset::Y(h, component as &dyn Widget<Engine = Tui>).render(to)?;
if let Some([_, _, width, height]) = area {
h += height;
w = w.max(width)
};
@ -541,9 +535,8 @@ where
if w >= area.w() {
return Ok(())
}
if let Some([_, _, width, height]) = Offset::X(
w, component as &dyn Widget<Engine = Tui>
).render(to)? {
let area = Offset::X(w, component as &dyn Widget<Engine = Tui>).render(to)?;
if let Some([_, _, width, height]) = area {
w += width;
h = h.max(height)
};

View file

@ -526,7 +526,7 @@ impl<'a> Content for SceneRows<'a> {
let Self(offset, columns, rows, tracks, scenes) = *self;
Split::down(move |add| {
for (scene, (pulses, _)) in scenes.iter().zip(rows) {
add(&Fixed::H(1.max((pulses / 96) as u16), SceneRow(
add(&Fixed::X(1.max((pulses / 96) as u16), SceneRow(
tracks, scene, columns, offset
)))?;
}

View file

@ -1,9 +0,0 @@
[package]
name = "tek_test"
edition = "2021"
version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
#tek_mixer = { path = "../tek_mixer" }
tek_sequencer = { path = "../tek_sequencer" }

View file

@ -1,135 +0,0 @@
use tek_core::*;
use tek_core::jack::*;
pub fn main () -> Usually<()> {
Tui::run(Arc::new(RwLock::new(Demo::new())))?;
Ok(())
}
pub struct Demo<E: Engine> {
index: usize,
items: Vec<Box<dyn Widget<Engine = E>>>
}
impl Demo<Tui> {
fn new () -> Self {
Self {
index: 0,
items: vec![
Box::new(tek_sequencer::TransportPlayPauseButton {
_engine: Default::default(),
transport: None,
value: Some(TransportState::Stopped),
focused: true
}),
Box::new(tek_sequencer::TransportPlayPauseButton {
_engine: Default::default(),
transport: None,
value: Some(TransportState::Rolling),
focused: false
}),
]
}
}
}
impl Content for Demo<Tui> {
type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> {
Align::Center(Layers::new(|add|{
add(&FillBg(Color::Rgb(128,0,0)))?;
add(&Split::down(|add|{
add(&Layers::new(|add|{
add(&FillBg(Color::Rgb(0,128,0)))?;
add(&Align::Center("12345"))?;
add(&Align::Center("FOO"))
}))?;
add(&Fixed::H(10, Layers::new(|add|{
add(&FillBg(Color::Rgb(0,0,128)))?;
add(&Align::Center("1234567"))?;
add(&Align::Center("BAR"))
})))?;
Ok(())
}))
}))
}
}
impl Handle<Tui> for Demo<Tui> {
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
match from.event() {
key!(KeyCode::PageUp) => {
self.index = (self.index + 1) % self.items.len();
},
key!(KeyCode::PageDown) => {
self.index = if self.index > 1 {
self.index - 1
} else {
self.items.len() - 1
};
},
_ => return Ok(None)
}
Ok(Some(true))
}
}
#[cfg(test)]
mod test {
use tek_core::*;
#[test]
fn test_stuff () -> Usually<()> {
let area: [u16;4] = [0, 0, 100, 100];
assert_eq!("1".layout(area)?,
Some([0, 0, 1, 1]));
assert_eq!("333".layout(area)?,
Some([0, 0, 3, 1]));
assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?,
Some([0, 0, 3, 1]));
assert_eq!(Split::down(|add|{add(&"1")?;add(&"333")}).layout(area)?,
Some([0, 0, 3, 2]));
assert_eq!(Split::right(|add|{add(&"1")?;add(&"333")}).layout(area)?,
Some([0, 0, 4, 1]));
assert_eq!(Split::down(|add|{
add(&Split::right(|add|{add(&"1")?;add(&"333")}))?;
add(&"55555")
}).layout(area)?,
Some([0, 0, 5, 2]));
let area: [u16;4] = [1, 1, 100, 100];
assert_eq!(Outset::W(1, Split::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
Some([0, 1, 6, 1]));
assert_eq!(Outset::H(1, Split::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
Some([1, 0, 4, 3]));
assert_eq!(Outset::WH(1, 1, Split::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
Some([0, 0, 6, 3]));
assert_eq!(Split::down(|add|{
add(&Outset::WH(1, 1, "1"))?;
add(&Outset::WH(1, 1, "333"))
}).layout(area)?,
Some([1, 1, 5, 6]));
let area: [u16;4] = [1, 1, 95, 100];
assert_eq!(Align::Center(Split::down(|add|{
add(&Outset::WH(1, 1, "1"))?;
add(&Outset::WH(1, 1, "333"))
})).layout(area)?,
Some([46, 48, 5, 6]));
assert_eq!(Align::Center(Split::down(|add|{
add(&Layers::new(|add|{
//add(&Outset::WH(1, 1, FillBg(Color::Rgb(0,128,0))))?;
add(&Outset::WH(1, 1, "1"))?;
add(&Outset::WH(1, 1, "333"))?;
//add(&FillBg(Color::Rgb(0,128,0)))?;
Ok(())
}))?;
add(&Layers::new(|add|{
//add(&Outset::WH(1, 1, FillBg(Color::Rgb(0,0,128))))?;
add(&Outset::WH(1, 1, "555"))?;
add(&Outset::WH(1, 1, "777777"))?;
//add(&FillBg(Color::Rgb(0,0,128)))?;
Ok(())
}))
})).layout(area)?,
Some([46, 48, 5, 6]));
Ok(())
}
}