mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 19:56:44 +01:00
This commit is contained in:
parent
91dc77cfea
commit
11f686650f
19 changed files with 964 additions and 918 deletions
|
|
@ -1,180 +1,14 @@
|
|||
#![feature(step_trait)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
pub(crate) use tengri_core::*;
|
||||
|
||||
pub(crate) use std::marker::PhantomData;
|
||||
pub(crate) use tengri_core::*;
|
||||
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
||||
|
||||
mod space; pub use self::space::*;
|
||||
mod ops; pub use self::ops::*;
|
||||
mod output; pub use self::output::*;
|
||||
#[cfg(test)] mod test;
|
||||
#[cfg(test)] pub use proptest_derive::Arbitrary;
|
||||
|
||||
/// Enabling the `dsl` feature implements [FromDsl] for
|
||||
/// the layout elements that are provided by this crate.
|
||||
#[cfg(feature = "dsl")] mod ops_dsl {
|
||||
use crate::*;
|
||||
use ::tengri_dsl::*;
|
||||
/// The syntagm `(when :condition :content)` corresponds to a [When] layout element.
|
||||
impl<S, A> FromDsl<S> for When<A> where S: Eval<Ast, bool> + Eval<Ast, A> {
|
||||
fn try_provide (state: &S, source: DslValue<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
source.exp_match("when", |_, tail|Ok(Some(Self(
|
||||
tail.eval(0, ||"no condition")?,
|
||||
tail.eval(1, ||"no content")?,
|
||||
))))
|
||||
}
|
||||
}
|
||||
/// The syntagm `(either :condition :content1 :content2)` corresponds to an [Either] layout element.
|
||||
impl<S, A, B> FromDsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
|
||||
fn try_provide (state: &S, source: DslValue<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
source.exp_match("either", |_, tail|Ok(Some(Self(
|
||||
tail.eval(0, ||"no condition")?,
|
||||
tail.eval(1, ||"no content 1")?,
|
||||
tail.eval(2, ||"no content 2")?,
|
||||
))))
|
||||
}
|
||||
}
|
||||
/// The syntagm `(align/* :content)` corresponds to an [Align] layout element,
|
||||
/// where `*` specifies the direction of the alignment.
|
||||
impl<S, A> FromDsl<S> for Align<A> where S: Eval<Option<Ast>, A> {
|
||||
fn try_provide (state: &S, source: DslValue<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
source.exp_match("align/", |head, tail|Ok(Some(match head {
|
||||
"c" => Self::c(tail.eval(0, ||"no content")?),
|
||||
"x" => Self::x(tail.eval(0, ||"no content")?),
|
||||
"y" => Self::y(tail.eval(0, ||"no content")?),
|
||||
"n" => Self::n(tail.eval(0, ||"no content")?),
|
||||
"s" => Self::s(tail.eval(0, ||"no content")?),
|
||||
"e" => Self::e(tail.eval(0, ||"no content")?),
|
||||
"w" => Self::w(tail.eval(0, ||"no content")?),
|
||||
"nw" => Self::nw(tail.eval(0, ||"no content")?),
|
||||
"ne" => Self::ne(tail.eval(0, ||"no content")?),
|
||||
"sw" => Self::sw(tail.eval(0, ||"no content")?),
|
||||
"se" => Self::se(tail.eval(0, ||"no content")?),
|
||||
_ => return Err("invalid align variant".into())
|
||||
})))
|
||||
}
|
||||
}
|
||||
/// The syntagm `(bsp/* :content1 :content2)` corresponds to a [Bsp] layout element,
|
||||
/// where `*` specifies the direction of the split.
|
||||
impl<S, A, B> FromDsl<S> for Bsp<A, B> where S: Eval<Option<Ast>, A> + Eval<Option<Ast>, B> {
|
||||
fn try_provide (state: &S, source: DslValue<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
source.exp_match("bsp/", |head, tail|Ok(Some(match head {
|
||||
"n" => Self::n(tail.eval(0, ||"no content 1"), tail.eval(1, ||"no content 2")),
|
||||
"s" => Self::s(tail.eval(0, ||"no content 1"), tail.eval(1, ||"no content 2")),
|
||||
"e" => Self::e(tail.eval(0, ||"no content 1"), tail.eval(1, ||"no content 2")),
|
||||
"w" => Self::w(tail.eval(0, ||"no content 1"), tail.eval(1, ||"no content 2")),
|
||||
"a" => Self::a(tail.eval(0, ||"no content 1"), tail.eval(1, ||"no content 2")),
|
||||
"b" => Self::b(tail.eval(0, ||"no content 1"), tail.eval(1, ||"no content 2")),
|
||||
_ => return Ok(None),
|
||||
})))
|
||||
}
|
||||
}
|
||||
//#[cfg(feature = "dsl")] take!($Enum<A>, A|state, words|Ok(
|
||||
//if let Some(Token { value: Key(k), .. }) = words.peek() {
|
||||
//let mut base = words.clone();
|
||||
//let content = state.give_or_fail(words, ||format!("{k}: no content"))?;
|
||||
//return Ok(Some(match words.next() {
|
||||
//Some(Token{value: Key($x),..}) => Self::x(content),
|
||||
//Some(Token{value: Key($y),..}) => Self::y(content),
|
||||
//Some(Token{value: Key($xy),..}) => Self::xy(content),
|
||||
//_ => unreachable!()
|
||||
//}))
|
||||
//} else {
|
||||
//None
|
||||
//}));
|
||||
//#[cfg(feature = "dsl")] take!($Enum<U, A>, U, A|state, words|Ok(
|
||||
//if let Some(Token { value: Key($x|$y|$xy), .. }) = words.peek() {
|
||||
//let mut base = words.clone();
|
||||
//Some(match words.next() {
|
||||
//Some(Token { value: Key($x), .. }) => Self::x(
|
||||
//state.give_or_fail(words, ||"x: no unit")?,
|
||||
//state.give_or_fail(words, ||"x: no content")?,
|
||||
//),
|
||||
//Some(Token { value: Key($y), .. }) => Self::y(
|
||||
//state.give_or_fail(words, ||"y: no unit")?,
|
||||
//state.give_or_fail(words, ||"y: no content")?,
|
||||
//),
|
||||
//Some(Token { value: Key($x), .. }) => Self::xy(
|
||||
//state.give_or_fail(words, ||"xy: no unit x")?,
|
||||
//state.give_or_fail(words, ||"xy: no unit y")?,
|
||||
//state.give_or_fail(words, ||"xy: no content")?
|
||||
//),
|
||||
//_ => unreachable!(),
|
||||
//})
|
||||
//} else {
|
||||
//None
|
||||
//}));
|
||||
//if let Exp(_, exp) = source.value() {
|
||||
//let mut rest = exp.clone();
|
||||
//return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
|
||||
//Some("bsp/n") => Self::n(
|
||||
//state.eval(rest.next(), ||"bsp/n: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/n: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/s") => Self::s(
|
||||
//state.eval(rest.next(), ||"bsp/s: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/s: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/e") => Self::e(
|
||||
//state.eval(rest.next(), ||"bsp/e: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/e: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/w") => Self::w(
|
||||
//state.eval(rest.next(), ||"bsp/w: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/w: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/a") => Self::a(
|
||||
//state.eval(rest.next(), ||"bsp/a: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/a: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/b") => Self::b(
|
||||
//state.eval(rest.next(), ||"bsp/b: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/b: no content 2")?,
|
||||
//),
|
||||
//_ => return Ok(None),
|
||||
//}))
|
||||
//}
|
||||
//Ok(None)
|
||||
//if let Exp(_, source) = source.value() {
|
||||
//let mut rest = source.clone();
|
||||
//return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
|
||||
//Some("align/c") => Self::c(state.eval(rest.next(), ||"align/c: no content")?),
|
||||
//Some("align/x") => Self::x(state.eval(rest.next(), ||"align/x: no content")?),
|
||||
//Some("align/y") => Self::y(state.eval(rest.next(), ||"align/y: no content")?),
|
||||
//Some("align/n") => Self::n(state.eval(rest.next(), ||"align/n: no content")?),
|
||||
//Some("align/s") => Self::s(state.eval(rest.next(), ||"align/s: no content")?),
|
||||
//Some("align/e") => Self::e(state.eval(rest.next(), ||"align/e: no content")?),
|
||||
//Some("align/w") => Self::w(state.eval(rest.next(), ||"align/w: no content")?),
|
||||
//Some("align/nw") => Self::nw(state.eval(rest.next(), ||"align/nw: no content")?),
|
||||
//Some("align/ne") => Self::ne(state.eval(rest.next(), ||"align/ne: no content")?),
|
||||
//Some("align/sw") => Self::sw(state.eval(rest.next(), ||"align/sw: no content")?),
|
||||
//Some("align/se") => Self::se(state.eval(rest.next(), ||"align/se: no content")?),
|
||||
//_ => return Ok(None),
|
||||
//}))
|
||||
//}
|
||||
//Ok(None)
|
||||
//Ok(match source.exp_head().and_then(|e|e.key()) {
|
||||
//Some("either") => Some(Self(
|
||||
//source.exp_tail().and_then(|t|t.get(0)).map(|x|state.eval(x, ||"when: no condition"))?,
|
||||
//source.exp_tail().and_then(|t|t.get(1)).map(|x|state.eval(x, ||"when: no content 1"))?,
|
||||
//source.exp_tail().and_then(|t|t.get(2)).map(|x|state.eval(x, ||"when: no content 2"))?,
|
||||
//)),
|
||||
//_ => None
|
||||
//})
|
||||
//if let Exp(_, mut exp) = source.value()
|
||||
//&& let Some(Ast(Key(id))) = exp.peek() && *id == *"either" {
|
||||
//let _ = exp.next();
|
||||
//return Ok(Some(Self(
|
||||
//state.eval(exp.next().unwrap(), ||"either: no condition")?,
|
||||
//state.eval(exp.next().unwrap(), ||"either: no content 1")?,
|
||||
//state.eval(exp.next().unwrap(), ||"either: no content 2")?,
|
||||
//)))
|
||||
//}
|
||||
//Ok(None)
|
||||
//Ok(match source.exp_head().and_then(|e|e.key()) {
|
||||
//Some("when") => Some(Self(
|
||||
//source.exp_tail().and_then(|t|t.get(0)).map(|x|state.eval(x, ||"when: no condition"))?,
|
||||
//source.exp_tail().and_then(|t|t.get(1)).map(|x|state.eval(x, ||"when: no content"))?,
|
||||
//)),
|
||||
//_ => None
|
||||
//})
|
||||
}
|
||||
#[cfg(test)] mod test;
|
||||
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
|
||||
|
|
|
|||
|
|
@ -49,11 +49,10 @@
|
|||
use crate::*;
|
||||
use Direction::*;
|
||||
|
||||
mod map; pub use self::map::*;
|
||||
mod memo; pub use self::memo::*;
|
||||
mod stack; pub use self::stack::*;
|
||||
mod thunk; pub use self::thunk::*;
|
||||
mod transform; //pub use self::transform::*;
|
||||
mod map; pub use self::map::*;
|
||||
mod memo; pub use self::memo::*;
|
||||
mod stack; pub use self::stack::*;
|
||||
mod thunk; pub use self::thunk::*;
|
||||
|
||||
/// Renders multiple things on top of each other,
|
||||
#[macro_export] macro_rules! lay {
|
||||
|
|
@ -223,7 +222,7 @@ pub trait BspAreas<E: Output, A: Content<E>, B: Content<E>> {
|
|||
let [x, y, w, h] = outer.center_xy([aw.max(bw), ah + bh]);
|
||||
let a = [(x + w/2.into()).minus(aw/2.into()), y, aw, ah];
|
||||
let b = [(x + w/2.into()).minus(bw/2.into()), y + ah, bw, bh];
|
||||
[a.into(), b.into(), [x, y, w, h].into()]
|
||||
[a.into(), b.into(), [x, y, w, h].into()]
|
||||
},
|
||||
North => {
|
||||
let [x, y, w, h] = outer.center_xy([aw.max(bw), ah + bh]);
|
||||
|
|
@ -380,3 +379,310 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
|||
let dy = self.dy();
|
||||
[area.x().plus(dx), area.y().plus(dy), area.w().minus(dy.plus(dy)), area.h().minus(dy.plus(dy))]
|
||||
});
|
||||
|
||||
/// Enabling the `dsl` feature implements [DslFrom] for
|
||||
/// the layout elements that are provided by this crate.
|
||||
#[cfg(feature = "dsl")] mod ops_dsl {
|
||||
use crate::*;
|
||||
use ::tengri_dsl::*;
|
||||
|
||||
//macro_rules! dsl {
|
||||
//($(
|
||||
//($Struct:ident $(<$($A:ident),+>)? $op:literal $(/)? [$($arg:ident $(:$ty:ty)?),*] $expr:expr)
|
||||
//)*) => {
|
||||
//$(
|
||||
//impl<S,$($($A),+)?> DslFrom<S> for $Struct$(<$($A),+>)? {
|
||||
//fn try_dsl_from (
|
||||
//state: &S, dsl: &impl Dsl
|
||||
//) -> Perhaps<Self> {
|
||||
//todo!()
|
||||
//}
|
||||
//}
|
||||
//)*
|
||||
//}
|
||||
//}
|
||||
|
||||
macro_rules! dsl {
|
||||
(
|
||||
$Struct:ident $(<$($A:ident),+>)?
|
||||
$op:literal $(/)? [$head: ident, $tail: ident] $expr:expr
|
||||
) => {
|
||||
impl<S,$($($A),+)?> DslFrom<S> for $Struct$(<$($A),+>)? {
|
||||
fn try_dsl_from (
|
||||
_state: &S, _dsl: &impl Dsl
|
||||
) -> Perhaps<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! dsl_ns {
|
||||
(
|
||||
$Struct:ident $(<$($A:ident),+>)?
|
||||
$op:literal $(/)? [$head: ident, $tail: ident] $expr:expr
|
||||
) => {
|
||||
impl<S,$($($A),+)?> DslFrom<S> for $Struct$(<$($A),+>)? {
|
||||
fn try_dsl_from (
|
||||
_state: &S, _dsl: &impl Dsl
|
||||
) -> Perhaps<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dsl!(When<A> "when" [_head, tail] Self(tail(0)?, tail(1)?));
|
||||
|
||||
dsl!(Either<A, B> "either" [_head, tail] Self(tail(0)?, tail(1)?, tail(2)?));
|
||||
|
||||
dsl_ns!(Align<A> "align/" [head, tail] match head {
|
||||
"c" => Self::c(tail(0)?),
|
||||
"x" => Self::x(tail(0)?),
|
||||
"y" => Self::y(tail(0)?),
|
||||
"n" => Self::n(tail(0)?),
|
||||
"s" => Self::s(tail(0)?),
|
||||
"e" => Self::e(tail(0)?),
|
||||
"w" => Self::w(tail(0)?),
|
||||
"nw" => Self::nw(tail(0)?),
|
||||
"ne" => Self::ne(tail(0)?),
|
||||
"sw" => Self::sw(tail(0)?),
|
||||
"se" => Self::se(tail(0)?),
|
||||
_ => return Err("invalid align variant".into()) });
|
||||
|
||||
dsl_ns!(Bsp<A, B> "bsp/" [head, tail] match head {
|
||||
"n" => Self::n(tail(0)?, tail(1)?),
|
||||
"s" => Self::s(tail(0)?, tail(1)?),
|
||||
"e" => Self::e(tail(0)?, tail(1)?),
|
||||
"w" => Self::w(tail(0)?, tail(1)?),
|
||||
"a" => Self::a(tail(0)?, tail(1)?),
|
||||
"b" => Self::b(tail(0)?, tail(1)?),
|
||||
_ => return Err("invalid bsp variant".into()) });
|
||||
|
||||
dsl_ns!(Fill<A> "fill/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?),
|
||||
"y" => Self::y(tail(0)?),
|
||||
"xy" => Self::xy(tail(0)?),
|
||||
_ => return Err("invalid fill variant".into()) });
|
||||
|
||||
dsl_ns!(Fixed<U, A> "fixed/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid fill variant".into()) });
|
||||
|
||||
dsl_ns!(Min<U, A> "min/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid min variant".into()) });
|
||||
|
||||
dsl_ns!(Max<U, A> "max/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid max variant".into()) });
|
||||
|
||||
dsl_ns!(Shrink<U, A> "shrink/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid min variant".into()) });
|
||||
|
||||
dsl_ns!(Expand<U, A> "expand/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid max variant".into()) });
|
||||
|
||||
dsl_ns!(Pull<U, A> "pull/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid max variant".into()) });
|
||||
|
||||
dsl_ns!(Push<U, A> "push/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid max variant".into()) });
|
||||
|
||||
dsl_ns!(Margin<U, A> "margin/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid max variant".into()) });
|
||||
|
||||
dsl_ns!(Padding<U, A> "padding/" [head, tail] match x {
|
||||
"x" => Self::x(tail(0)?, tail(1)?),
|
||||
"y" => Self::y(tail(0)?, tail(1)?),
|
||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||
_ => return Err("invalid max variant".into()) });
|
||||
|
||||
|
||||
///// The syntagm `(when :condition :content)` corresponds to a [When] layout element.
|
||||
//impl<S, A> FromDsl<S> for When<A> where bool: FromDsl<S>, A: FromDsl<S> {
|
||||
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
//source.exp_match("when", |_, tail|Ok(Some(Self(
|
||||
//FromDsl::<S>::provide(state,
|
||||
//tail.nth(0, ||"no condition".into())?, ||"no condition".into())?,
|
||||
//FromDsl::<S>::provide(state,
|
||||
//tail.nth(1, ||"no content".into())?, ||"no content".into())?,
|
||||
//))))
|
||||
//}
|
||||
//}
|
||||
///// The syntagm `(either :condition :content1 :content2)` corresponds to an [Either] layout element.
|
||||
//impl<S, A, B> FromDsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
|
||||
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
//source.exp_match("either", |_, tail|Ok(Some(Self(
|
||||
//state.eval(tail.nth(0, ||"no condition")?, ||"no condition")?,
|
||||
//state.eval(tail.nth(1, ||"no content 1")?, ||"no content 1")?,
|
||||
//state.eval(tail.nth(2, ||"no content 1")?, ||"no content 2")?,
|
||||
//))))
|
||||
//}
|
||||
//}
|
||||
///// The syntagm `(align/* :content)` corresponds to an [Align] layout element,
|
||||
///// where `*` specifies the direction of the alignment.
|
||||
//impl<S, A> FromDsl<S> for Align<A> where S: Eval<Option<Ast>, A> {
|
||||
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
//source.exp_match("align/", |head, tail|Ok(Some(match head {
|
||||
//"c" => Self::c(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"x" => Self::x(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"y" => Self::y(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"n" => Self::n(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"s" => Self::s(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"e" => Self::e(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"w" => Self::w(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"nw" => Self::nw(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"ne" => Self::ne(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"sw" => Self::sw(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//"se" => Self::se(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
|
||||
//_ => return Err("invalid align variant".into())
|
||||
//})))
|
||||
//}
|
||||
//}
|
||||
///// The syntagm `(bsp/* :content1 :content2)` corresponds to a [Bsp] layout element,
|
||||
///// where `*` specifies the direction of the split.
|
||||
//impl<S, A, B> FromDsl<S> for Bsp<A, B> where S: Eval<Option<Ast>, A> + Eval<Option<Ast>, B> {
|
||||
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
|
||||
//source.exp_match("bsp/", |head, tail|Ok(Some(match head {
|
||||
//"n" => Self::n(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
|
||||
//"s" => Self::s(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
|
||||
//"e" => Self::e(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
|
||||
//"w" => Self::w(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
|
||||
//"a" => Self::a(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
|
||||
//"b" => Self::b(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
|
||||
//_ => return Ok(None),
|
||||
//})))
|
||||
//}
|
||||
//}
|
||||
//#[cfg(feature = "dsl")] take!($Enum<A>, A|state, words|Ok(
|
||||
//if let Some(Token { value: Key(k), .. }) = words.peek() {
|
||||
//let mut base = words.clone();
|
||||
//let content = state.give_or_fail(words, ||format!("{k}: no content"))?;
|
||||
//return Ok(Some(match words.next() {
|
||||
//Some(Token{value: Key($x),..}) => Self::x(content),
|
||||
//Some(Token{value: Key($y),..}) => Self::y(content),
|
||||
//Some(Token{value: Key($xy),..}) => Self::xy(content),
|
||||
//_ => unreachable!()
|
||||
//}))
|
||||
//} else {
|
||||
//None
|
||||
//}));
|
||||
//#[cfg(feature = "dsl")] take!($Enum<U, A>, U, A|state, words|Ok(
|
||||
//if let Some(Token { value: Key($x|$y|$xy), .. }) = words.peek() {
|
||||
//let mut base = words.clone();
|
||||
//Some(match words.next() {
|
||||
//Some(Token { value: Key($x), .. }) => Self::x(
|
||||
//state.give_or_fail(words, ||"x: no unit")?,
|
||||
//state.give_or_fail(words, ||"x: no content")?,
|
||||
//),
|
||||
//Some(Token { value: Key($y), .. }) => Self::y(
|
||||
//state.give_or_fail(words, ||"y: no unit")?,
|
||||
//state.give_or_fail(words, ||"y: no content")?,
|
||||
//),
|
||||
//Some(Token { value: Key($x), .. }) => Self::xy(
|
||||
//state.give_or_fail(words, ||"xy: no unit x")?,
|
||||
//state.give_or_fail(words, ||"xy: no unit y")?,
|
||||
//state.give_or_fail(words, ||"xy: no content")?
|
||||
//),
|
||||
//_ => unreachable!(),
|
||||
//})
|
||||
//} else {
|
||||
//None
|
||||
//}));
|
||||
//if let Exp(_, exp) = source.value() {
|
||||
//let mut rest = exp.clone();
|
||||
//return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
|
||||
//Some("bsp/n") => Self::n(
|
||||
//state.eval(rest.next(), ||"bsp/n: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/n: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/s") => Self::s(
|
||||
//state.eval(rest.next(), ||"bsp/s: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/s: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/e") => Self::e(
|
||||
//state.eval(rest.next(), ||"bsp/e: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/e: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/w") => Self::w(
|
||||
//state.eval(rest.next(), ||"bsp/w: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/w: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/a") => Self::a(
|
||||
//state.eval(rest.next(), ||"bsp/a: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/a: no content 2")?,
|
||||
//),
|
||||
//Some("bsp/b") => Self::b(
|
||||
//state.eval(rest.next(), ||"bsp/b: no content 1")?,
|
||||
//state.eval(rest.next(), ||"bsp/b: no content 2")?,
|
||||
//),
|
||||
//_ => return Ok(None),
|
||||
//}))
|
||||
//}
|
||||
//Ok(None)
|
||||
//if let Exp(_, source) = source.value() {
|
||||
//let mut rest = source.clone();
|
||||
//return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
|
||||
//Some("align/c") => Self::c(state.eval(rest.next(), ||"align/c: no content")?),
|
||||
//Some("align/x") => Self::x(state.eval(rest.next(), ||"align/x: no content")?),
|
||||
//Some("align/y") => Self::y(state.eval(rest.next(), ||"align/y: no content")?),
|
||||
//Some("align/n") => Self::n(state.eval(rest.next(), ||"align/n: no content")?),
|
||||
//Some("align/s") => Self::s(state.eval(rest.next(), ||"align/s: no content")?),
|
||||
//Some("align/e") => Self::e(state.eval(rest.next(), ||"align/e: no content")?),
|
||||
//Some("align/w") => Self::w(state.eval(rest.next(), ||"align/w: no content")?),
|
||||
//Some("align/nw") => Self::nw(state.eval(rest.next(), ||"align/nw: no content")?),
|
||||
//Some("align/ne") => Self::ne(state.eval(rest.next(), ||"align/ne: no content")?),
|
||||
//Some("align/sw") => Self::sw(state.eval(rest.next(), ||"align/sw: no content")?),
|
||||
//Some("align/se") => Self::se(state.eval(rest.next(), ||"align/se: no content")?),
|
||||
//_ => return Ok(None),
|
||||
//}))
|
||||
//}
|
||||
//Ok(None)
|
||||
//Ok(match source.exp_head().and_then(|e|e.key()) {
|
||||
//Some("either") => Some(Self(
|
||||
//source.exp_tail().and_then(|t|t.get(0)).map(|x|state.eval(x, ||"when: no condition"))?,
|
||||
//source.exp_tail().and_then(|t|t.get(1)).map(|x|state.eval(x, ||"when: no content 1"))?,
|
||||
//source.exp_tail().and_then(|t|t.get(2)).map(|x|state.eval(x, ||"when: no content 2"))?,
|
||||
//)),
|
||||
//_ => None
|
||||
//})
|
||||
//if let Exp(_, mut exp) = source.value()
|
||||
//&& let Some(Ast(Key(id))) = exp.peek() && *id == *"either" {
|
||||
//let _ = exp.next();
|
||||
//return Ok(Some(Self(
|
||||
//state.eval(exp.next().unwrap(), ||"either: no condition")?,
|
||||
//state.eval(exp.next().unwrap(), ||"either: no content 1")?,
|
||||
//state.eval(exp.next().unwrap(), ||"either: no content 2")?,
|
||||
//)))
|
||||
//}
|
||||
//Ok(None)
|
||||
//Ok(match source.exp_head().and_then(|e|e.key()) {
|
||||
//Some("when") => Some(Self(
|
||||
//source.exp_tail().and_then(|t|t.get(0)).map(|x|state.eval(x, ||"when: no condition"))?,
|
||||
//source.exp_tail().and_then(|t|t.get(1)).map(|x|state.eval(x, ||"when: no content"))?,
|
||||
//)),
|
||||
//_ => None
|
||||
//})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,192 +0,0 @@
|
|||
//! [Content] items that modify the inherent
|
||||
//! dimensions of their inner [Render]ables.
|
||||
//!
|
||||
//! Transform may also react to the [Area] taked.
|
||||
//! ```
|
||||
//! use ::tengri::{output::*, tui::*};
|
||||
//! let area: [u16;4] = [10, 10, 20, 20];
|
||||
//! fn test (area: [u16;4], item: &impl Content<TuiOut>, expected: [u16;4]) {
|
||||
//! assert_eq!(Content::layout(item, area), expected);
|
||||
//! assert_eq!(Render::layout(item, area), expected);
|
||||
//! };
|
||||
//! test(area, &(), [20, 20, 0, 0]);
|
||||
//!
|
||||
//! test(area, &Fill::xy(()), area);
|
||||
//! test(area, &Fill::x(()), [10, 20, 20, 0]);
|
||||
//! test(area, &Fill::y(()), [20, 10, 0, 20]);
|
||||
//!
|
||||
//! //FIXME:test(area, &Fixed::x(4, ()), [18, 20, 4, 0]);
|
||||
//! //FIXME:test(area, &Fixed::y(4, ()), [20, 18, 0, 4]);
|
||||
//! //FIXME:test(area, &Fixed::xy(4, 4, unit), [18, 18, 4, 4]);
|
||||
//! ```
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// Defines an enum that transforms its content
|
||||
/// along either the X axis, the Y axis, or both.
|
||||
macro_rules! transform_xy {
|
||||
($x:literal $y:literal $xy:literal |$self:ident : $Enum:ident, $to:ident|$area:expr) => {
|
||||
pub enum $Enum<A> { X(A), Y(A), XY(A) }
|
||||
impl<A> $Enum<A> {
|
||||
#[inline] pub const fn x (item: A) -> Self { Self::X(item) }
|
||||
#[inline] pub const fn y (item: A) -> Self { Self::Y(item) }
|
||||
#[inline] pub const fn xy (item: A) -> Self { Self::XY(item) }
|
||||
}
|
||||
//#[cfg(feature = "dsl")] take!($Enum<A>, A|state, words|Ok(
|
||||
//if let Some(Token { value: Value::Key(k), .. }) = words.peek() {
|
||||
//let mut base = words.clone();
|
||||
//let content = state.give_or_fail(words, ||format!("{k}: no content"))?;
|
||||
//return Ok(Some(match words.next() {
|
||||
//Some(Token{value: Value::Key($x),..}) => Self::x(content),
|
||||
//Some(Token{value: Value::Key($y),..}) => Self::y(content),
|
||||
//Some(Token{value: Value::Key($xy),..}) => Self::xy(content),
|
||||
//_ => unreachable!()
|
||||
//}))
|
||||
//} else {
|
||||
//None
|
||||
//}));
|
||||
impl<E: Output, T: Content<E>> Content<E> for $Enum<T> {
|
||||
fn content (&self) -> impl Render<E> + '_ {
|
||||
match self {
|
||||
Self::X(item) => item,
|
||||
Self::Y(item) => item,
|
||||
Self::XY(item) => item,
|
||||
}
|
||||
}
|
||||
fn layout (&$self, $to: <E as Output>::Area) -> <E as Output>::Area {
|
||||
use $Enum::*;
|
||||
$area
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines an enum that parametrically transforms its content
|
||||
/// along either the X axis, the Y axis, or both.
|
||||
macro_rules! transform_xy_unit {
|
||||
($x:literal $y:literal $xy:literal |$self:ident : $Enum:ident, $to:ident|$layout:expr) => {
|
||||
pub enum $Enum<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||
impl<U, A> $Enum<U, A> {
|
||||
#[inline] pub const fn x (x: U, item: A) -> Self { Self::X(x, item) }
|
||||
#[inline] pub const fn y (y: U, item: A) -> Self { Self::Y(y, item) }
|
||||
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self { Self::XY(x, y, item) }
|
||||
}
|
||||
//#[cfg(feature = "dsl")] take!($Enum<U, A>, U, A|state, words|Ok(
|
||||
//if let Some(Token { value: Value::Key($x|$y|$xy), .. }) = words.peek() {
|
||||
//let mut base = words.clone();
|
||||
//Some(match words.next() {
|
||||
//Some(Token { value: Value::Key($x), .. }) => Self::x(
|
||||
//state.give_or_fail(words, ||"x: no unit")?,
|
||||
//state.give_or_fail(words, ||"x: no content")?,
|
||||
//),
|
||||
//Some(Token { value: Value::Key($y), .. }) => Self::y(
|
||||
//state.give_or_fail(words, ||"y: no unit")?,
|
||||
//state.give_or_fail(words, ||"y: no content")?,
|
||||
//),
|
||||
//Some(Token { value: Value::Key($x), .. }) => Self::xy(
|
||||
//state.give_or_fail(words, ||"xy: no unit x")?,
|
||||
//state.give_or_fail(words, ||"xy: no unit y")?,
|
||||
//state.give_or_fail(words, ||"xy: no content")?
|
||||
//),
|
||||
//_ => unreachable!(),
|
||||
//})
|
||||
//} else {
|
||||
//None
|
||||
//}));
|
||||
impl<E: Output, T: Content<E>> Content<E> for $Enum<E::Unit, T> {
|
||||
fn layout (&$self, $to: E::Area) -> E::Area {
|
||||
$layout.into()
|
||||
}
|
||||
fn content (&self) -> impl Render<E> + '_ {
|
||||
use $Enum::*;
|
||||
Some(match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, })
|
||||
}
|
||||
}
|
||||
impl<U: Coordinate, T> $Enum<U, T> {
|
||||
#[inline] pub fn dx (&self) -> U {
|
||||
use $Enum::*;
|
||||
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
|
||||
}
|
||||
#[inline] pub fn dy (&self) -> U {
|
||||
use $Enum::*;
|
||||
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transform_xy!("fill/x" "fill/y" "fill/xy" |self: Fill, to|{
|
||||
let [x0, y0, wmax, hmax] = to.xywh();
|
||||
let [x, y, w, h] = self.content().layout(to).xywh();
|
||||
match self {
|
||||
X(_) => [x0, y, wmax, h],
|
||||
Y(_) => [x, y0, w, hmax],
|
||||
XY(_) => [x0, y0, wmax, hmax],
|
||||
}.into()
|
||||
});
|
||||
|
||||
transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
|
||||
let [x, y, w, h] = area.xywh();
|
||||
let fixed_area = match self {
|
||||
Self::X(fw, _) => [x, y, *fw, h],
|
||||
Self::Y(fh, _) => [x, y, w, *fh],
|
||||
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
||||
};
|
||||
let [x, y, w, h] = Render::layout(&self.content(), fixed_area.into()).xywh();
|
||||
let fixed_area = match self {
|
||||
Self::X(fw, _) => [x, y, *fw, h],
|
||||
Self::Y(fh, _) => [x, y, w, *fh],
|
||||
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
||||
};
|
||||
fixed_area
|
||||
});
|
||||
|
||||
transform_xy_unit!("min/x" "min/y" "min/xy"|self: Min, area|{
|
||||
let area = Render::layout(&self.content(), area);
|
||||
match self {
|
||||
Self::X(mw, _) => [area.x(), area.y(), area.w().max(*mw), area.h()],
|
||||
Self::Y(mh, _) => [area.x(), area.y(), area.w(), area.h().max(*mh)],
|
||||
Self::XY(mw, mh, _) => [area.x(), area.y(), area.w().max(*mw), area.h().max(*mh)],
|
||||
}
|
||||
});
|
||||
|
||||
transform_xy_unit!("max/x" "max/y" "max/xy"|self: Max, area|{
|
||||
let [x, y, w, h] = area.xywh();
|
||||
Render::layout(&self.content(), match self {
|
||||
Self::X(fw, _) => [x, y, *fw, h],
|
||||
Self::Y(fh, _) => [x, y, w, *fh],
|
||||
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
||||
}.into())
|
||||
});
|
||||
|
||||
transform_xy_unit!("shrink/x" "shrink/y" "shrink/xy"|self: Shrink, area|Render::layout(
|
||||
&self.content(),
|
||||
[area.x(), area.y(), area.w().minus(self.dx()), area.h().minus(self.dy())].into()));
|
||||
|
||||
transform_xy_unit!("expand/x" "expand/y" "expand/xy"|self: Expand, area|Render::layout(
|
||||
&self.content(),
|
||||
[area.x(), area.y(), area.w().plus(self.dx()), area.h().plus(self.dy())].into()));
|
||||
|
||||
transform_xy_unit!("push/x" "push/y" "push/xy"|self: Push, area|{
|
||||
let area = Render::layout(&self.content(), area);
|
||||
[area.x().plus(self.dx()), area.y().plus(self.dy()), area.w(), area.h()]
|
||||
});
|
||||
|
||||
transform_xy_unit!("pull/x" "pull/y" "pull/xy"|self: Pull, area|{
|
||||
let area = Render::layout(&self.content(), area);
|
||||
[area.x().minus(self.dx()), area.y().minus(self.dy()), area.w(), area.h()]
|
||||
});
|
||||
|
||||
transform_xy_unit!("margin/x" "margin/y" "margin/xy"|self: Margin, area|{
|
||||
let area = Render::layout(&self.content(), area);
|
||||
let dx = self.dx();
|
||||
let dy = self.dy();
|
||||
[area.x().minus(dx), area.y().minus(dy), area.w().plus(dy.plus(dy)), area.h().plus(dy.plus(dy))]
|
||||
});
|
||||
|
||||
transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
||||
let area = Render::layout(&self.content(), area);
|
||||
let dx = self.dx();
|
||||
let dy = self.dy();
|
||||
[area.x().plus(dx), area.y().plus(dy), area.w().minus(dy.plus(dy)), area.h().minus(dy.plus(dy))]
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue