generalize EdnItem.

maybe should rename it to Atom? ~90 instances of it
This commit is contained in:
🪞👃🪞 2025-01-17 19:47:35 +01:00
parent 1b9da07280
commit 143cd24e09
20 changed files with 314 additions and 286 deletions

74
output/src/op_cond.rs Normal file
View file

@ -0,0 +1,74 @@
use crate::*;
/// Show an item only when a condition is true.
pub struct When<E, A>(pub PhantomData<E>, pub bool, pub A);
impl<E, A> When<E, A> {
pub fn new (c: bool, a: A) -> Self {
Self(Default::default(), c, a)
}
}
impl<'a, E: Output + 'a, T: EdnViewData<'a, E>> TryFromEdn<'a, T> for When<E, RenderBox<'a, E>> {
fn try_from_edn (
state: &'a T, head: &EdnItem<impl AsRef<str>>, tail: &'a [EdnItem<impl AsRef<str>>]
) -> Option<Self> {
use EdnItem::*;
if let (Key("when"), [condition, content]) = (head.to_ref(), tail) {
Some(Self(
Default::default(),
state.get_bool(condition).expect("when: no condition"),
state.get_content(content).expect("when: no content")
))
} else {
None
}
}
}
impl<E: Output, A: Render<E>> Content<E> for When<E, A> {
fn layout (&self, to: E::Area) -> E::Area {
let Self(_, cond, item) = self;
let mut area = E::Area::zero();
if *cond {
let item_area = item.layout(to);
area[0] = item_area.x();
area[1] = item_area.y();
area[2] = item_area.w();
area[3] = item_area.h();
}
area.into()
}
fn render (&self, to: &mut E) {
let Self(_, cond, item) = self;
if *cond { item.render(to) }
}
}
/// Show one item if a condition is true and another if the condition is false
pub struct Either<E, A, B>(pub PhantomData<E>, pub bool, pub A, pub B);
impl<E, A, B> Either<E, A, B> {
pub fn new (c: bool, a: A, b: B) -> Self {
Self(Default::default(), c, a, b)
}
}
impl<'a, E: Output + 'a, T: EdnViewData<'a, E>> TryFromEdn<'a, T> for Either<E, RenderBox<'a, E>, RenderBox<'a, E>> {
fn try_from_edn (state: &'a T, head: &EdnItem<impl AsRef<str>>, tail: &'a [EdnItem<impl AsRef<str>>]) -> Option<Self> {
use EdnItem::*;
if let (Key("either"), [condition, content, alternative]) = (head.to_ref(), tail) {
Some(Self::new(
state.get_bool(condition).expect("either: no condition"),
state.get_content(content).expect("either: no content"),
state.get_content(alternative).expect("either: no alternative")
))
} else {
None
}
}
}
impl<E: Output, A: Render<E>, B: Render<E>> Content<E> for Either<E, A, B> {
fn layout (&self, to: E::Area) -> E::Area {
let Self(_, cond, a, b) = self;
if *cond { a.layout(to) } else { b.layout(to) }
}
fn render (&self, to: &mut E) {
let Self(_, cond, a, b) = self;
if *cond { a.render(to) } else { b.render(to) }
}
}