genericize layout rendering

This commit is contained in:
🪞👃🪞 2024-09-06 23:32:13 +03:00
parent 1d21071c86
commit 4855609a7d
8 changed files with 167 additions and 118 deletions

View file

@ -6,7 +6,7 @@ pub enum Collected<'a, E: Engine> {
}
impl<'a, E: Engine> Render<E> for Collected<'a, E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
match self {
Self::Box(item) => (*item).render(to),
Self::Ref(item) => (*item).render(to),

View file

@ -1,7 +1,7 @@
use crate::*;
/// Compute drawing area before rendering
pub trait Layout<E: Engine> {
pub trait Layout<E: Engine>: Render<E> {
fn layout (&self, area: impl Rectangle<E::Unit>) -> Perhaps<impl Rectangle<E::Unit>>;
}
/// Enforce minimum size of drawing area
@ -98,3 +98,73 @@ impl<E: Engine, L: Layout<E>> Layout<E> for Offset<E::Unit, L> {
}
}
}
impl<E: Engine, R: Render<E> + Layout<E>> Render<E> for Min<E::Unit, R> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.layout(to.area())?
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
.map(|to|match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}.render(to))
.transpose()
.map(|x|x.flatten())
}
}
impl<E: Engine, R: Render<E> + Layout<E>> Render<E> for Max<E::Unit, R> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.layout(to.area())?
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
.map(|to|match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}.render(to))
.transpose()
.map(|x|x.flatten())
}
}
impl<E: Engine, R: Render<E> + Layout<E>> Render<E> for Inset<E::Unit, R> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.layout(to.area())?
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
.map(|to|match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}.render(to))
.transpose()
.map(|x|x.flatten())
}
}
impl<E: Engine, R: Render<E> + Layout<E>> Render<E> for Outset<E::Unit, R> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.layout(to.area())?
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
.map(|to|match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}.render(to))
.transpose()
.map(|x|x.flatten())
}
}
impl<E: Engine, R: Render<E> + Layout<E>> Render<E> for Offset<E::Unit, R> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.layout(to.area())?
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
.map(|to|match self {
Self::X(_, inner) => inner,
Self::Y(_, inner) => inner,
Self::XY(_, _, inner) => inner,
}.render(to))
.transpose()
.map(|x|x.flatten())
}
}

View file

@ -2,12 +2,12 @@ use crate::*;
/// Render to output.
pub trait Render<E: Engine>: Send + Sync {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered>;
fn render (&self, to: &mut E) -> Perhaps<E::Rendered>;
}
/// Options can be rendered optionally.
impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
match self {
Some(component) => component.render(to),
None => Ok(None)
@ -17,42 +17,42 @@ impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
/// Boxed references can be rendered.
impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to)
}
}
/// Immutable references can be rendered.
impl<R, E: Engine> Render<E> for &R where R: Render<E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(*self).render(to)
}
}
/// Mutable references can be rendered.
impl<R, E: Engine> Render<E> for &mut R where R: Render<E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to)
}
}
/// Counted references can be rendered.
impl<R, E: Engine> Render<E> for Arc<R> where R: Render<E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.as_ref().render(to)
}
}
/// References behind a [Mutex] can be rendered.
impl<R, E: Engine> Render<E> for Mutex<R> where R: Render<E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.lock().unwrap().render(to)
}
}
/// References behind a [RwLock] can be rendered.
impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.read().unwrap().render(to)
}
}
@ -62,8 +62,8 @@ impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> {
/// Rendering unboxed closures should also be possible;
/// but in practice implementing the trait for an unboxed
/// `Fn` closure causes an impl conflict.
impl<'a, E: Engine> Render<E> for Box<dyn Fn(&mut E::RenderInput) -> Perhaps<E::Rendered> + Send + Sync + 'a> {
fn render (&self, to: &mut E::RenderInput) -> Perhaps<E::Rendered> {
impl<'a, E: Engine> Render<E> for Box<dyn Fn(&mut E) -> Perhaps<E::Rendered> + Send + Sync + 'a> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(*self)(to)
}
}