mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
118 lines
3.7 KiB
Rust
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 }
|
|
}
|
|
};
|
|
}
|