tek/engine/src/output.rs

118 lines
3.7 KiB
Rust

use crate::*;
use std::marker::PhantomData;
//use std::sync::{Arc, Mutex, RwLock};
/// Rendering target
pub trait Output<E: Engine> {
/// Current output area
fn area (&self) -> E::Area;
/// Mutable pointer to area
fn area_mut (&mut self) -> &mut E::Area;
/// Render widget in area
fn place (&mut self, area: E::Area, content: &impl Content<E>);
#[inline] fn x (&self) -> E::Unit { self.area().x() }
#[inline] fn y (&self) -> E::Unit { self.area().y() }
#[inline] fn w (&self) -> E::Unit { self.area().w() }
#[inline] fn h (&self) -> E::Unit { self.area().h() }
#[inline] fn wh (&self) -> E::Size { self.area().wh().into() }
}
pub trait Content<E: Engine>: Send + Sync {
fn content (&self) -> impl Content<E> {
()
}
fn layout (&self, area: E::Area) -> E::Area {
self.content().layout(area)
}
fn render (&self, output: &mut E::Output) {
output.place(self.layout(output.area()), &self.content())
}
}
/// The platonic ideal unit of [Content]: total emptiness at dead center.
impl<E: Engine> Content<E> for () {
fn layout (&self, area: E::Area) -> E::Area {
let [x, y] = area.center();
[x, y, 0.into(), 0.into()].into()
}
fn render (&self, _: &mut E::Output) {}
}
impl<E: Engine, T: Content<E>> Content<E> for &T {
fn content (&self) -> impl Content<E> {
(*self).content()
}
fn layout (&self, area: E::Area) -> E::Area {
(*self).layout(area)
}
fn render (&self, output: &mut E::Output) {
(*self).render(output)
}
}
impl<E: Engine, T: Content<E>> Content<E> for Option<T> {
fn content (&self) -> impl Content<E> {
self.as_ref()
.map(|content|content.content())
}
fn layout (&self, area: E::Area) -> E::Area {
self.as_ref()
.map(|content|content.layout(area))
.unwrap_or([0.into(), 0.into(), 0.into(), 0.into(),].into())
}
fn render (&self, output: &mut E::Output) {
self.as_ref()
.map(|content|content.render(output));
}
}
pub struct Thunk<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync>(F, PhantomData<E>);
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Thunk<E, T, F> {
pub fn new (thunk: F) -> Self {
Self(thunk, Default::default())
}
}
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Content<E> for Thunk<E, T, F> {
fn content (&self) -> impl Content<E> {
(self.0)()
}
}
#[macro_export] macro_rules! render {
(($self:ident:$Struct:ty) => $content:expr) => {
impl <E: Engine> Content<E> for $Struct {
fn content (&$self) -> impl Content<E> { Some($content) }
}
};
(|$self:ident:$Struct:ident $(<
$($L:lifetime),* $($T:ident $(:$Trait:path)?),*
>)?, $to:ident | $render:expr) => {
impl <$($($L),*)? E: Engine, $($T$(:$Trait)?),*> Content<E>
for $Struct $(<$($L),* $($T),*>>)? {
fn render (&$self, $to: &mut E::Output) { $render }
}
};
($Engine:ty:
($self:ident:$Struct:ident $(<$(
$($L:lifetime)? $($T:ident)? $(:$Trait:path)?
),+>)?) => $content:expr
) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine>
for $Struct $(<$($($L)? $($T)?),+>)? {
fn content (&$self) -> impl Content<$Engine> { $content }
}
};
($Engine:ty:
|$self:ident : $Struct:ident $(<$(
$($L:lifetime)? $($T:ident)? $(:$Trait:path)?
),+>)?, $to:ident| $render:expr
) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine>
for $Struct $(<$($($L)? $($T)?),+>)? {
fn render (&$self, $to: &mut <$Engine as Engine>::Output) { $render }
}
};
}