mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-09-18 13:26:42 +02:00
Compare commits
No commits in common. "a9f2fa2cdd5fac6ea0f7aee7e9c9d4acec8eac39" and "95ace837565c65292d86694cb395d9ba7fa834eb" have entirely different histories.
a9f2fa2cdd
...
95ace83756
17 changed files with 1096 additions and 1874 deletions
1865
Cargo.lock
generated
1865
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
11
Cargo.toml
11
Cargo.toml
|
|
@ -6,8 +6,7 @@ description = "UI metaframework."
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["lang", "sing", "midi", "draw", "play", "term", "text", "time", "rand", "okhsl", "eval", "exit"]
|
default = ["lang", "sing", "midi", "draw", "play", "term", "text", "time", "rand", "okhsl", "eval", "exit"]
|
||||||
prof = ["dep:profiling", "dep:tracing", "dep:tracing-flame", "dep:tracing-subscriber"]
|
bumpalo = ["dep:bumpalo"]
|
||||||
bump = ["dep:bumpalo"]
|
|
||||||
draw = []
|
draw = []
|
||||||
gui = ["draw", "dep:winit"]
|
gui = ["draw", "dep:winit"]
|
||||||
eval = []
|
eval = []
|
||||||
|
|
@ -26,7 +25,6 @@ term = ["draw", "dep:ratatui", "dep:crossterm"]
|
||||||
anyhow = { version = "1.0" }
|
anyhow = { version = "1.0" }
|
||||||
atomic_float = { version = "1" }
|
atomic_float = { version = "1" }
|
||||||
better-panic = { version = "0.3.0" }
|
better-panic = { version = "0.3.0" }
|
||||||
konst = { version = "0.3.16", features = [ "rust_1_83" ] }
|
|
||||||
|
|
||||||
bumpalo = { optional = true, version = "3.19.0" }
|
bumpalo = { optional = true, version = "3.19.0" }
|
||||||
crossterm = { optional = true, version = "0.29.0" }
|
crossterm = { optional = true, version = "0.29.0" }
|
||||||
|
|
@ -36,15 +34,10 @@ midly = { optional = true, version = "0.5" }
|
||||||
palette = { optional = true, version = "0.7.6", features = [ "random" ] }
|
palette = { optional = true, version = "0.7.6", features = [ "random" ] }
|
||||||
quanta = { optional = true, version = "0.12.3" }
|
quanta = { optional = true, version = "0.12.3" }
|
||||||
rand = { optional = true, version = "0.8.5" }
|
rand = { optional = true, version = "0.8.5" }
|
||||||
ratatui = { optional = true, version = "^0.30.2", features = [ "unstable-widget-ref", "underline-color" ] }
|
ratatui = { optional = true, version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] }
|
||||||
unicode-width = { optional = true, version = "0.2" }
|
unicode-width = { optional = true, version = "0.2" }
|
||||||
winit = { optional = true, version = "0.30.4", features = [ "x11" ]}
|
winit = { optional = true, version = "0.30.4", features = [ "x11" ]}
|
||||||
|
|
||||||
profiling = { version = "1.0.18", optional = true, features = ["profile-with-tracing"] }
|
|
||||||
tracing = { version = "0.1", optional = true, default-features = false, features = [ "std" ] }
|
|
||||||
tracing-subscriber = { version = "0.3", optional = true }
|
|
||||||
tracing-flame = { version = "0.2", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest = { version = "^1" }
|
proptest = { version = "^1" }
|
||||||
proptest-derive = { version = "^0.5.1" }
|
proptest-derive = { version = "^0.5.1" }
|
||||||
|
|
|
||||||
2
dizzle
2
dizzle
|
|
@ -1 +1 @@
|
||||||
Subproject commit 648be30918bef0a975bd225c0499911aaa88bc13
|
Subproject commit ab177b0d0d1ccdff0c69f915847be9a23a364663
|
||||||
|
|
@ -45,20 +45,16 @@ impl_keywords!(Tui, XYWH<u16>, State [
|
||||||
kw_tui_bg
|
kw_tui_bg
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl<'a> Interpret<'a, Tui, Option<XYWH<u16>>> for State {
|
impl Interpret<Tui, Option<XYWH<u16>>> for State {
|
||||||
fn interpret_word <L: Language<'a> + ?Sized> (&'a self, to: &mut Tui, lang: &'a L)
|
fn interpret_word (&self, to: &mut Tui, sym: &impl Language) -> Perhaps<XYWH<u16>> {
|
||||||
-> Drawn<'a, u16>
|
match sym.src()? {
|
||||||
{
|
|
||||||
match lang.src()? {
|
|
||||||
Some(":foo") => "foo".draw(to),
|
Some(":foo") => "foo".draw(to),
|
||||||
Some(":bar") => "bar".draw(to),
|
Some(":bar") => "bar".draw(to),
|
||||||
Some(":foobar") => "FOOBAR".draw(to),
|
Some(":foobar") => "FOOBAR".draw(to),
|
||||||
src => todo!("src: {src:?}")
|
src => todo!("src: {src:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn interpret_expr <L: Language<'a> + ?Sized> (&self, to: &mut Tui, src: &'a L)
|
fn interpret_expr (&self, to: &mut Tui, src: &impl Expression) -> Perhaps<XYWH<u16>> {
|
||||||
-> Drawn<'a, u16>
|
|
||||||
{
|
|
||||||
if let Some(area) = self.keyword(to, src)? {
|
if let Some(area) = self.keyword(to, src)? {
|
||||||
Ok(Some(area))
|
Ok(Some(area))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
133
src/layout.rs
133
src/layout.rs
|
|
@ -1,44 +1,44 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> Layout<'a, S> for T {}
|
impl<S: Screen, T: Draw<S>> Layout<S> for T {}
|
||||||
|
|
||||||
pub trait Layout<'a, S: Screen>: Draw<'a, S> + Sized {
|
pub trait Layout<S: Screen>: Draw<S> + Sized {
|
||||||
fn origin (self, azimuth: impl Into<Option<Azimuth>>) -> impl Draw<'a, S> {
|
fn origin (self, azimuth: impl Into<Option<Azimuth>>) -> impl Draw<S> {
|
||||||
Origin(azimuth.into(), self)
|
Origin(azimuth.into(), self)
|
||||||
}
|
}
|
||||||
fn origin_c (self) -> impl Draw<'a, S> {
|
fn origin_c (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::C), self)
|
Origin(Some(Azimuth::C), self)
|
||||||
}
|
}
|
||||||
fn origin_x (self) -> impl Draw<'a, S> {
|
fn origin_x (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::X), self)
|
Origin(Some(Azimuth::X), self)
|
||||||
}
|
}
|
||||||
fn origin_y (self) -> impl Draw<'a, S> {
|
fn origin_y (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::Y), self)
|
Origin(Some(Azimuth::Y), self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_n (self) -> impl Draw<'a, S> {
|
fn origin_n (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::N), self)
|
Origin(Some(Azimuth::N), self)
|
||||||
}
|
}
|
||||||
fn origin_s (self) -> impl Draw<'a, S> {
|
fn origin_s (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::S), self)
|
Origin(Some(Azimuth::S), self)
|
||||||
}
|
}
|
||||||
fn origin_e (self) -> impl Draw<'a, S> {
|
fn origin_e (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::E), self)
|
Origin(Some(Azimuth::E), self)
|
||||||
}
|
}
|
||||||
fn origin_w (self) -> impl Draw<'a, S> {
|
fn origin_w (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::W), self)
|
Origin(Some(Azimuth::W), self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_ne (self) -> impl Draw<'a, S> {
|
fn origin_ne (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::NE), self)
|
Origin(Some(Azimuth::NE), self)
|
||||||
}
|
}
|
||||||
fn origin_se (self) -> impl Draw<'a, S> {
|
fn origin_se (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::SE), self)
|
Origin(Some(Azimuth::SE), self)
|
||||||
}
|
}
|
||||||
fn origin_nw (self) -> impl Draw<'a, S> {
|
fn origin_nw (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::NW), self)
|
Origin(Some(Azimuth::NW), self)
|
||||||
}
|
}
|
||||||
fn origin_sw (self) -> impl Draw<'a, S> {
|
fn origin_sw (self) -> impl Draw<S> {
|
||||||
Origin(Some(Azimuth::SW), self)
|
Origin(Some(Azimuth::SW), self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ impl PartialEq for Sizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sizer {
|
impl Sizer {
|
||||||
pub const fn of <'a, T: Screen> (&self, of: impl Draw<'a, T>) -> impl Draw<'a, T> {
|
pub const fn of <T: Screen> (&self, of: impl Draw<T>) -> impl Draw<T> {
|
||||||
draw(move|to: &mut T|{
|
draw(move|to: &mut T|{
|
||||||
let area = of.draw(to)?;
|
let area = of.draw(to)?;
|
||||||
self.0.store(area.map(|a|a.w()).unwrap_or(T::Unit::zero()).into(), Relaxed);
|
self.0.store(area.map(|a|a.w()).unwrap_or(T::Unit::zero()).into(), Relaxed);
|
||||||
|
|
@ -99,13 +99,70 @@ impl Sizer {
|
||||||
}
|
}
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
/// Some layout operations exist in XY, X, and Y variants that take 3 or 2 arguments.
|
||||||
|
/// Their handling in [eval_view] is uniform and goes like this:
|
||||||
|
#[macro_export] macro_rules! eval_xy (
|
||||||
|
// Valueless variant:
|
||||||
|
// (fill/x ...)
|
||||||
|
// (fill/y ...)
|
||||||
|
// (fill/xy ...)
|
||||||
|
(
|
||||||
|
$name:expr => $expr:expr, $head:expr, $output:ident, $state:ident,
|
||||||
|
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg:expr,
|
||||||
|
) => {{
|
||||||
|
// frags.next(): 2nd slash-delimited fragment: /x, /y, /xy
|
||||||
|
let variant = $variant;
|
||||||
|
let thunk = draw(move|screen|$state.interpret(screen, &$arg));
|
||||||
|
match variant {
|
||||||
|
// X variant
|
||||||
|
Some("x") => thunk.$x().draw($output),
|
||||||
|
// Y variant
|
||||||
|
Some("y") => thunk.$y().draw($output),
|
||||||
|
// XY variant (can be omitted)
|
||||||
|
Some("xy") | None => thunk.$xy().draw($output),
|
||||||
|
// Other namespace members are invalid
|
||||||
|
frag => invalid_variant($name, frag, $expr, $head)
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Variadic variant:
|
||||||
|
// (push/x n ...)
|
||||||
|
// (push/y n ...)
|
||||||
|
// (push/xy n m ...)
|
||||||
|
(
|
||||||
|
$name:expr => $expr:expr, $head:expr, $output:ident, $state:ident,
|
||||||
|
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg0:expr, $arg1:expr, $arg2:expr,
|
||||||
|
) => {{
|
||||||
|
// frags.next(): 2nd slash-delimited fragment: /x, /y, /xy
|
||||||
|
let variant = $variant;
|
||||||
|
let thunk = draw(move|screen|$state.interpret(screen, &match variant {
|
||||||
|
Some("x") | Some("y") => $arg1,
|
||||||
|
Some("xy") | None => $arg2,
|
||||||
|
_ => panic!("{}: unsupported axis {variant:?}; try /x, /y, /xy", $name)
|
||||||
|
}));
|
||||||
|
match variant {
|
||||||
|
// X variant
|
||||||
|
Some("x") => thunk.$x($state.namespace($arg0?)?)
|
||||||
|
.draw($output),
|
||||||
|
// Y variant
|
||||||
|
Some("y") => thunk.$y($state.namespace($arg0?)?)
|
||||||
|
.draw($output),
|
||||||
|
// XY variant (can be omitted)
|
||||||
|
Some("xy") | None => thunk.$xy($state.namespace($arg0?)?, $state.namespace($arg1?)?)
|
||||||
|
.draw($output),
|
||||||
|
// Other namespace members are invalid
|
||||||
|
frag => invalid_variant($name, frag, $expr, $head)
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
);
|
||||||
|
|
||||||
#[macro_export] macro_rules! fn_kw_layout {
|
#[macro_export] macro_rules! fn_kw_layout {
|
||||||
($name:ident |$state:ident, $output: ident, $expr:ident| $body:block) => {
|
($name:ident |$state:ident, $output: ident, $expr:ident| $body:block) => {
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
#[cfg(all(feature = "draw", feature = "eval"))]
|
||||||
pub fn $name <'a, O: Screen, S> (
|
pub fn $name <O: Screen, S> (
|
||||||
$state: &'a S, $output: &mut O, $expr: &'a str
|
$state: &S, $output: &mut O, $expr: &str
|
||||||
) -> PerhapsRef<'a, XYWH<O::Unit>> where
|
) -> Perhaps<XYWH<O::Unit>> where
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
S: Interpret<O, Option<XYWH<O::Unit>>>
|
||||||
+ Namespace<bool>
|
+ Namespace<bool>
|
||||||
+ Namespace<O::Unit>
|
+ Namespace<O::Unit>
|
||||||
+ Namespace<Option<O::Unit>>
|
+ Namespace<Option<O::Unit>>
|
||||||
|
|
@ -116,10 +173,10 @@ impl Sizer {
|
||||||
#[macro_export] macro_rules! fn_kw_layout_tui {
|
#[macro_export] macro_rules! fn_kw_layout_tui {
|
||||||
($name:ident |$state:ident, $output: ident, $expr:ident| $body:block) => {
|
($name:ident |$state:ident, $output: ident, $expr:ident| $body:block) => {
|
||||||
#[cfg(all(feature = "draw", feature = "eval", feature = "term"))]
|
#[cfg(all(feature = "draw", feature = "eval", feature = "term"))]
|
||||||
pub fn $name <'a, S> (
|
pub fn $name <S> (
|
||||||
$state: &'a S, $output: &mut Tui, $expr: &'a str
|
$state: &S, $output: &mut Tui, $expr: &str
|
||||||
) -> PerhapsRef<'a, XYWH<u16>> where
|
) -> Perhaps<XYWH<u16>> where
|
||||||
S: Interpret<'a, Tui, Option<XYWH<u16>>>
|
S: Interpret<Tui, Option<XYWH<u16>>>
|
||||||
+ Namespace<bool>
|
+ Namespace<bool>
|
||||||
+ Namespace<u16>
|
+ Namespace<u16>
|
||||||
+ Namespace<Option<u16>>
|
+ Namespace<Option<u16>>
|
||||||
|
|
@ -134,9 +191,9 @@ impl Sizer {
|
||||||
$Struct:ident { $X:ident $Y:ident $XY:ident } $kw_name:ident $name:literal
|
$Struct:ident { $X:ident $Y:ident $XY:ident } $kw_name:ident $name:literal
|
||||||
|$self:ident, $to:ident| $body:block
|
|$self:ident, $to:ident| $body:block
|
||||||
) => {
|
) => {
|
||||||
impl<S: Screen, T: Draw<'a, S>> $Trait<S> for T {}
|
impl<S: Screen, T: Draw<S>> $Trait<S> for T {}
|
||||||
|
|
||||||
pub trait $Trait<S: Screen>: Draw<'a, S> + Sized {
|
pub trait $Trait<S: Screen>: Draw<S> + Sized {
|
||||||
fn $fn_x <N: Into<Option<S::Unit>> + Copy> (self, x: N)
|
fn $fn_x <N: Into<Option<S::Unit>> + Copy> (self, x: N)
|
||||||
-> $Struct<S, Self, N> { $Struct::$X(self, x) }
|
-> $Struct<S, Self, N> { $Struct::$X(self, x) }
|
||||||
fn $fn_y <N: Into<Option<S::Unit>> + Copy> (self, y: N)
|
fn $fn_y <N: Into<Option<S::Unit>> + Copy> (self, y: N)
|
||||||
|
|
@ -145,24 +202,28 @@ impl Sizer {
|
||||||
-> $Struct<S, Self, N> { $Struct::$XY(self, x, y) }
|
-> $Struct<S, Self, N> { $Struct::$XY(self, x, y) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum $Struct<S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
pub enum $Struct<S: Screen, I: Draw<S>, X: Into<Option<S::Unit>>> {
|
||||||
__(PhantomData<S>), $X(I, X), $Y(I, X), $XY(I, X, X),
|
__(PhantomData<S>), $X(I, X), $Y(I, X), $XY(I, X, X),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for $Struct<S, I, X> {
|
impl <S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for $Struct<S, I, X> {
|
||||||
fn draw (&$self, $to: &mut S) -> Perhaps<XYWH<S::Unit>> { $body }
|
fn draw (&$self, $to: &mut S) -> Perhaps<XYWH<S::Unit>> { $body }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_kw_layout!($kw_name |state, output, expr| {
|
fn_kw_layout!($kw_name |state, output, expr| {
|
||||||
#[cfg(feature = "prof")] profiling::scope!(stringify!(match $kw_name));
|
|
||||||
let head = expr.head()?;
|
let head = expr.head()?;
|
||||||
let mut frags = head.src()?.unwrap_or_default().split("/");
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||||
Ok(matches!(frags.next(), Some($name)).then(||{
|
Ok(matches!(frags.next(), Some($name)).then(||{
|
||||||
#[cfg(feature = "prof")] profiling::scope!(stringify!(inner $kw_name));
|
let args = expr.tail();
|
||||||
|
let arg0 = args.head();
|
||||||
|
let tail0 = args.tail();
|
||||||
|
let arg1 = tail0.head();
|
||||||
|
let tail1 = tail0.tail();
|
||||||
|
let arg2 = tail1.head();
|
||||||
eval_xy!(
|
eval_xy!(
|
||||||
$name => expr, head, output, state, frags.next(),
|
$name => expr, head, output, state, frags.next(),
|
||||||
$fn_xy, $fn_x, $fn_y,
|
$fn_xy, $fn_x, $fn_y,
|
||||||
expr.nth(1), expr.nth(2), expr.nth(3),
|
arg0, arg1, arg2,
|
||||||
)
|
)
|
||||||
}).transpose()?.flatten())
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
@ -175,9 +236,9 @@ impl Sizer {
|
||||||
$Struct:ident { $X:ident $Y:ident $XY:ident } $kw_name:ident $name:literal
|
$Struct:ident { $X:ident $Y:ident $XY:ident } $kw_name:ident $name:literal
|
||||||
|$self:ident, $to:ident| $body:block
|
|$self:ident, $to:ident| $body:block
|
||||||
) => {
|
) => {
|
||||||
impl<S: Screen, T: Draw<'a, S>> $Trait<S> for T {}
|
impl<S: Screen, T: Draw<S>> $Trait<S> for T {}
|
||||||
|
|
||||||
pub trait $Trait<S: Screen>: Draw<'a, S> + Sized {
|
pub trait $Trait<S: Screen>: Draw<S> + Sized {
|
||||||
fn $fn_x (self) -> $Struct<S, Self> { $Struct::$X(self) }
|
fn $fn_x (self) -> $Struct<S, Self> { $Struct::$X(self) }
|
||||||
fn $fn_y (self) -> $Struct<S, Self> { $Struct::$Y(self) }
|
fn $fn_y (self) -> $Struct<S, Self> { $Struct::$Y(self) }
|
||||||
fn $fn_xy (self) -> $Struct<S, Self> { $Struct::$XY(self) }
|
fn $fn_xy (self) -> $Struct<S, Self> { $Struct::$XY(self) }
|
||||||
|
|
@ -187,19 +248,19 @@ impl Sizer {
|
||||||
__(PhantomData<S>), $X(I), $Y(I), $XY(I),
|
__(PhantomData<S>), $X(I), $Y(I), $XY(I),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>> Draw<'a, S> for $Struct<S, I> {
|
impl <S: Screen, I: Draw<S>> Draw<S> for $Struct<S, I> {
|
||||||
fn draw (&$self, $to: &mut S) -> Perhaps<XYWH<S::Unit>> { $body }
|
fn draw (&$self, $to: &mut S) -> Perhaps<XYWH<S::Unit>> { $body }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_kw_layout!($kw_name |state, output, expr| {
|
fn_kw_layout!($kw_name |state, output, expr| {
|
||||||
#[cfg(feature = "prof")] profiling::scope!(stringify!(match $kw_name));
|
|
||||||
let head = expr.head()?;
|
let head = expr.head()?;
|
||||||
let mut frags = head.src()?.unwrap_or_default().split("/");
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||||
Ok(matches!(frags.next(), Some($name)).then(||{
|
Ok(matches!(frags.next(), Some($name)).then(||{
|
||||||
#[cfg(feature = "prof")] profiling::scope!(stringify!(inner $kw_name));
|
let args = expr.tail();
|
||||||
|
let arg0 = args.head();
|
||||||
eval_xy!(
|
eval_xy!(
|
||||||
$name => expr, head, output, state, frags.next(),
|
$name => expr, head, output, state, frags.next(),
|
||||||
$fn_xy, $fn_x, $fn_y, expr.nth(1),
|
$fn_xy, $fn_x, $fn_y, arg0,
|
||||||
)
|
)
|
||||||
}).transpose()?.flatten())
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,17 @@ use crate::*;
|
||||||
/// let _ = area(XYWH(1, 2, 3, 4), "southeast");
|
/// let _ = area(XYWH(1, 2, 3, 4), "southeast");
|
||||||
/// let _ = area(Some(XYWH(1, 2, 3, 4)), "southeast");
|
/// let _ = area(Some(XYWH(1, 2, 3, 4)), "southeast");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn area <'a, S: Screen, T: Draw<'a, S>, U: Into<Option<XYWH<S::Unit>>>> (
|
pub fn area <S: Screen, T: Draw<S>, U: Into<Option<XYWH<S::Unit>>>> (
|
||||||
origin: U, it: T
|
origin: U, it: T
|
||||||
) -> Area<S, T> {
|
) -> Area<S, T> {
|
||||||
Area(origin.into(), it)
|
Area(origin.into(), it)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Area<S: Screen, T>(
|
pub struct Area<S: Screen, T: Draw<S>>(
|
||||||
pub Option<XYWH<S::Unit>>,
|
pub Option<XYWH<S::Unit>>,
|
||||||
pub T,
|
pub T
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> Draw<'a, S> for Area<S, T> {
|
impl_draw!(<S: Screen, T: Draw<S>,>|self: Area<S, T>, to: S|{
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
to.draw(self.0, &self.1)
|
||||||
to.draw(self.0, &self.1)
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,296 +1,8 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub enum Full<'a, S: Screen, I: Draw<'a, S>> {
|
def_layout_modifier_flat!(
|
||||||
__(PhantomData<&'a S>), W(I), H(I), WH(I),
|
LayoutFull (full_w full_h full_wh),
|
||||||
}
|
Full { W H WH } kw_full "full" |self, to| {
|
||||||
|
|
||||||
pub enum Exact<'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
|
||||||
__(PhantomData<&'a S>), W(I, X), H(I, X), WH(I, X, X),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Push<'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
|
||||||
__(PhantomData<&'a S>), X(I, X), Y(I, X), XY(I, X, X),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Pull<'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
|
||||||
__(PhantomData<&'a S>), X(I, X), Y(I, X), XY(I, X, X),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Min<'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
|
||||||
__(PhantomData<&'a S>), W(I, X), H(I, X), WH(I, X, X),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Max<'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
|
||||||
__(PhantomData<&'a S>), W(I, X), H(I, X), WH(I, X, X),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Pad<'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>>> {
|
|
||||||
__(PhantomData<&'a S>), X(I, X), Y(I, X), XY(I, X, X),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// # fn test_layout_full () -> Usually<()> {
|
|
||||||
/// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".full_w())?, Some(XYWH(1u16, 1, 80, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".full_h())?, Some(XYWH(1u16, 1, 1, 25)));
|
|
||||||
/// assert_eq!(check_layout("1".full_wh())?, Some(XYWH(1u16, 1, 80, 25)));
|
|
||||||
/// # Ok(()) }}
|
|
||||||
/// ```
|
|
||||||
pub trait LayoutFull<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn full_w (self) -> Full<'a, S, Self> { Full::W(self) }
|
|
||||||
fn full_h (self) -> Full<'a, S, Self> { Full::H(self) }
|
|
||||||
fn full_wh (self) -> Full<'a, S, Self> { Full::WH(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// # fn test_layout_exact () -> Usually<()> {
|
|
||||||
/// assert_eq!(check_layout("FOOBAR\nKILROY")?, Some(XYWH(1, 1, 6, 2)));
|
|
||||||
/// assert_eq!(check_layout("FOOBAR\nKILROY".exact_w(3))?, Some(XYWH(1, 1, 3, 2)));
|
|
||||||
/// assert_eq!(check_layout("FOOBAR\nKILROY".exact_h(1))?, Some(XYWH(1, 1, 6, 1)));
|
|
||||||
/// assert_eq!(check_layout("FOOBAR\nKILROY".exact_wh(2, 1))?, Some(XYWH(1, 1, 2, 1)));
|
|
||||||
/// # Ok(()) }}
|
|
||||||
/// ```
|
|
||||||
pub trait LayoutExact<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn exact_w <X: Into<Option<S::Unit>> + Copy> (self, w: X)
|
|
||||||
-> Exact<'a, S, Self, X> { Exact::W(self, w) }
|
|
||||||
fn exact_h <X: Into<Option<S::Unit>> + Copy> (self, h: X)
|
|
||||||
-> Exact<'a, S, Self, X> { Exact::H(self, h) }
|
|
||||||
fn exact_wh <X: Into<Option<S::Unit>> + Copy> (self, w: X, h: X)
|
|
||||||
-> Exact<'a, S, Self, X> { Exact::WH(self, w, h) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// # fn test_layout_min () -> Usually<()> {
|
|
||||||
/// assert_eq!(check_layout("1".min_w(5))?, Some(XYWH(1u16, 1, 5, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".min_h(5))?, Some(XYWH(1u16, 1, 1, 5)));
|
|
||||||
/// assert_eq!(check_layout("1".min_wh(5, 5))?, Some(XYWH(1u16, 1, 5, 5)));
|
|
||||||
/// assert_eq!(check_layout("123456".min_w(5))?, Some(XYWH(1u16, 1, 6, 1)));
|
|
||||||
/// # Ok(()) }}
|
|
||||||
/// ```
|
|
||||||
pub trait LayoutMin<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn min_w <X: Into<Option<S::Unit>> + Copy> (self, w: X)
|
|
||||||
-> Min<'a, S, Self, X> { Min::W(self, w) }
|
|
||||||
fn min_h <X: Into<Option<S::Unit>> + Copy> (self, h: X)
|
|
||||||
-> Min<'a, S, Self, X> { Min::H(self, h) }
|
|
||||||
fn min_wh <X: Into<Option<S::Unit>> + Copy> (self, w: X, h: X)
|
|
||||||
-> Min<'a, S, Self, X> { Min::WH(self, w, h) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayoutMax<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn max_w <X: Into<Option<S::Unit>> + Copy> (self, w: X)
|
|
||||||
-> Max<'a, S, Self, X> { Max::W(self, w) }
|
|
||||||
fn max_h <X: Into<Option<S::Unit>> + Copy> (self, h: X)
|
|
||||||
-> Max<'a, S, Self, X> { Max::H(self, h) }
|
|
||||||
fn max_wh <X: Into<Option<S::Unit>> + Copy> (self, w: X, h: X)
|
|
||||||
-> Max<'a, S, Self, X> { Max::WH(self, w, h) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayoutPad<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn pad_w <X: Into<Option<S::Unit>> + Copy> (self, w: X)
|
|
||||||
-> Pad<'a, S, Self, X> { Pad::X(self, w) }
|
|
||||||
fn pad_h <X: Into<Option<S::Unit>> + Copy> (self, h: X)
|
|
||||||
-> Pad<'a, S, Self, X> { Pad::Y(self, h) }
|
|
||||||
fn pad_wh <X: Into<Option<S::Unit>> + Copy> (self, w: X, h: X)
|
|
||||||
-> Pad<'a, S, Self, X> { Pad::XY(self, w, h) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// # fn test_layout_pull () -> Usually<()> {
|
|
||||||
/// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".push_x(1))?, Some(XYWH(2u16, 1, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".push_y(1))?, Some(XYWH(1u16, 2, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".push_xy(1, 1))?, Some(XYWH(2u16, 2, 1, 1)));
|
|
||||||
/// # Ok(()) }
|
|
||||||
/// ```
|
|
||||||
pub trait LayoutPush<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn push_x <X: Into<Option<S::Unit>> + Copy> (self, w: X)
|
|
||||||
-> Push<'a, S, Self, X> { Push::X(self, w) }
|
|
||||||
fn push_y <X: Into<Option<S::Unit>> + Copy> (self, h: X)
|
|
||||||
-> Push<'a, S, Self, X> { Push::Y(self, h) }
|
|
||||||
fn push_xy <X: Into<Option<S::Unit>> + Copy> (self, w: X, h: X)
|
|
||||||
-> Push<'a, S, Self, X> { Push::XY(self, w, h) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// # fn test_layout_push () -> Usually<()> {
|
|
||||||
/// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".pull_x(1))?, Some(XYWH(0u16, 1, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".pull_y(1))?, Some(XYWH(1u16, 0, 1, 1)));
|
|
||||||
/// assert_eq!(check_layout("1".pull_xy(1, 1))?, Some(XYWH(0u16, 0, 1, 1)));
|
|
||||||
/// # Ok(()) }
|
|
||||||
/// ```
|
|
||||||
pub trait LayoutPull<'a, S: Screen>: Draw<'a, S> + Sized {
|
|
||||||
fn pull_x <X: Into<Option<S::Unit>> + Copy> (self, w: X)
|
|
||||||
-> Pull<'a, S, Self, X> { Pull::X(self, w) }
|
|
||||||
fn pull_y <X: Into<Option<S::Unit>> + Copy> (self, h: X)
|
|
||||||
-> Pull<'a, S, Self, X> { Pull::Y(self, h) }
|
|
||||||
fn pull_xy <X: Into<Option<S::Unit>> + Copy> (self, w: X, h: X)
|
|
||||||
-> Pull<'a, S, Self, X> { Pull::XY(self, w, h) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_full <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.nth(1)?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("full/x") | Some("full/w") => Full::W(thunk).draw(to)?,
|
|
||||||
Some("full/y") | Some("full/h") => Full::H(thunk).draw(to)?,
|
|
||||||
Some("full/xy") | Some("full/wh") => Full::WH(thunk).draw(to)?,
|
|
||||||
frag => return Err(format!("invalid variant: {frag:?}").into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_exact <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("exact/w") => thunk.exact_w(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("exact/h") => thunk.exact_h(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("exact/wh") => thunk.exact_wh(
|
|
||||||
state.namespace(expr.nth(1)?)?,
|
|
||||||
state.namespace(expr.nth(2)?)?,
|
|
||||||
).draw(to)?,
|
|
||||||
_ => return Err(format!("invalid variant: {:?}", expr.head()?).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_min <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("min/w") => thunk.min_w(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("min/h") => thunk.min_h(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("min/wh") => thunk.min_wh(
|
|
||||||
state.namespace(expr.nth(1)?)?,
|
|
||||||
state.namespace(expr.nth(2)?)?,
|
|
||||||
).draw(to)?,
|
|
||||||
_ => return Err(format!("invalid variant: {:?}", expr.head()?).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_max <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("max/w") => thunk.max_w(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("max/h") => thunk.max_h(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("max/wh") => thunk.max_wh(
|
|
||||||
state.namespace(expr.nth(1)?)?,
|
|
||||||
state.namespace(expr.nth(2)?)?,
|
|
||||||
).draw(to)?,
|
|
||||||
_ => return Err(format!("invalid variant: {:?}", expr.head()?).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_push <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("push/w") => thunk.push_x(state.namespace(expr.nth(1)?)?).draw(to)?,
|
|
||||||
Some("push/h") => thunk.push_y(state.namespace(expr.nth(1)?)?).draw(to)?,
|
|
||||||
Some("push/wh") => thunk.push_xy(state.namespace(expr.nth(1)?)?, state.namespace(expr.nth(2)?)?,).draw(to)?,
|
|
||||||
_ => return Err(format!("invalid variant: {:?}", expr.head()?).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_pull <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("pull/w") => thunk.pull_x(state.namespace(expr.nth(1)?)?).draw(to)?,
|
|
||||||
Some("pull/h") => thunk.pull_y(state.namespace(expr.nth(1)?)?).draw(to)?,
|
|
||||||
Some("pull/wh") => thunk.pull_xy(state.namespace(expr.nth(1)?)?, state.namespace(expr.nth(2)?)?,).draw(to)?,
|
|
||||||
_ => return Err(format!("invalid variant: {:?}", expr.head()?).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
|
||||||
pub fn kw_pad <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
|
||||||
-> PerhapsRef<'a, XYWH<O::Unit>>
|
|
||||||
where
|
|
||||||
O: Screen + 'a,
|
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
|
||||||
+ Namespace<bool>
|
|
||||||
+ Namespace<O::Unit>
|
|
||||||
+ Namespace<Option<O::Unit>>
|
|
||||||
{
|
|
||||||
let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(match expr.head()? {
|
|
||||||
Some("pad/w") => thunk.pad_w(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("pad/h") => thunk.pad_h(
|
|
||||||
state.namespace(expr.nth(1)?)?
|
|
||||||
).draw(to)?,
|
|
||||||
Some("pad/wh") => thunk.pad_wh(
|
|
||||||
state.namespace(expr.nth(1)?)?,
|
|
||||||
state.namespace(expr.nth(2)?)?,
|
|
||||||
).draw(to)?,
|
|
||||||
_ => return Err(format!("invalid variant: {:?}", expr.head()?).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>> Draw<'a, S> for Full<'a, S, I> {
|
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
|
||||||
let XYWH(x0, y0, w0, h0) = to.area();
|
let XYWH(x0, y0, w0, h0) = to.area();
|
||||||
let item = match self {
|
let item = match self {
|
||||||
Self::W(i) => i, Self::H(i) => i, Self::WH(i) => i, _ => unreachable!()
|
Self::W(i) => i, Self::H(i) => i, Self::WH(i) => i, _ => unreachable!()
|
||||||
|
|
@ -305,10 +17,19 @@ impl <'a, S: Screen, I: Draw<'a, S>> Draw<'a, S> for Full<'a, S, I> {
|
||||||
x1.unwrap_or(x2), y1.unwrap_or(y2), w1.unwrap_or(w2), h1.unwrap_or(h2),
|
x1.unwrap_or(x2), y1.unwrap_or(y2), w1.unwrap_or(w2), h1.unwrap_or(h2),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_layout_full () -> Usually<()> {
|
||||||
|
assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".full_w())?, Some(XYWH(1u16, 1, 80, 1)));
|
||||||
|
assert_eq!(check_layout("1".full_h())?, Some(XYWH(1u16, 1, 1, 25)));
|
||||||
|
assert_eq!(check_layout("1".full_wh())?, Some(XYWH(1u16, 1, 80, 25)));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for Exact<'a, S, I, X> {
|
def_layout_modifier!(
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
LayoutExact (exact_w exact_h exact_wh),
|
||||||
|
Exact { W H WH } kw_exact "exact" |self, to| {
|
||||||
let XYWH(x0, y0, w0, h0) = to.area();
|
let XYWH(x0, y0, w0, h0) = to.area();
|
||||||
let (item, w1, h1) = match self {
|
let (item, w1, h1) = match self {
|
||||||
Self::W(item, w1) => (item, (*w1).into(), None),
|
Self::W(item, w1) => (item, (*w1).into(), None),
|
||||||
|
|
@ -327,10 +48,19 @@ impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_layout_exact () -> Usually<()> {
|
||||||
|
assert_eq!(check_layout("FOOBAR\nKILROY")?, Some(XYWH(1, 1, 6, 2)));
|
||||||
|
assert_eq!(check_layout("FOOBAR\nKILROY".exact_w(3))?, Some(XYWH(1, 1, 3, 2)));
|
||||||
|
assert_eq!(check_layout("FOOBAR\nKILROY".exact_h(1))?, Some(XYWH(1, 1, 6, 1)));
|
||||||
|
assert_eq!(check_layout("FOOBAR\nKILROY".exact_wh(2, 1))?, Some(XYWH(1, 1, 2, 1)));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for Min<'a, S, I, X> {
|
def_layout_modifier!(
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
LayoutMin (min_w min_h min_wh),
|
||||||
|
Min { W H WH } kw_min "min" |self, to| {
|
||||||
let XYWH(x0, y0, w0, h0) = to.area();
|
let XYWH(x0, y0, w0, h0) = to.area();
|
||||||
let (item, w1, h1) = match self {
|
let (item, w1, h1) = match self {
|
||||||
Self::W(item, w1) => (item, (*w1).into(), None),
|
Self::W(item, w1) => (item, (*w1).into(), None),
|
||||||
|
|
@ -348,10 +78,19 @@ impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S
|
||||||
h1.map(|h1|h1.max(h2)).unwrap_or(h2)
|
h1.map(|h1|h1.max(h2)).unwrap_or(h2)
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_layout_min () -> Usually<()> {
|
||||||
|
assert_eq!(check_layout("1".min_w(5))?, Some(XYWH(1u16, 1, 5, 1)));
|
||||||
|
assert_eq!(check_layout("1".min_h(5))?, Some(XYWH(1u16, 1, 1, 5)));
|
||||||
|
assert_eq!(check_layout("1".min_wh(5, 5))?, Some(XYWH(1u16, 1, 5, 5)));
|
||||||
|
assert_eq!(check_layout("123456".min_w(5))?, Some(XYWH(1u16, 1, 6, 1)));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for Max<'a, S, I, X> {
|
def_layout_modifier!(
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
LayoutMax (max_w max_h max_wh),
|
||||||
|
Max { W H WH } kw_max "max" |self, to| {
|
||||||
let XYWH(x, y, w0, h0) = to.area();
|
let XYWH(x, y, w0, h0) = to.area();
|
||||||
let (item, w, h) = match self {
|
let (item, w, h) = match self {
|
||||||
Self::W(item, w) => (item, (*w).into().unwrap_or(w0), h0),
|
Self::W(item, w) => (item, (*w).into().unwrap_or(w0), h0),
|
||||||
|
|
@ -361,10 +100,31 @@ impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S
|
||||||
};
|
};
|
||||||
to.draw(XYWH(x, y, if w0 > w { w } else { w0 }, if h0 > h { h } else { h0 }), item)
|
to.draw(XYWH(x, y, if w0 > w { w } else { w0 }, if h0 > h { h } else { h0 }), item)
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for Push<'a, S, I, X> {
|
def_layout_modifier!(
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
LayoutPad (pad_w pad_h pad_wh),
|
||||||
|
Pad { X Y XY } kw_pad "pad" |self, to| {
|
||||||
|
let XYWH(x, y, w0, h0) = to.area();
|
||||||
|
let (item, w, h) = match self {
|
||||||
|
Self::X(item, w) => (item, (*w).into().unwrap_or_default(), Default::default()),
|
||||||
|
Self::Y(item, h) => (item, Default::default(), (*h).into().unwrap_or_default()),
|
||||||
|
Self::XY(item, w, h) => (item, (*w).into().unwrap_or_default(),
|
||||||
|
(*h).into().unwrap_or_default()),
|
||||||
|
_ => return Ok(None)
|
||||||
|
};
|
||||||
|
to.draw(XYWH(
|
||||||
|
x.plus(w),
|
||||||
|
y.plus(h),
|
||||||
|
w0.minus(w).minus(w),
|
||||||
|
h0.minus(h).minus(h),
|
||||||
|
), item)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
def_layout_modifier!(
|
||||||
|
LayoutPush (push_x push_y push_xy),
|
||||||
|
Push { X Y XY } kw_push "push" |self, to| {
|
||||||
match self {
|
match self {
|
||||||
Self::__(_) => unreachable!(),
|
Self::__(_) => unreachable!(),
|
||||||
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
||||||
|
|
@ -379,10 +139,19 @@ impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S
|
||||||
_ => Ok(None)
|
_ => Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_layout_push () -> Usually<()> {
|
||||||
|
assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".push_x(1))?, Some(XYWH(2u16, 1, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".push_y(1))?, Some(XYWH(1u16, 2, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".push_xy(1, 1))?, Some(XYWH(2u16, 2, 1, 1)));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for Pull<'a, S, I, X> {
|
def_layout_modifier!(
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
LayoutPull (pull_x pull_y pull_xy),
|
||||||
|
Pull { X Y XY } kw_pull "pull" |self, to| {
|
||||||
match self {
|
match self {
|
||||||
Self::__(_) => unreachable!(),
|
Self::__(_) => unreachable!(),
|
||||||
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
||||||
|
|
@ -403,41 +172,16 @@ impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S
|
||||||
_ => Ok(None)
|
_ => Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_layout_pull () -> Usually<()> {
|
||||||
|
assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".pull_x(1))?, Some(XYWH(0u16, 1, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".pull_y(1))?, Some(XYWH(1u16, 0, 1, 1)));
|
||||||
|
assert_eq!(check_layout("1".pull_xy(1, 1))?, Some(XYWH(0u16, 0, 1, 1)));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<'a, S>, X: Into<Option<S::Unit>> + Copy> Draw<'a, S> for Pad<'a, S, I, X> {
|
#[cfg(test)] fn check_layout (t: impl Draw<Tui>) -> Perhaps<XYWH<u16>> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
|
||||||
let XYWH(x, y, w0, h0) = to.area();
|
|
||||||
let (item, w, h) = match self {
|
|
||||||
Self::X(item, w) => (item, (*w).into().unwrap_or_default(), Default::default()),
|
|
||||||
Self::Y(item, h) => (item, Default::default(), (*h).into().unwrap_or_default()),
|
|
||||||
Self::XY(item, w, h) => (item, (*w).into().unwrap_or_default(),
|
|
||||||
(*h).into().unwrap_or_default()),
|
|
||||||
_ => return Ok(None)
|
|
||||||
};
|
|
||||||
to.draw(XYWH(
|
|
||||||
x.plus(w),
|
|
||||||
y.plus(h),
|
|
||||||
w0.minus(w).minus(w),
|
|
||||||
h0.minus(h).minus(h),
|
|
||||||
), item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutFull<'a, S> for T {}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutExact<'a, S> for T {}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutMin<'a, S> for T {}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutMax<'a, S> for T {}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutPush<'a, S> for T {}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutPull<'a, S> for T {}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> LayoutPad<'a, S> for T {}
|
|
||||||
|
|
||||||
#[cfg(test)] fn check_layout <'a> (t: impl Draw<'a, Tui>) -> Drawn<'a, u16> {
|
|
||||||
Tui::Layout(XYWH(1u16, 1, 80, 25)).size(None, t)
|
Tui::Layout(XYWH(1u16, 1, 80, 25)).size(None, t)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,9 @@ pub struct Origin<T>(
|
||||||
pub(crate) T
|
pub(crate) T
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> Draw<'a, S> for Origin<T> {
|
impl_draw!(<S: Screen, T: Draw<S>,>|self: Origin<T>, _to: S|{
|
||||||
fn draw (&self, _to: &mut S) -> Drawn<'a, S::Unit> {
|
todo!()
|
||||||
todo!()
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Something that has `[0, 0]` at a particular point.
|
/// Something that has `[0, 0]` at a particular point.
|
||||||
pub trait HasOrigin {
|
pub trait HasOrigin {
|
||||||
|
|
@ -35,47 +33,25 @@ impl<T: AsRef<Azimuth>> HasOrigin for T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "draw", feature = "eval"))]
|
fn_kw_layout!(kw_align |state, output, expr| {
|
||||||
pub fn kw_align <'a, O, S> (state: &'a S, to: &mut O, expr: &'a str)
|
let head = expr.head();
|
||||||
-> Drawn<'a, O::Unit>
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||||
where
|
Ok(matches!(frags.next(), Some("align")).then(||{
|
||||||
O: Screen,
|
draw(move|output: &mut O|{state.interpret(output, &expr.tail().head())}).align(
|
||||||
S: Interpret<'a, O, Option<XYWH<O::Unit>>>
|
eval_enum!("align", output, state,
|
||||||
+ Namespace<bool>
|
expr.head().src()?.unwrap_or_default().split("/").skip(1).next(),
|
||||||
+ Namespace<O::Unit>
|
Azimuth {
|
||||||
+ Namespace<Option<O::Unit>>
|
"c" => C, "x" => X, "y" => Y,
|
||||||
{
|
"n" => N, "s" => S, "e" => E, "w" => W,
|
||||||
let thunk = draw(move|screen|ok_flat(expr.nth(1)?.map(|x: &'a str|state.interpret(screen, x))));
|
"nw" => NW, "sw" => SW, "ne" => NE, "se" => SE,
|
||||||
Ok(match expr.head()? {
|
})
|
||||||
Some("align/c") => Align(Some(Azimuth::C), thunk).draw(to)?,
|
).draw(output)
|
||||||
Some("align/x") => Align(Some(Azimuth::X), thunk).draw(to)?,
|
}).transpose()?.flatten())
|
||||||
Some("align/y") => Align(Some(Azimuth::Y), thunk).draw(to)?,
|
});
|
||||||
Some("align/n") => Align(Some(Azimuth::N), thunk).draw(to)?,
|
|
||||||
Some("align/s") => Align(Some(Azimuth::S), thunk).draw(to)?,
|
|
||||||
Some("align/e") => Align(Some(Azimuth::E), thunk).draw(to)?,
|
|
||||||
Some("align/w") => Align(Some(Azimuth::W), thunk).draw(to)?,
|
|
||||||
Some("align/nw") => Align(Some(Azimuth::NW), thunk).draw(to)?,
|
|
||||||
Some("align/sw") => Align(Some(Azimuth::SW), thunk).draw(to)?,
|
|
||||||
Some("align/ne") => Align(Some(Azimuth::NE), thunk).draw(to)?,
|
|
||||||
Some("align/se") => Align(Some(Azimuth::SE), thunk).draw(to)?,
|
|
||||||
frag => return Err(format!("invalid variant: {frag:?}").into())
|
|
||||||
})
|
|
||||||
//Ok(matches!(expr.head().src()?.unwrap_or_default().split("/").next(), Some("align")).then(||{
|
|
||||||
//draw(move|output: &mut O|{state.interpret(output, &expr.nth(1))}).align(
|
|
||||||
//eval_enum!("align", output, state,
|
|
||||||
//expr.head().src()?.unwrap_or_default().split("/").skip(1).next(),
|
|
||||||
//Azimuth {
|
|
||||||
//"c" => C, "x" => X, "y" => Y,
|
|
||||||
//"n" => N, "s" => S, "e" => E, "w" => W,
|
|
||||||
//"nw" => NW, "sw" => SW, "ne" => NE, "se" => SE,
|
|
||||||
//})
|
|
||||||
//).draw(output)
|
|
||||||
//}).transpose()?.flatten())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> CanAlign<'a, S> for T {}
|
impl<S: Screen, T: Draw<S>> CanAlign<S> for T {}
|
||||||
|
|
||||||
pub trait CanAlign<'a, S: Screen>: Draw<'a, S> + Sized {
|
pub trait CanAlign<S: Screen>: Draw<S> + Sized {
|
||||||
fn align (self, azimuth: impl Into<Option<Azimuth>>) -> Align<Self> {
|
fn align (self, azimuth: impl Into<Option<Azimuth>>) -> Align<Self> {
|
||||||
Align(azimuth.into(), self)
|
Align(azimuth.into(), self)
|
||||||
}
|
}
|
||||||
|
|
@ -119,8 +95,8 @@ pub struct Align<T>(
|
||||||
pub(crate) T,
|
pub(crate) T,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<'a, S>> Draw<'a, S> for Align<T> {
|
impl<S: Screen, T: Draw<S>> Draw<S> for Align<T> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
fn draw (&self, to: &mut S) -> Perhaps<XYWH<S::Unit>> {
|
||||||
let Self(azimuth, item) = self;
|
let Self(azimuth, item) = self;
|
||||||
let area0 = to.area();
|
let area0 = to.area();
|
||||||
let size = to.size(area0, item)?;
|
let size = to.size(area0, item)?;
|
||||||
|
|
@ -157,17 +133,25 @@ fn align <S: Screen> (
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_kw_layout!(kw_split |state, output, expr| {
|
fn_kw_layout!(kw_split |state, output, expr| {
|
||||||
let thunk_a = draw(move|screen|ok_flat(expr.nth(1)?.map(|x: &'a str|state.interpret(screen, x))));
|
let head = expr.head();
|
||||||
let thunk_b = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x))));
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||||
Ok(match expr.head()? {
|
Ok(matches!(frags.next(), Some("bsp")).then(||{
|
||||||
Some("bsp/n") => Split::North.stack(thunk_a, thunk_b).draw(output)?,
|
eval_enum!("bsp", output, state, frags.next(), Split {
|
||||||
Some("bsp/s") => Split::South.stack(thunk_a, thunk_b).draw(output)?,
|
"n" => North,
|
||||||
Some("bsp/e") => Split::East.stack(thunk_a, thunk_b).draw(output)?,
|
"s" => South,
|
||||||
Some("bsp/w") => Split::West.stack(thunk_a, thunk_b).draw(output)?,
|
"e" => East,
|
||||||
Some("bsp/a") => Split::Above.stack(thunk_a, thunk_b).draw(output)?,
|
"w" => West,
|
||||||
Some("bsp/b") => Split::Below.stack(thunk_a, thunk_b).draw(output)?,
|
"a" => Above,
|
||||||
frag => return Err(format!("invalid variant: {frag:?}").into())
|
"b" => Below
|
||||||
})
|
}).stack(
|
||||||
|
draw(move|output: &mut O|{
|
||||||
|
state.interpret(output, &expr.tail().head()?)
|
||||||
|
}),
|
||||||
|
draw(move|output: &mut O|{
|
||||||
|
state.interpret(output, &expr.tail().tail().head()?)
|
||||||
|
}),
|
||||||
|
).draw(output)
|
||||||
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Split along an axis. Direction determines order.
|
/// Split along an axis. Direction determines order.
|
||||||
|
|
@ -181,28 +165,16 @@ fn_kw_layout!(kw_split |state, output, expr| {
|
||||||
#[default] Below
|
#[default] Below
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pair<A, B>(Split, A, B);
|
pub struct Pair<S: Screen, A: Draw<S>, B: Draw<S>>(Split, A, B, PhantomData<S>);
|
||||||
|
|
||||||
/// ```
|
pub fn split <S: Screen, A: Draw<S>, B: Draw<S>> (
|
||||||
/// # fn test_split_stack () -> Usually<()> {
|
|
||||||
/// use Split::*;
|
|
||||||
/// fn size_of <A: Draw<Tui>, B: Draw<Tui>> (stack: &Pair<Tui, A, B>) -> Drawn<'a, S::Unit> {
|
|
||||||
/// Tui::Layout(XYWH(0, 0, 80, 25)).size(None, stack)
|
|
||||||
/// }
|
|
||||||
/// assert_eq!(size_of(&split(East, "foo", "bar"))?, Some(XYWH(0, 0, 6, 1)));
|
|
||||||
/// assert_eq!(size_of(&split(South, "foo", "bar"))?, Some(XYWH(0, 0, 3, 2)));
|
|
||||||
/// assert_eq!(size_of(&split(South, split(East, "foo", "bar"), "baz"))?, Some(XYWH(0, 0, 6, 2)));
|
|
||||||
/// assert_eq!(size_of(&split(East, split(South, "foo", "bar"), "baz"))?, Some(XYWH(0, 0, 6, 2)));
|
|
||||||
/// # return Ok(()); }
|
|
||||||
/// ```
|
|
||||||
pub fn split <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (
|
|
||||||
split: Split, a: A, b: B
|
split: Split, a: A, b: B
|
||||||
) -> Pair<A, B> {
|
) -> Pair<S, A, B> {
|
||||||
Pair(split, a, b)
|
Pair(split, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> Draw<'a, S> for Pair<A, B> {
|
impl<S: Screen, A: Draw<S>, B: Draw<S>> Draw<S> for Pair<S, A, B> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
let Self(split, a, b, ..) = self;
|
let Self(split, a, b, ..) = self;
|
||||||
let (area_a, area_b) = stack_areas(split, to, a, b)?;
|
let (area_a, area_b) = stack_areas(split, to, a, b)?;
|
||||||
let (drawn_a, drawn_b) = draw_stacks(split, to, a, area_a, None, b, area_b, None)?;
|
let (drawn_a, drawn_b) = draw_stacks(split, to, a, area_a, None, b, area_b, None)?;
|
||||||
|
|
@ -210,16 +182,16 @@ impl<'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> Draw<'a, S> for Pair<A, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_stacks <'a, S: Screen> (
|
fn draw_stacks <S: Screen> (
|
||||||
split: &Split,
|
split: &Split,
|
||||||
to: &mut S,
|
to: &mut S,
|
||||||
a: impl Draw<'a, S>,
|
a: impl Draw<S>,
|
||||||
area_a: impl Into<Option<XYWH<S::Unit>>>,
|
area_a: impl Into<Option<XYWH<S::Unit>>>,
|
||||||
origin_a: impl Into<Option<Azimuth>>,
|
origin_a: impl Into<Option<Azimuth>>,
|
||||||
b: impl Draw<'a, S>,
|
b: impl Draw<S>,
|
||||||
area_b: impl Into<Option<XYWH<S::Unit>>>,
|
area_b: impl Into<Option<XYWH<S::Unit>>>,
|
||||||
origin_b: impl Into<Option<Azimuth>>,
|
origin_b: impl Into<Option<Azimuth>>,
|
||||||
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
) -> Usually<(Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
||||||
let draw_a = |to: &mut S|Ok::<_, Box<dyn Error>>(match origin_a.into() {
|
let draw_a = |to: &mut S|Ok::<_, Box<dyn Error>>(match origin_a.into() {
|
||||||
Some(origin_a) => to.draw(area_a.into(), a.align(origin_a))?,
|
Some(origin_a) => to.draw(area_a.into(), a.align(origin_a))?,
|
||||||
None => to.draw(area_a.into(), a)?
|
None => to.draw(area_a.into(), a)?
|
||||||
|
|
@ -237,25 +209,12 @@ fn draw_stacks <'a, S: Screen> (
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
pub fn stack_areas <S: Screen> (
|
||||||
/// # fn test_stack_areas () -> Usually<()> {
|
|
||||||
/// let area = XYWH(0u16, 0, 80, 25);
|
|
||||||
/// assert_eq!(stack_areas(&Split::East, &mut Tui::Layout(area), &"foo", &"bar")?, (
|
|
||||||
/// Some(XYWH(0u16, 0, 3, 1)),
|
|
||||||
/// Some(XYWH(3u16, 0, 3, 1)),
|
|
||||||
/// ));
|
|
||||||
/// assert_eq!(stack_areas(&Split::South, &mut Tui::Layout(area), &"foo", &"bar")?, (
|
|
||||||
/// Some(XYWH(0u16, 0, 3, 1)),
|
|
||||||
/// Some(XYWH(0u16, 1, 3, 1)),
|
|
||||||
/// ));
|
|
||||||
/// # Ok(()) }
|
|
||||||
/// ```
|
|
||||||
pub fn stack_areas <'a, S: Screen> (
|
|
||||||
split: &Split,
|
split: &Split,
|
||||||
to: &mut S,
|
to: &mut S,
|
||||||
a: impl Draw<'a, S>,
|
a: impl Draw<S>,
|
||||||
b: impl Draw<'a, S>,
|
b: impl Draw<S>,
|
||||||
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
) -> Usually<(Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
||||||
let area_a = to.size(None, a)?;
|
let area_a = to.size(None, a)?;
|
||||||
Ok(match split {
|
Ok(match split {
|
||||||
Split::South => (
|
Split::South => (
|
||||||
|
|
@ -330,10 +289,8 @@ impl Split {
|
||||||
/// let _ = Split::East.stack(&"", &"");
|
/// let _ = Split::East.stack(&"", &"");
|
||||||
/// let _ = Split::West.stack(&"", &"");
|
/// let _ = Split::West.stack(&"", &"");
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn stack <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (&self, a: A, b: B)
|
pub const fn stack <S: Screen, A: Draw<S>, B: Draw<S>> (&self, a: A, b: B) -> impl Draw<S> {
|
||||||
-> impl Draw<'a, S>
|
Pair(*self, a, b, PhantomData)
|
||||||
{
|
|
||||||
Pair(*self, a, b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
|
|
@ -345,9 +302,7 @@ impl Split {
|
||||||
/// let _ = Split::East.half(&"", &"");
|
/// let _ = Split::East.half(&"", &"");
|
||||||
/// let _ = Split::West.half(&"", &"");
|
/// let _ = Split::West.half(&"", &"");
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn half <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (&self, a: &A, b: &B)
|
pub const fn half <S: Screen, A: Draw<S>, B: Draw<S>> (&self, a: &A, b: &B) -> impl Draw<S> {
|
||||||
-> impl Draw<'a, S>
|
|
||||||
{
|
|
||||||
draw(move|to: &mut S|{
|
draw(move|to: &mut S|{
|
||||||
let (area_a, area_b) = to.xywh().split_half(self);
|
let (area_a, area_b) = to.xywh().split_half(self);
|
||||||
let (origin_a, origin_b) = self.origins();
|
let (origin_a, origin_b) = self.origins();
|
||||||
|
|
@ -401,28 +356,28 @@ impl Split {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn east <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B) -> impl Draw<'a, S> {
|
pub const fn east <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
|
||||||
Pair(Split::East, a, b)
|
Pair(Split::East, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn north <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B) -> impl Draw<'a, S> {
|
pub const fn north <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
|
||||||
Pair(Split::North, a, b)
|
Pair(Split::North, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn west <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B) -> impl Draw<'a, S> {
|
pub const fn west <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
|
||||||
Pair(Split::West, a, b)
|
Pair(Split::West, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn south <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B) -> impl Draw<'a, S> {
|
pub const fn south <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
|
||||||
Pair(Split::South, a, b)
|
Pair(Split::South, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn above <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B) -> impl Draw<'a, S> {
|
pub const fn above <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
|
||||||
Pair(Split::Above, a, b)
|
Pair(Split::Above, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn below <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B) -> impl Draw<'a, S> {
|
pub const fn below <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
|
||||||
Pair(Split::Below, a, b)
|
Pair(Split::Below, a, b, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export] macro_rules! north {
|
#[macro_export] macro_rules! north {
|
||||||
|
|
@ -455,6 +410,38 @@ pub const fn below <'a, S: Screen, A: Draw<'a, S>, B: Draw<'a, S>> (a: A, b: B)
|
||||||
($head:expr, $($tail:expr),* $(,)?) => { below($head, below!($($tail,)*)) };
|
($head:expr, $($tail:expr),* $(,)?) => { below($head, below!($($tail,)*)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_stack_areas () -> Usually<()> {
|
||||||
|
let area = XYWH(0u16, 0, 80, 25);
|
||||||
|
|
||||||
|
assert_eq!(stack_areas(&Split::East, &mut Tui::Layout(area), &"foo", &"bar")?, (
|
||||||
|
Some(XYWH(0u16, 0, 3, 1)),
|
||||||
|
Some(XYWH(3u16, 0, 3, 1)),
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(stack_areas(&Split::South, &mut Tui::Layout(area), &"foo", &"bar")?, (
|
||||||
|
Some(XYWH(0u16, 0, 3, 1)),
|
||||||
|
Some(XYWH(0u16, 1, 3, 1)),
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)] #[test] fn test_split_stack () -> Usually<()> {
|
||||||
|
use Split::*;
|
||||||
|
fn size_of <A: Draw<Tui>, B: Draw<Tui>> (stack: &Pair<Tui, A, B>) -> Perhaps<XYWH<u16>> {
|
||||||
|
Tui::Layout(XYWH(0, 0, 80, 25)).size(None, stack)
|
||||||
|
}
|
||||||
|
assert_eq!(size_of(&split(East, "foo", "bar"))?,
|
||||||
|
Some(XYWH(0, 0, 6, 1)));
|
||||||
|
assert_eq!(size_of(&split(South, "foo", "bar"))?,
|
||||||
|
Some(XYWH(0, 0, 3, 2)));
|
||||||
|
assert_eq!(size_of(&split(South, split(East, "foo", "bar"), "baz"))?,
|
||||||
|
Some(XYWH(0, 0, 6, 2)));
|
||||||
|
assert_eq!(size_of(&split(East, split(South, "foo", "bar"), "baz"))?,
|
||||||
|
Some(XYWH(0, 0, 6, 2)));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)] #[test] fn test_align () -> Usually<()> {
|
#[cfg(test)] #[test] fn test_align () -> Usually<()> {
|
||||||
let mut screen = Tui::Layout(XYWH(0, 0, 80, 25));
|
let mut screen = Tui::Layout(XYWH(0, 0, 80, 25));
|
||||||
assert_eq!("FOOBAR\nKILROY".draw(&mut screen)?, Some(XYWH(0, 0, 6, 2)));
|
assert_eq!("FOOBAR\nKILROY".draw(&mut screen)?, Some(XYWH(0, 0, 6, 2)));
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
fn_kw_layout!(kw_when |state, output, expr| {
|
fn_kw_layout!(kw_when |state, output, expr| {
|
||||||
let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x))));
|
Ok(matches!(expr.head()?, Some("when")).then(||{
|
||||||
ok_flat(matches!(expr.head()?, Some("when")).then(||{
|
when(state.namespace(expr.tail().head())?.unwrap(),
|
||||||
when(state.namespace(expr.nth(1)?)?.unwrap(), thunk) .draw(output)
|
draw(move|output: &mut O|{state.interpret(output, &expr.tail().tail().head())})
|
||||||
}))
|
).draw(output)
|
||||||
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Only render when condition is true.
|
/// Only render when condition is true.
|
||||||
|
|
@ -15,16 +16,21 @@ fn_kw_layout!(kw_when |state, output, expr| {
|
||||||
/// when(true, "Yes")
|
/// when(true, "Yes")
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn when <'a, T: Screen> (condition: bool, item: impl Draw<'a, T>) -> impl Draw<'a, T> {
|
pub const fn when <T: Screen> (condition: bool, item: impl Draw<T>) -> impl Draw<T> {
|
||||||
draw(move|to: &mut T|if condition { item.draw(to) } else { Ok(Default::default()) })
|
draw(move|to: &mut T|if condition { item.draw(to) } else { Ok(Default::default()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_kw_layout!(kw_either |state, output, expr| {
|
fn_kw_layout!(kw_either |state, output, expr| {
|
||||||
let thunk_a = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x))));
|
Ok(matches!(expr.head()?, Some("either")).then(||{
|
||||||
let thunk_b = draw(move|screen|ok_flat(expr.nth(3)?.map(|x: &'a str|state.interpret(screen, x))));
|
either(state.namespace(expr.tail().head()?)?.unwrap(),
|
||||||
ok_flat(matches!(expr.head()?, Some("either")).then(||{
|
draw(move|output: &mut O|{
|
||||||
either(state.namespace(expr.nth(1)?)?.unwrap(), thunk_a, thunk_b).draw(output)
|
state.interpret(output, &expr.tail().tail().head()?)
|
||||||
}))
|
}),
|
||||||
|
draw(move|output: &mut O|{
|
||||||
|
state.interpret(output, &expr.tail().tail().tail().head()?)
|
||||||
|
}),
|
||||||
|
).draw(output)
|
||||||
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Render one thing if a condition is true and another false.
|
/// Render one thing if a condition is true and another false.
|
||||||
|
|
@ -35,8 +41,6 @@ fn_kw_layout!(kw_either |state, output, expr| {
|
||||||
/// either(true, "Yes", "No")
|
/// either(true, "Yes", "No")
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn either <'a, T: Screen> (
|
pub const fn either <T: Screen> (condition: bool, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> {
|
||||||
condition: bool, a: impl Draw<'a, T>, b: impl Draw<'a, T>
|
|
||||||
) -> impl Draw<'a, T> {
|
|
||||||
draw(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) })
|
draw(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn iter_south <'a, S: Screen, D: Draw<'a, S>, I: Iterator<Item = D>> (
|
pub fn iter_south <'a, S: Screen, D: Draw<S>, I: Iterator<Item = D>> (
|
||||||
iter: impl Fn()->I
|
iter: impl Fn()->I
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|to: &mut S|{
|
draw(move|to: &mut S|{
|
||||||
let XYWH(x, y, w, h) = to.area();
|
let XYWH(x, y, w, h) = to.area();
|
||||||
let mut y_next = y;
|
let mut y_next = y;
|
||||||
|
|
@ -22,9 +22,9 @@ pub fn iter_south <'a, S: Screen, D: Draw<'a, S>, I: Iterator<Item = D>> (
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_east <'a, S: Screen, D: Draw<'a, S>, I: Iterator<Item = D>> (
|
pub fn iter_east <'a, S: Screen, D: Draw<S>, I: Iterator<Item = D>> (
|
||||||
iter: impl Fn()->I
|
iter: impl Fn()->I
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|to: &mut S|{
|
draw(move|to: &mut S|{
|
||||||
let XYWH(x, y, w, h) = to.area();
|
let XYWH(x, y, w, h) = to.area();
|
||||||
let mut x_next = x;
|
let mut x_next = x;
|
||||||
|
|
@ -45,75 +45,74 @@ pub fn iter_east <'a, S: Screen, D: Draw<'a, S>, I: Iterator<Item = D>> (
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over a collection of the same kind of [Draw]able:
|
/// Iterate over a collection of the same kind of [Draw]able:
|
||||||
pub fn iter <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<'a, S>> (
|
pub fn iter <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
|
||||||
_iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
_iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over a collection of the same kind of [Draw]able:
|
/// Iterate over a collection of the same kind of [Draw]able:
|
||||||
pub fn iter_once <'a, S: Screen, D: 'a, U: Draw<'a, S>> (
|
pub fn iter_once <'a, S: Screen, D: 'a, U: Draw<S>> (
|
||||||
_iter: impl Iterator<Item = D>, _draw: impl Fn(D, usize)->U,
|
_iter: impl Iterator<Item = D>, _draw: impl Fn(D, usize)->U,
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over a collection of various [Draw]ables:
|
/// Iterate over a collection of various [Draw]ables:
|
||||||
pub fn iter_dyn <
|
pub fn iter_dyn <
|
||||||
'a,
|
|
||||||
S: Screen, // Target screen
|
S: Screen, // Target screen
|
||||||
D, // Input doesn't need to be [Draw]able, output does
|
D, // Input doesn't need to be [Draw]able, output does
|
||||||
V: Fn()->I, // Function that returns the iterator
|
V: Fn()->I, // Function that returns the iterator
|
||||||
I: Iterator<Item = D>, // Type of the iterator
|
I: Iterator<Item = D>, // Type of the iterator
|
||||||
F: Fn(&D, usize)->dyn Draw<'a, S>, // Function that returns [Draw]able from iterator item
|
F: Fn(&D, usize)->dyn Draw<S>, // Function that returns [Draw]able from iterator item
|
||||||
> (_items: V, _cb: F) -> impl Draw<'a, S> {
|
> (_items: V, _cb: F) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_north <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<'a, S>> (
|
pub fn iter_north <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
|
||||||
_iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
_iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_east_fixed <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<'a, S>> (
|
pub fn iter_east_fixed <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
|
||||||
_height: S::Unit, _iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
_height: S::Unit, _iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_south_fixed <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<'a, S>> (
|
pub fn iter_south_fixed <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
|
||||||
_height: S::Unit, _iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
_height: S::Unit, _iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_west <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<'a, S>> (
|
pub fn iter_west <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
|
||||||
_iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
_iter: impl Fn()->I, _draw: impl Fn(D, usize)->U,
|
||||||
) -> impl Draw<'a, S> {
|
) -> impl Draw<S> {
|
||||||
draw(move|_to: &mut S|{ todo!() })
|
draw(move|_to: &mut S|{ todo!() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn row_south <'a, S: Screen + 'a> (south: S::Unit, height: S::Unit, content: impl Draw<'a, S>)
|
pub fn row_south <S: Screen> (south: S::Unit, height: S::Unit, content: impl Draw<S>)
|
||||||
-> impl Draw<'a, S>
|
-> impl Draw<S>
|
||||||
{
|
{
|
||||||
content.exact_h(height).push_y(south)
|
content.exact_h(height).push_y(south)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn row_north <'a, S: Screen + 'a> (north: S::Unit, height: S::Unit, content: impl Draw<'a, S>)
|
pub fn row_north <S: Screen> (north: S::Unit, height: S::Unit, content: impl Draw<S>)
|
||||||
-> impl Draw<'a, S>
|
-> impl Draw<S>
|
||||||
{
|
{
|
||||||
content.exact_h(height).pull_y(north)
|
content.exact_h(height).pull_y(north)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn col_east <'a, S: Screen + 'a> (east: S::Unit, width: S::Unit, content: impl Draw<'a, S>)
|
pub fn col_east <S: Screen> (east: S::Unit, width: S::Unit, content: impl Draw<S>)
|
||||||
-> impl Draw<'a, S>
|
-> impl Draw<S>
|
||||||
{
|
{
|
||||||
content.exact_w(width).push_x(east)
|
content.exact_w(width).push_x(east)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn col_west <'a, S: Screen + 'a> (west: S::Unit, width: S::Unit, content: impl Draw<'a, S>)
|
pub fn col_west <S: Screen> (west: S::Unit, width: S::Unit, content: impl Draw<S>)
|
||||||
-> impl Draw<'a, S>
|
-> impl Draw<S>
|
||||||
{
|
{
|
||||||
content.exact_w(width).pull_x(west)
|
content.exact_w(width).pull_x(west)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
94
src/lib.rs
94
src/lib.rs
|
|
@ -1205,8 +1205,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
exit: exit.clone(),
|
exit: exit.clone(),
|
||||||
perf: perf.clone(),
|
perf: perf.clone(),
|
||||||
join: Builder::new().name("tengri task".into()).spawn(move || {
|
join: Builder::new().name("tengri tui output".into()).spawn(move || {
|
||||||
#[cfg(feature = "prof")] profiling::register_thread!();
|
|
||||||
while !exit.fetch_and(true, Relaxed) {
|
while !exit.fetch_and(true, Relaxed) {
|
||||||
let _ = perf.cycle(&mut call);
|
let _ = perf.cycle(&mut call);
|
||||||
}
|
}
|
||||||
|
|
@ -1265,17 +1264,17 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
draw: &impl Fn(&mut Self)->T
|
draw: &impl Fn(&mut Self)->T
|
||||||
) -> T;
|
) -> T;
|
||||||
/// Determine used area without drawing
|
/// Determine used area without drawing
|
||||||
fn size <'a> (
|
fn size (
|
||||||
&mut self,
|
&mut self,
|
||||||
area: impl Into<Option<XYWH<Self::Unit>>>,
|
area: impl Into<Option<XYWH<Self::Unit>>>,
|
||||||
draw: impl Draw<'a, Self>
|
draw: impl Draw<Self>
|
||||||
) -> Drawn<'a, Self::Unit>;
|
) -> Perhaps<XYWH<Self::Unit>>;
|
||||||
/// Draw
|
/// Draw
|
||||||
fn draw <'a> (
|
fn draw (
|
||||||
&mut self,
|
&mut self,
|
||||||
area: impl Into<Option<XYWH<Self::Unit>>>,
|
area: impl Into<Option<XYWH<Self::Unit>>>,
|
||||||
draw: impl Draw<'a, Self>
|
draw: impl Draw<Self>
|
||||||
) -> Drawn<'a, Self::Unit>;
|
) -> Perhaps<XYWH<Self::Unit>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement the [Draw] trait for a particular drawable and [Screen].
|
/// Implement the [Draw] trait for a particular drawable and [Screen].
|
||||||
|
|
@ -1290,7 +1289,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
#[macro_export] macro_rules! impl_draw (
|
#[macro_export] macro_rules! impl_draw (
|
||||||
($(<$($T:ident: $Trait:path,)+>)?|
|
($(<$($T:ident: $Trait:path,)+>)?|
|
||||||
$self:ident:$Self:path, $to:ident:$To:ty
|
$self:ident:$Self:path, $to:ident:$To:ty
|
||||||
|$draw:block)=>{ impl$(<$($T:$Trait),+>)? Draw<'_, $To> for $Self {
|
|$draw:block)=>{ impl$(<$($T:$Trait),+>)? Draw<$To> for $Self {
|
||||||
fn draw (&$self, $to: &mut $To) -> Perhaps<XYWH<<$To as Screen>::Unit>> $draw
|
fn draw (&$self, $to: &mut $To) -> Perhaps<XYWH<<$To as Screen>::Unit>> $draw
|
||||||
} };
|
} };
|
||||||
($(<$($T:ident: $Trait:path,)+>)?|
|
($(<$($T:ident: $Trait:path,)+>)?|
|
||||||
|
|
@ -1321,8 +1320,8 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub trait Draw<'a, S: Screen> {
|
pub trait Draw<S: Screen> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit>;
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a [Draw]able.
|
/// Emit a [Draw]able.
|
||||||
|
|
@ -1345,14 +1344,14 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// let _ = view::<Tui, _, _>(||"drawable");
|
/// let _ = view::<Tui, _, _>(||"drawable");
|
||||||
/// let _ = view::<Tui, _, _>(||Some("drawable"));
|
/// let _ = view::<Tui, _, _>(||Some("drawable"));
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn view <S: Screen, T: for<'a> Draw<'a, S>, F: Fn()->T> (view: F) -> impl View<S> {
|
pub const fn view <S: Screen, T: Draw<S>, F: Fn()->T> (view: F) -> impl View<S> {
|
||||||
ViewThunk(view, PhantomData)
|
ViewThunk(view, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
||||||
pub struct ViewThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
|
pub struct ViewThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
|
||||||
|
|
||||||
impl<S: Screen, T: for<'a> Draw<'a, S>, F: Fn()->T> View<S> for ViewThunk<S, F> {
|
impl<S: Screen, T: Draw<S>, F: Fn()->T> View<S> for ViewThunk<S, F> {
|
||||||
fn view (&self) -> impl Draw<S> {
|
fn view (&self) -> impl Draw<S> {
|
||||||
self.0()
|
self.0()
|
||||||
}
|
}
|
||||||
|
|
@ -1361,8 +1360,8 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
||||||
pub struct DrawThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
|
pub struct DrawThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
|
||||||
|
|
||||||
impl<'a, T: Screen, F: Fn(&mut T)->PerhapsRef<'a, XYWH<T::Unit>>> Draw<'a, T> for DrawThunk<T, F> {
|
impl<T: Screen, F: Fn(&mut T)->Perhaps<XYWH<T::Unit>>> Draw<T> for DrawThunk<T, F> {
|
||||||
fn draw (&self, to: &mut T) -> PerhapsRef<'a, XYWH<T::Unit>> {
|
fn draw (&self, to: &mut T) -> Perhaps<XYWH<T::Unit>> {
|
||||||
to.clip(None, &self.0)
|
to.clip(None, &self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1373,25 +1372,23 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// # use tengri::*;
|
/// # use tengri::*;
|
||||||
/// let _ = draw(|to: &mut Tui|Ok(Some(to.area()))); // draws nothing
|
/// let _ = draw(|to: &mut Tui|Ok(Some(to.area()))); // draws nothing
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn draw <'a, T: Screen, F: Fn(&mut T)->PerhapsRef<'a, XYWH<T::Unit>>> (
|
pub const fn draw <T: Screen, F: Fn(&mut T)->Perhaps<XYWH<T::Unit>>> (
|
||||||
item: F
|
item: F
|
||||||
) -> DrawThunk<T, F> {
|
) -> DrawThunk<T, F> {
|
||||||
DrawThunk(item, std::marker::PhantomData)
|
DrawThunk(item, std::marker::PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Drawn<'a, U> = PerhapsRef<'a, XYWH<U>>;
|
pub type Drawn<U> = Perhaps<XYWH<U>>;
|
||||||
|
|
||||||
impl<'a, S: Screen> Draw<'a, S> for () {
|
impl<S: Screen> Draw<S> for () {
|
||||||
fn draw (&self, _: &mut S) -> Drawn<'a, S::Unit> {
|
fn draw (&self, _: &mut S) -> Drawn<S::Unit> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S: Screen, D: Draw<'a, S>> Draw<'a, S> for Option<D> {
|
impl_draw!(<S: Screen, D: Draw<S>,>|self: Option<D>, to: S|{
|
||||||
fn draw (&self, to: &mut S) -> Drawn<'a, S::Unit> {
|
self.as_ref().map(|it|it.draw(to)).transpose().map(Option::unwrap_or_default)
|
||||||
self.as_ref().map(|it|it.draw(to)).transpose().map(Option::unwrap_or_default)
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//impl<S: Screen, D: Draw<S>> Draw<S> for RwLock<D> {
|
//impl<S: Screen, D: Draw<S>> Draw<S> for RwLock<D> {
|
||||||
//fn draw (&self, __: &mut S) -> Drawn<S::Unit> {
|
//fn draw (&self, __: &mut S) -> Drawn<S::Unit> {
|
||||||
|
|
@ -1405,8 +1402,8 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
impl<'a, T: Screen, V: Draw<'a, T>> Draw<'a, T> for &V {
|
impl<T: Screen, V: Draw<T>> Draw<T> for &V {
|
||||||
fn draw (&self, to: &mut T) -> Drawn<'a, T::Unit> {
|
fn draw (&self, to: &mut T) -> Perhaps<XYWH<T::Unit>> {
|
||||||
(*self).draw(to)
|
(*self).draw(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1719,7 +1716,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
|
|
||||||
impl ItemTheme {
|
impl ItemTheme {
|
||||||
#[cfg(feature = "term")] pub const G: [Self;256] = {
|
#[cfg(feature = "term")] pub const G: [Self;256] = {
|
||||||
let mut builder = ::konst::array::ArrayBuilder::new();
|
let mut builder = dizzle::konst::array::ArrayBuilder::new();
|
||||||
while !builder.is_full() {
|
while !builder.is_full() {
|
||||||
let index = builder.len() as u8;
|
let index = builder.len() as u8;
|
||||||
let light = (index as f64 * 1.15) as u8;
|
let light = (index as f64 * 1.15) as u8;
|
||||||
|
|
@ -1790,26 +1787,23 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ColorDsl<'a, T>: Sized {
|
pub trait ColorDsl<T>: Sized {
|
||||||
fn new_g (expr: &'a T, try_to_u8: impl Fn(PerhapsRef<'a, &'a str>)->PerhapsRef<'a, u8>)
|
fn new_g (expr: T, try_to_u8: impl Fn(Perhaps<&str>)->Perhaps<u8>) -> Usually<Self>;
|
||||||
-> UsuallyRef<'a, Self>;
|
fn new_rgb (expr: T, try_to_u8: impl Fn(Perhaps<&str>)->Perhaps<u8>) -> Usually<Self>;
|
||||||
fn new_rgb (expr: &'a T, try_to_u8: impl Fn(PerhapsRef<'a, &str>)->PerhapsRef<'a, u8>)
|
|
||||||
-> UsuallyRef<'a, Self>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Language<'a> + 'a> ColorDsl<'a, T> for Color {
|
impl<T: Expression> ColorDsl<T> for Color {
|
||||||
fn new_g (expr: &'a T, try_to_u8: impl Fn(PerhapsRef<'a, &'a str>)->PerhapsRef<'a, u8>)
|
fn new_g (expr: T, try_to_u8: impl Fn(Perhaps<&str>)->Perhaps<u8>) -> Usually<Self> {
|
||||||
-> Result<Self, Box<dyn Error + 'a>>
|
|
||||||
{
|
|
||||||
let n = try_to_u8(expr.tail().map_err(Into::into))?.ok_or(Domain("not gray"))?;
|
let n = try_to_u8(expr.tail().map_err(Into::into))?.ok_or(Domain("not gray"))?;
|
||||||
Ok(Self::Rgb(n, n, n))
|
Ok(Self::Rgb(n, n, n))
|
||||||
}
|
}
|
||||||
fn new_rgb (expr: &'a T, try_to_u8: impl Fn(PerhapsRef<'a, &str>)->PerhapsRef<'a, u8>)
|
fn new_rgb (expr: T, try_to_u8: impl Fn(Perhaps<&str>)->Perhaps<u8>) -> Usually<Self> {
|
||||||
-> Result<Self, Box<dyn Error + 'a>>
|
let r = try_to_u8(expr.tail().map_err(Into::into))?
|
||||||
{
|
.ok_or(Domain("not red"))?;
|
||||||
let r = try_to_u8(expr.nth(1).map_err(Into::into))?.ok_or(Domain("not red"))?;
|
let g = try_to_u8(expr.tail().tail().head().map_err(Into::into))?
|
||||||
let g = try_to_u8(expr.nth(2).map_err(Into::into))?.ok_or(Domain("not green"))?;
|
.ok_or(Domain("not green"))?;
|
||||||
let b = try_to_u8(expr.nth(3).map_err(Into::into))?.ok_or(Domain("not blue"))?;
|
let b = try_to_u8(expr.tail().tail().tail().head().map_err(Into::into))?
|
||||||
|
.ok_or(Domain("not blue"))?;
|
||||||
Ok(Color::Rgb(r, g, b))
|
Ok(Color::Rgb(r, g, b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1907,7 +1901,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl Interpret<Tui, Option<XYWH<u16>>> for App {
|
/// impl Interpret<Tui, Option<XYWH<u16>>> for App {
|
||||||
/// fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Language)
|
/// fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression)
|
||||||
/// -> Usually<Option<XYWH<u16>>>
|
/// -> Usually<Option<XYWH<u16>>>
|
||||||
/// {
|
/// {
|
||||||
/// self.keyword(to, lang)
|
/// self.keyword(to, lang)
|
||||||
|
|
@ -1936,7 +1930,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// ```
|
/// ```
|
||||||
pub trait Keywords <U, V>: 'static {
|
pub trait Keywords <U, V>: 'static {
|
||||||
fn keywords () -> impl Iterator<Item = fn(&Self, &mut U, &str) -> Perhaps<V>>;
|
fn keywords () -> impl Iterator<Item = fn(&Self, &mut U, &str) -> Perhaps<V>>;
|
||||||
fn keyword <'a> (&self, to: &mut U, expr: &'a impl Language<'a>) -> PerhapsRef<'a, V> {
|
fn keyword (&self, to: &mut U, expr: &impl Expression) -> Perhaps<V> {
|
||||||
if let Some(expr) = expr.src()? {
|
if let Some(expr) = expr.src()? {
|
||||||
for keyword in Self::keywords() {
|
for keyword in Self::keywords() {
|
||||||
if let Some(result) = keyword(self, to, &expr)? {
|
if let Some(result) = keyword(self, to, &expr)? {
|
||||||
|
|
@ -1959,5 +1953,17 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn invalid_variant <T> (
|
||||||
|
name: &str,
|
||||||
|
frag: impl Language,
|
||||||
|
expr: impl Language,
|
||||||
|
head: impl Language,
|
||||||
|
) -> Usually<T> {
|
||||||
|
unimplemented!(
|
||||||
|
"{name}/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
||||||
|
head.src()?.unwrap_or_default().split("/").next()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "term")] pub use self::term::*;
|
#[cfg(feature = "term")] pub use self::term::*;
|
||||||
#[cfg(feature = "term")] mod term;
|
#[cfg(feature = "term")] mod term;
|
||||||
|
|
|
||||||
47
src/term.rs
47
src/term.rs
|
|
@ -96,14 +96,14 @@ impl Screen for Tui {
|
||||||
fn area (&self) -> XYWH<Self::Unit> {
|
fn area (&self) -> XYWH<Self::Unit> {
|
||||||
self.into()
|
self.into()
|
||||||
}
|
}
|
||||||
fn size <'a> (
|
fn size (
|
||||||
&mut self, area: impl Into<Option<XYWH<u16>>>, draw: impl Draw<'a, Self>,
|
&mut self, area: impl Into<Option<XYWH<u16>>>, draw: impl Draw<Self>,
|
||||||
) -> Drawn<'a, Self::Unit> {
|
) -> Perhaps<XYWH<Self::Unit>> {
|
||||||
Self::Layout(self.area()).clip(area, &|to|draw.draw(to))
|
Self::Layout(self.area()).clip(area, &|to|draw.draw(to))
|
||||||
}
|
}
|
||||||
fn draw <'a> (
|
fn draw (
|
||||||
&mut self, area: impl Into<Option<XYWH<u16>>>, draw: impl Draw<'a, Tui>
|
&mut self, area: impl Into<Option<XYWH<u16>>>, draw: impl Draw<Tui>
|
||||||
) -> Drawn<'a, Self::Unit> {
|
) -> Perhaps<XYWH<Self::Unit>> {
|
||||||
self.clip(area, &|to|draw.draw(to))
|
self.clip(area, &|to|draw.draw(to))
|
||||||
}
|
}
|
||||||
fn clip <T> (
|
fn clip <T> (
|
||||||
|
|
@ -289,7 +289,7 @@ impl Tui {
|
||||||
/// let _ = tengri::Tui::catcher(&variant);
|
/// let _ = tengri::Tui::catcher(&variant);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn catcher <'a, T: Draw<'a, Tui>> (result: &Usually<T>) -> impl Draw<'a, Tui> {
|
pub fn catcher <T: Draw<Tui>> (result: &Usually<T>) -> impl Draw<Tui> {
|
||||||
draw(move|to: &mut Tui|match result {
|
draw(move|to: &mut Tui|match result {
|
||||||
Ok(content) => content.draw(to),
|
Ok(content) => content.draw(to),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -369,7 +369,7 @@ impl<'a: 'b, 'b> From<&'a mut Tui> for &'b mut XYWH<u16> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn fill_char <'a> (c: char) -> impl Draw<'a, Tui> {
|
pub const fn fill_char (c: char) -> impl Draw<Tui> {
|
||||||
draw(move|to: &mut Tui|Ok(Some(to.update(&|cell,_,_|{
|
draw(move|to: &mut Tui|Ok(Some(to.update(&|cell,_,_|{
|
||||||
cell.set_char(c);
|
cell.set_char(c);
|
||||||
}))))
|
}))))
|
||||||
|
|
@ -378,8 +378,8 @@ pub const fn fill_char <'a> (c: char) -> impl Draw<'a, Tui> {
|
||||||
/// FIXME: Don't use `format!` but implement number blitting
|
/// FIXME: Don't use `format!` but implement number blitting
|
||||||
pub struct ShowSize;
|
pub struct ShowSize;
|
||||||
|
|
||||||
impl<'a> Draw<'a, Tui> for ShowSize {
|
impl Draw<Tui> for ShowSize {
|
||||||
fn draw (&self, to: &mut Tui) -> Drawn<'a, u16> {
|
fn draw (&self, to: &mut Tui) -> Drawn<u16> {
|
||||||
let area = to.area();
|
let area = to.area();
|
||||||
let info = format!("{area:?}");
|
let info = format!("{area:?}");
|
||||||
to.text(&info, area.0, area.1, info.len() as u16)
|
to.text(&info, area.0, area.1, info.len() as u16)
|
||||||
|
|
@ -388,8 +388,8 @@ impl<'a> Draw<'a, Tui> for ShowSize {
|
||||||
|
|
||||||
pub struct ShowSizeOf<T>(pub T);
|
pub struct ShowSizeOf<T>(pub T);
|
||||||
|
|
||||||
impl<'a, T: Draw<'a, Tui>> Draw<'a, Tui> for ShowSizeOf<T> {
|
impl<T: Draw<Tui>> Draw<Tui> for ShowSizeOf<T> {
|
||||||
fn draw (&self, to: &mut Tui) -> Drawn<'a, u16> {
|
fn draw (&self, to: &mut Tui) -> Drawn<u16> {
|
||||||
Ok(self.0.draw(to)?.map(|used|{
|
Ok(self.0.draw(to)?.map(|used|{
|
||||||
let _ = to.text(&format!("{used:?}"), used.0, used.1, u16::MAX);
|
let _ = to.text(&format!("{used:?}"), used.0, used.1, u16::MAX);
|
||||||
used
|
used
|
||||||
|
|
@ -398,14 +398,13 @@ impl<'a, T: Draw<'a, Tui>> Draw<'a, Tui> for ShowSizeOf<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "eval")] fn_kw_layout_tui!(kw_tui_text |_state, output, expr| {
|
#[cfg(feature = "eval")] fn_kw_layout_tui!(kw_tui_text |_state, output, expr| {
|
||||||
Ok(if matches!(expr.head()?, Some("text")) {
|
Ok(matches!(expr.head()?, Some("text")).then(||{
|
||||||
expr.tail()?
|
if let Some(src) = expr.tail().src()? && src.len() > 0 {
|
||||||
.and_then(|src|(src.len() > 0).then(||(&src[1..]).draw(output)))
|
(&src[1..]).draw(output)
|
||||||
.transpose()?
|
} else {
|
||||||
.flatten()
|
return Ok(None)
|
||||||
} else {
|
}
|
||||||
None
|
}).transpose()?.flatten())
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "text")] pub use self::tui_text::*;
|
#[cfg(feature = "text")] pub use self::tui_text::*;
|
||||||
|
|
@ -474,8 +473,8 @@ impl<'a, T: Draw<'a, Tui>> Draw<'a, Tui> for ShowSizeOf<T> {
|
||||||
self.as_ref().draw(to)
|
self.as_ref().draw(to)
|
||||||
});
|
});
|
||||||
|
|
||||||
impl<'a> Draw<'a, Tui> for &str {
|
impl Draw<Tui> for &str {
|
||||||
fn draw (&self, to: &mut Tui) -> Drawn<'a, u16> {
|
fn draw (&self, to: &mut Tui) -> Drawn<u16> {
|
||||||
let XYWH(x, y, w, h) = to.area();
|
let XYWH(x, y, w, h) = to.area();
|
||||||
let mut max_w = 0u16;
|
let mut max_w = 0u16;
|
||||||
let mut max_h = 0u16;
|
let mut max_h = 0u16;
|
||||||
|
|
@ -494,8 +493,8 @@ impl<'a, T: Draw<'a, Tui>> Draw<'a, Tui> for ShowSizeOf<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: AsRef<str>> Draw<'a, Tui> for TrimStr<'a, T> {
|
impl<'t, T: AsRef<str>> Draw<Tui> for TrimStr<'_, T> {
|
||||||
fn draw (&self, to: &mut Tui) -> Drawn<'a, u16> {
|
fn draw (&self, to: &mut Tui) -> Drawn<u16> {
|
||||||
let text = self.1.as_ref();
|
let text = self.1.as_ref();
|
||||||
let area = layout_text_u16(text, to.area())?.unwrap();
|
let area = layout_text_u16(text, to.area())?.unwrap();
|
||||||
let XYWH(x, y, w, ..) = to.area();
|
let XYWH(x, y, w, ..) = to.area();
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@ use crate::*;
|
||||||
/// ```
|
/// ```
|
||||||
/// /// TODO
|
/// /// TODO
|
||||||
/// ```
|
/// ```
|
||||||
pub fn border <'a> (
|
pub fn border (on: bool, style: impl BorderStyle, item: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
on: bool, style: impl BorderStyle<'a>, item: impl Draw<'a, Tui>
|
|
||||||
) -> impl Draw<'a, Tui> {
|
|
||||||
let content = item.pad_wh(1, 1);
|
let content = item.pad_wh(1, 1);
|
||||||
let outline = when(on, draw(move|to: &mut Tui|{
|
let outline = when(on, draw(move|to: &mut Tui|{
|
||||||
let XYWH(x, y, w, h) = to.area();
|
let XYWH(x, y, w, h) = to.area();
|
||||||
|
|
@ -35,7 +33,7 @@ macro_rules! border {
|
||||||
$nw:literal $n:literal $ne:literal $w:literal $e:literal $sw:literal $s:literal $se:literal
|
$nw:literal $n:literal $ne:literal $w:literal $e:literal $sw:literal $s:literal $se:literal
|
||||||
$($x:tt)*
|
$($x:tt)*
|
||||||
}),+) => {$(
|
}),+) => {$(
|
||||||
impl<'a> BorderStyle<'a> for $T {
|
impl BorderStyle for $T {
|
||||||
const NW: &'static str = $nw;
|
const NW: &'static str = $nw;
|
||||||
const N: &'static str = $n;
|
const N: &'static str = $n;
|
||||||
const NE: &'static str = $ne;
|
const NE: &'static str = $ne;
|
||||||
|
|
@ -49,7 +47,7 @@ macro_rules! border {
|
||||||
}
|
}
|
||||||
#[derive(Copy, Clone)] pub struct $T(pub bool, pub Style);
|
#[derive(Copy, Clone)] pub struct $T(pub bool, pub Style);
|
||||||
//impl Layout<Tui> for $T {}
|
//impl Layout<Tui> for $T {}
|
||||||
impl<'a> Draw<'a, Tui> for $T {
|
impl Draw<Tui> for $T {
|
||||||
fn draw (&self, to: &mut Tui) -> Perhaps<XYWH<u16>> {
|
fn draw (&self, to: &mut Tui) -> Perhaps<XYWH<u16>> {
|
||||||
when(self.enabled(), draw(|to: &mut Tui|BorderStyle::draw(*self, to).map(Some))).draw(to)
|
when(self.enabled(), draw(|to: &mut Tui|BorderStyle::draw(*self, to).map(Some))).draw(to)
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +161,7 @@ border! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BorderStyle<'a>: Draw<'a, Tui> + Copy {
|
pub trait BorderStyle: Draw<Tui> + Copy {
|
||||||
fn enabled (&self) -> bool;
|
fn enabled (&self) -> bool;
|
||||||
fn border_n (&self) -> &str { Self::N }
|
fn border_n (&self) -> &str { Self::N }
|
||||||
fn border_s (&self) -> &str { Self::S }
|
fn border_s (&self) -> &str { Self::S }
|
||||||
|
|
@ -174,7 +172,7 @@ pub trait BorderStyle<'a>: Draw<'a, Tui> + Copy {
|
||||||
fn border_sw (&self) -> &str { Self::SW }
|
fn border_sw (&self) -> &str { Self::SW }
|
||||||
fn border_se (&self) -> &str { Self::SE }
|
fn border_se (&self) -> &str { Self::SE }
|
||||||
|
|
||||||
#[inline] fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
#[inline] fn draw <'a> (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
||||||
if self.enabled() {
|
if self.enabled() {
|
||||||
self.draw_h(to, None)?;
|
self.draw_h(to, None)?;
|
||||||
self.draw_v(to, None)?;
|
self.draw_v(to, None)?;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ::dizzle::*;
|
use ::dizzle::{Language, Symbol, Usually};
|
||||||
use ::crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
|
use ::crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
|
||||||
|
|
||||||
/// TUI key spec.
|
/// TUI key spec.
|
||||||
|
|
@ -70,7 +70,7 @@ impl TuiKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lang")]
|
#[cfg(feature = "lang")]
|
||||||
pub fn from_dsl <'a> (dsl: &'a impl Language<'a>) -> UsuallyRef<'a, Self> {
|
pub fn from_dsl (dsl: impl Language) -> Usually<Self> {
|
||||||
if let Some(word) = dsl.word()? {
|
if let Some(word) = dsl.word()? {
|
||||||
let word = word.trim();
|
let word = word.trim();
|
||||||
Ok(if word == ":char" {
|
Ok(if word == ":char" {
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,36 @@ use crate::*;
|
||||||
use Color::*;
|
use Color::*;
|
||||||
|
|
||||||
fn_kw_layout_tui!(kw_tui_fg |state, output, expr| {
|
fn_kw_layout_tui!(kw_tui_fg |state, output, expr| {
|
||||||
let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(matches!(expr.head()?, Some("fg")).then(||{
|
Ok(matches!(expr.head()?, Some("fg")).then(||{
|
||||||
if let Some(color) = state.namespace(expr.nth(1)?.expect("fg: expected arg 0 (color)"))? {
|
let args = expr.tail();
|
||||||
fg(color, thunk).draw(output)
|
let arg0 = args.head();
|
||||||
|
let tail0 = args.tail();
|
||||||
|
let arg1 = tail0.head();
|
||||||
|
if let Some(color) = state.namespace(arg0?.expect("fg: expected arg 0 (color)"))? {
|
||||||
|
fg(color, draw(move|to: &mut Tui|state.interpret(to, &arg1))).draw(output)
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("fg: {:?}: not a color", expr.nth(1)).into())
|
return Err(format!("fg: {arg0:?}: not a color").into())
|
||||||
}
|
}
|
||||||
}).transpose()?.flatten())
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
||||||
fn_kw_layout_tui!(kw_tui_bg |state, output, expr| {
|
fn_kw_layout_tui!(kw_tui_bg |state, output, expr| {
|
||||||
let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x))));
|
|
||||||
Ok(matches!(expr.head()?, Some("bg")).then(||{
|
Ok(matches!(expr.head()?, Some("bg")).then(||{
|
||||||
if let Some(color) = state.namespace(expr.nth(1)?.expect("bg: expected arg 0 (color)"))? {
|
let args = expr.tail();
|
||||||
bg(color, thunk).draw(output)
|
let arg0 = args.head();
|
||||||
|
let tail0 = args.tail();
|
||||||
|
let arg1 = tail0.head();
|
||||||
|
if let Some(color) = state.namespace(arg0?.expect("bg: expected arg 0 (color)"))? {
|
||||||
|
bg(color, draw(move|to: &mut Tui|state.interpret(to, &arg1))).draw(output)
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("bg: {:?}: not a color", expr.nth(1)?).into())
|
return Err(format!("bg: {arg0:?}: not a color").into())
|
||||||
}
|
}
|
||||||
}).transpose()?.flatten())
|
}).transpose()?.flatten())
|
||||||
});
|
});
|
||||||
|
|
||||||
impl Tui {
|
impl Tui {
|
||||||
pub fn eval_color_expr <'a> (state: &impl Namespace<u8>, src: &'a impl Language<'a>)
|
pub fn eval_color_expr (state: &impl Namespace<u8>, src: impl Language)
|
||||||
-> Result<Option<Color>, Box<dyn Error + 'a>>
|
-> Perhaps<Color>
|
||||||
{
|
{
|
||||||
if let Some(expr) = src.expr()? {
|
if let Some(expr) = src.expr()? {
|
||||||
match (expr.head()?, expr.tail()?) {
|
match (expr.head()?, expr.tail()?) {
|
||||||
|
|
@ -57,9 +63,7 @@ impl Tui {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply foreground color.
|
/// Apply foreground color.
|
||||||
pub const fn fg <'a> (fg: Color, item: impl Draw<'a, Tui>)
|
pub const fn fg (fg: Color, item: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
-> impl Draw<'a, Tui>
|
|
||||||
{
|
|
||||||
draw(move|to: &mut Tui|{
|
draw(move|to: &mut Tui|{
|
||||||
if let Some(size) = to.size(None, &item)? {
|
if let Some(size) = to.size(None, &item)? {
|
||||||
to.draw(Some(size), draw(|to: &mut Tui|{
|
to.draw(Some(size), draw(|to: &mut Tui|{
|
||||||
|
|
@ -73,9 +77,7 @@ pub const fn fg <'a> (fg: Color, item: impl Draw<'a, Tui>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply background color.
|
/// Apply background color.
|
||||||
pub const fn bg <'a> (bg: Color, item: impl Draw<'a, Tui>)
|
pub const fn bg (bg: Color, item: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
-> impl Draw<'a, Tui>
|
|
||||||
{
|
|
||||||
draw(move|to: &mut Tui|{
|
draw(move|to: &mut Tui|{
|
||||||
if let Some(size) = to.size(None, &item)? {
|
if let Some(size) = to.size(None, &item)? {
|
||||||
let _ = to.draw(Some(size), draw(|to: &mut Tui|{
|
let _ = to.draw(Some(size), draw(|to: &mut Tui|{
|
||||||
|
|
@ -88,9 +90,7 @@ pub const fn bg <'a> (bg: Color, item: impl Draw<'a, Tui>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn fg_bg <'a> (fg: Color, bg: Color, item: impl Draw<'a, Tui>)
|
pub const fn fg_bg (fg: Color, bg: Color, item: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
-> impl Draw<'a, Tui>
|
|
||||||
{
|
|
||||||
draw(move|to: &mut Tui|{
|
draw(move|to: &mut Tui|{
|
||||||
if let Some(size) = to.size(None, &item)? {
|
if let Some(size) = to.size(None, &item)? {
|
||||||
let _ = to.draw(Some(size), draw(|to: &mut Tui|{
|
let _ = to.draw(Some(size), draw(|to: &mut Tui|{
|
||||||
|
|
@ -104,16 +104,14 @@ pub const fn fg_bg <'a> (fg: Color, bg: Color, item: impl Draw<'a, Tui>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw contents with modifier applied.
|
/// Draw contents with modifier applied.
|
||||||
pub const fn modify <'a> (on: bool, modifier: Modifier, item: impl Draw<'a, Tui>)
|
pub const fn modify (on: bool, modifier: Modifier, item: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
-> impl Draw<'a, Tui>
|
|
||||||
{
|
|
||||||
draw(move|to: &mut Tui|{
|
draw(move|to: &mut Tui|{
|
||||||
fill_mod(on, modifier).draw(to)?;
|
fill_mod(on, modifier).draw(to)?;
|
||||||
item.draw(to)
|
item.draw(to)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn fill_mod <'a> (on: bool, modifier: Modifier) -> impl Draw<'a, Tui> {
|
pub const fn fill_mod (on: bool, modifier: Modifier) -> impl Draw<Tui> {
|
||||||
draw(move|to: &mut Tui|Ok(Some({
|
draw(move|to: &mut Tui|Ok(Some({
|
||||||
if on {
|
if on {
|
||||||
to.update(&|cell,_,_|cell.modifier.insert(modifier))
|
to.update(&|cell,_,_|cell.modifier.insert(modifier))
|
||||||
|
|
@ -124,11 +122,11 @@ pub const fn fill_mod <'a> (on: bool, modifier: Modifier) -> impl Draw<'a, Tui>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw contents with bold modifier applied.
|
/// Draw contents with bold modifier applied.
|
||||||
pub const fn bold <'a> (on: bool, item: impl Draw<'a, Tui>) -> impl Draw<'a, Tui> {
|
pub const fn bold (on: bool, item: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
modify(on, Modifier::BOLD, item)
|
modify(on, Modifier::BOLD, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn fill_ul <'a> (color: Option<Color>) -> impl Draw<'a, Tui> {
|
pub const fn fill_ul (color: Option<Color>) -> impl Draw<Tui> {
|
||||||
draw(move|to: &mut Tui|Ok(Some(if let Some(color) = color {
|
draw(move|to: &mut Tui|Ok(Some(if let Some(color) = color {
|
||||||
to.update(&|cell,_,_|{
|
to.update(&|cell,_,_|{
|
||||||
cell.modifier.insert(Modifier::UNDERLINED);
|
cell.modifier.insert(Modifier::UNDERLINED);
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@ use crate::*;
|
||||||
/// ```
|
/// ```
|
||||||
/// /// TODO
|
/// /// TODO
|
||||||
/// ```
|
/// ```
|
||||||
pub fn phat <'a> (
|
pub fn phat (w: u16, h: u16, [fg, bg, hi, lo]: [Color;4], draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||||
w: u16, h: u16, [fg, bg, hi, lo]: [Color;4], draw: impl Draw<'a, Tui>
|
|
||||||
) -> impl Draw<'a, Tui> {
|
|
||||||
let top = phat_lo(bg, hi).exact_h(1);
|
let top = phat_lo(bg, hi).exact_h(1);
|
||||||
let low = phat_hi(bg, lo).exact_h(1);
|
let low = phat_hi(bg, lo).exact_h(1);
|
||||||
let draw = fg_bg(fg, bg, draw);
|
let draw = fg_bg(fg, bg, draw);
|
||||||
|
|
@ -19,11 +17,11 @@ pub const LO: &'static str = "▄";
|
||||||
pub const HI: &'static str = "▀";
|
pub const HI: &'static str = "▀";
|
||||||
|
|
||||||
/// A phat line
|
/// A phat line
|
||||||
fn phat_lo <'a> (fg: Color, bg: Color) -> impl Draw<'a, Tui> {
|
fn phat_lo (fg: Color, bg: Color) -> impl Draw<Tui> {
|
||||||
fg_bg(fg, bg, x_repeat(LO)).exact_h(1)
|
fg_bg(fg, bg, x_repeat(LO)).exact_h(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A phat line
|
/// A phat line
|
||||||
fn phat_hi <'a> (fg: Color, bg: Color) -> impl Draw<'a, Tui> {
|
fn phat_hi (fg: Color, bg: Color) -> impl Draw<Tui> {
|
||||||
fg_bg(fg, bg, x_repeat(HI)).exact_h(1)
|
fg_bg(fg, bg, x_repeat(HI)).exact_h(1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ pub const ICON_INC_V: &[char] = &['▼'];
|
||||||
pub const ICON_DEC_H: &[char] = &[' ', '🞀', ' '];
|
pub const ICON_DEC_H: &[char] = &[' ', '🞀', ' '];
|
||||||
pub const ICON_INC_H: &[char] = &[' ', '🞂', ' '];
|
pub const ICON_INC_H: &[char] = &[' ', '🞂', ' '];
|
||||||
|
|
||||||
pub fn x_scroll <'a> () -> impl Draw<'a, Tui> {
|
pub fn x_scroll () -> impl Draw<Tui> {
|
||||||
draw(|to: &mut Tui|{
|
draw(|to: &mut Tui|{
|
||||||
let XYWH(x1, y1, w, _h) = to.area();
|
let XYWH(x1, y1, w, _h) = to.area();
|
||||||
let x2 = x1 + w;
|
let x2 = x1 + w;
|
||||||
|
|
@ -37,7 +37,7 @@ pub fn x_scroll <'a> () -> impl Draw<'a, Tui> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn y_scroll <'a> () -> impl Draw<'a, Tui> {
|
pub fn y_scroll () -> impl Draw<Tui> {
|
||||||
draw(|to: &mut Tui|{
|
draw(|to: &mut Tui|{
|
||||||
let XYWH(x1, y1, _w, h) = to.area();
|
let XYWH(x1, y1, _w, h) = to.area();
|
||||||
let y2 = y1 + h;
|
let y2 = y1 + h;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue