diff --git a/output/src/layout_align.rs b/output/src/layout_align.rs
index 59eda80..9991d1d 100644
--- a/output/src/layout_align.rs
+++ b/output/src/layout_align.rs
@@ -48,33 +48,36 @@ impl Align {
#[inline] pub const fn se (a: A) -> Self { Self(Alignment::SE, a) }
}
-impl> Content for Align {
- fn content (&self) -> impl Render + '_ {
- &self.1
- }
+impl> Render for Align {
fn layout (&self, on: E::Area) -> E::Area {
+ self.0.align(on, &self.1)
+ }
+ fn render (&self, to: &mut E) {
+ to.place(self.layout(to.area()), &self.1)
+ }
+}
+
+impl Alignment {
+ fn align (&self, on: E::Area, content: impl Render) -> E::Area {
use Alignment::*;
- let it = Render::layout(&self.content(), on).xywh();
+ let it = content.layout(on).xywh();
let cx = on.x()+(on.w().minus(it.w())/2.into());
let cy = on.y()+(on.h().minus(it.h())/2.into());
let fx = (on.x()+on.w()).minus(it.w());
let fy = (on.y()+on.h()).minus(it.h());
- let [x, y] = match self.0 {
- Center => [cx, cy],
- X => [cx, it.y()],
- Y => [it.x(), cy],
- NW => [on.x(), on.y()],
- N => [cx, on.y()],
- NE => [fx, on.y()],
- W => [on.x(), cy],
- E => [fx, cy],
- SW => [on.x(), fy],
- S => [cx, fy],
- SE => [fx, fy],
- }.into();
+ let [x, y] = match self {
+ Center => [cx, cy],
+ X => [cx, it.y()],
+ Y => [it.x(), cy],
+ NW => [on.x(), on.y()],
+ N => [cx, on.y()],
+ NE => [fx, on.y()],
+ W => [on.x(), cy],
+ E => [fx, cy],
+ SW => [on.x(), fy],
+ S => [cx, fy],
+ SE => [fx, fy],
+ };
[x, y, it.w(), it.h()].into()
}
- fn render (&self, to: &mut E) {
- to.place(Content::layout(self, to.area()), &self.content())
- }
}
diff --git a/output/src/layout_bsp.rs b/output/src/layout_bsp.rs
index 0272d17..73d6882 100644
--- a/output/src/layout_bsp.rs
+++ b/output/src/layout_bsp.rs
@@ -15,7 +15,7 @@ impl Bsp {
#[inline] pub const fn a (a: A, b: B) -> Self { Self(Above, a, b) }
#[inline] pub const fn b (a: A, b: B) -> Self { Self(Below, a, b) }
}
-impl, B: Content> Content for Bsp {
+impl, B: Render> Render for Bsp {
fn layout (&self, outer: E::Area) -> E::Area { let [_, _, c] = self.areas(outer); c }
fn render (&self, to: &mut E) {
let [area_a, area_b, _] = self.areas(to.area());
@@ -26,11 +26,11 @@ impl, B: Content> Content for Bsp {
}
}
}
-impl, B: Content> BspAreas for Bsp {
+impl, B: Render> BspAreas for Bsp {
fn direction (&self) -> Direction { self.0 }
fn contents (&self) -> (&A, &B) { (&self.1, &self.2) }
}
-pub trait BspAreas, B: Content> {
+pub trait BspAreas, B: Render> {
fn direction (&self) -> Direction;
fn contents (&self) -> (&A, &B);
fn areas (&self, outer: E::Area) -> [E::Area;3] {
diff --git a/output/src/layout_cond.rs b/output/src/layout_cond.rs
index 1da4925..7a7bdc0 100644
--- a/output/src/layout_cond.rs
+++ b/output/src/layout_cond.rs
@@ -6,7 +6,7 @@ impl When {
/// Create a binary condition.
pub const fn new (c: bool, a: A) -> Self { Self(c, a) }
}
-impl> Content for When {
+impl> Render for When {
fn layout (&self, to: E::Area) -> E::Area {
let Self(cond, item) = self;
let mut area = E::Area::zero();
@@ -31,7 +31,7 @@ impl Either {
/// Create a ternary view condition.
pub const fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b) }
}
-impl, B: Render> Content for Either {
+impl, B: Render> Render for Either {
fn layout (&self, to: E::Area) -> E::Area {
let Self(cond, a, b) = self;
if *cond { a.layout(to) } else { b.layout(to) }
diff --git a/output/src/layout_map.rs b/output/src/layout_map.rs
index a194c06..4c8494c 100644
--- a/output/src/layout_map.rs
+++ b/output/src/layout_map.rs
@@ -66,7 +66,7 @@ impl_map_direction!(south, y, n);
impl_map_direction!(west, x, e);
impl_map_direction!(north, y, s);
-impl<'a, E, A, B, I, F, G> Content for Map where
+impl<'a, E, A, B, I, F, G> Render for Map where
E: Output,
B: Render,
I: Iterator- + Send + Sync + 'a,
@@ -94,7 +94,7 @@ impl<'a, E, A, B, I, F, G> Content for Map where
fn render (&self, to: &mut E) {
let Self { get_iter, get_item, .. } = self;
let mut index = 0;
- let area = Content::layout(self, to.area());
+ let area = Render::layout(self, to.area());
for item in get_iter() {
let item = get_item(item, index);
//to.place(area.into(), &item);
@@ -107,24 +107,24 @@ impl<'a, E, A, B, I, F, G> Content for Map where
#[inline] pub fn map_south(
item_offset: O::Unit,
item_height: O::Unit,
- item: impl Content
-) -> impl Content {
+ item: impl Render
+) -> impl Render {
Push::y(item_offset, Fixed::y(item_height, Fill::x(item)))
}
#[inline] pub fn map_south_west(
item_offset: O::Unit,
item_height: O::Unit,
- item: impl Content
-) -> impl Content {
+ item: impl Render
+) -> impl Render {
Push::y(item_offset, Align::nw(Fixed::y(item_height, Fill::x(item))))
}
#[inline] pub fn map_east(
item_offset: O::Unit,
item_width: O::Unit,
- item: impl Content
-) -> impl Content {
+ item: impl Render
+) -> impl Render {
Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item))))
}
diff --git a/output/src/layout_stack.rs b/output/src/layout_stack.rs
index 95f8c82..c316c39 100644
--- a/output/src/layout_stack.rs
+++ b/output/src/layout_stack.rs
@@ -1,43 +1,44 @@
use crate::*;
use Direction::*;
-pub struct Stack<'x, E, F> {
- __: PhantomData<&'x E>,
+pub struct Stack<'x, E, F1> {
+ __: PhantomData<&'x (E, F1)>,
direction: Direction,
- callback: F
+ callback: F1
}
-impl<'x, E, F: Fn(&mut dyn FnMut(&dyn Render)) + 'x> Stack<'x, E, F> {
- pub fn new (direction: Direction, callback: F) -> Self {
+
+impl<'x, E, F1> Stack<'x, E, F1> {
+ pub fn new (direction: Direction, callback: F1) -> Self {
Self { direction, callback, __: Default::default(), }
}
- pub fn above (callback: F) -> Self {
+ pub fn above (callback: F1) -> Self {
Self::new(Above, callback)
}
- pub fn below (callback: F) -> Self {
+ pub fn below (callback: F1) -> Self {
Self::new(Below, callback)
}
- pub fn north (callback: F) -> Self {
+ pub fn north (callback: F1) -> Self {
Self::new(North, callback)
}
- pub fn south (callback: F) -> Self {
+ pub fn south (callback: F1) -> Self {
Self::new(South, callback)
}
- pub fn east (callback: F) -> Self {
+ pub fn east (callback: F1) -> Self {
Self::new(East, callback)
}
- pub fn west (callback: F) -> Self {
+ pub fn west (callback: F1) -> Self {
Self::new(West, callback)
}
}
-impl<'x, E: Output, F: Fn(&mut dyn FnMut(&dyn Render)) + 'x> Content for Stack<'x, E, F> {
+
+impl<'x, E: Output, F1: Fn(&mut dyn FnMut(&dyn Render))> Render for Stack<'x, E, F1> {
fn layout (&self, to: E::Area) -> E::Area {
let state = StackLayoutState::::new(self.direction, to);
- let mut adder = |component: &dyn Render|{
+ (self.callback)(&mut |component: &dyn Render|{
let StackLayoutState { x, y, w_remaining, h_remaining, .. } = *state.borrow();
let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
state.borrow_mut().grow(w, h);
- };
- (self.callback)(&mut adder);
+ });
let StackLayoutState { w_used, h_used, .. } = *state.borrow();
match self.direction {
North | West => { todo!() },
@@ -48,13 +49,12 @@ impl<'x, E: Output, F: Fn(&mut dyn FnMut(&dyn Render)) + 'x> Content for S
fn render (&self, to: &mut E) {
let state = StackLayoutState::::new(self.direction, to.area());
let to = Rc::new(RefCell::new(to));
- let mut adder = |component: &dyn Render|{
+ (self.callback)(&mut |component: &dyn Render|{
let StackLayoutState { x, y, w_remaining, h_remaining, .. } = *state.borrow();
let layout = component.layout([x, y, w_remaining, h_remaining].into());
state.borrow_mut().grow(layout.w(), layout.h());
to.borrow_mut().place(layout, component);
- };
- (self.callback)(&mut adder);
+ });
}
}
@@ -115,7 +115,7 @@ impl StackLayoutState {
//Self { direction, callback, __: Default::default(), }
//}
//}
-//impl<'a, E, F1> Content for Stack<'a, E, F1> where
+//impl<'a, E, F1> Render for Stack<'a, E, F1> where
//E: Output, F1: Fn(&mut dyn FnMut(&'a dyn Render)) + Send + Sync,
//{
//fn layout (&self, to: E::Area) -> E::Area {
diff --git a/output/src/layout_xy.rs b/output/src/layout_xy.rs
index 93d2eea..52d99a6 100644
--- a/output/src/layout_xy.rs
+++ b/output/src/layout_xy.rs
@@ -2,9 +2,8 @@
//! ```
//! use ::tengri::{output::*, tui::*};
//! let area: [u16;4] = [10, 10, 20, 20];
-//! fn test (area: [u16;4], item: &impl Content, expected: [u16;4]) {
-//! assert_eq!(Content::layout(item, area), expected);
-//! assert_eq!(Render::layout(item, area), expected);
+//! fn test (area: [u16;4], item: &impl Render, expected: [u16;4]) {
+//! assert_eq!(item.layout(area), expected);
//! };
//! test(area, &(), [20, 20, 0, 0]);
//!
@@ -28,18 +27,20 @@ macro_rules! transform_xy {
#[inline] pub const fn y (item: A) -> Self { Self::Y(item) }
#[inline] pub const fn xy (item: A) -> Self { Self::XY(item) }
}
- impl> Content for $Enum {
- fn content (&self) -> impl Render + '_ {
- match self {
- Self::X(item) => item,
- Self::Y(item) => item,
- Self::XY(item) => item,
- }
+ impl> Content for $Enum {
+ fn content (&self) -> Option + '_> {
+ use $Enum::*;
+ Some(match self { X(item) | Y(item) | XY(item) => item, })
}
+ }
+ impl> Render for $Enum {
fn layout (&$self, $to: ::Area) -> ::Area {
use $Enum::*;
$area
}
+ fn render (&self, output: &mut E) {
+ output.place(self.layout(output.area()), &self.content())
+ }
}
}
}
@@ -54,13 +55,18 @@ macro_rules! transform_xy_unit {
#[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) }
}
- impl> Content for $Enum {
+ impl> Content for $Enum {
+ fn content (&self) -> Option + '_> {
+ use $Enum::*;
+ Some(match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, })
+ }
+ }
+ impl> Render for $Enum {
fn layout (&$self, $to: E::Area) -> E::Area {
$layout.into()
}
- fn content (&self) -> impl Render + '_ {
- use $Enum::*;
- Some(match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, })
+ fn render (&self, output: &mut E) {
+ output.place(self.layout(output.area()), &self.content())
}
}
impl $Enum {
@@ -88,12 +94,11 @@ transform_xy!("fill/x" "fill/y" "fill/xy" |self: Fill, to|{
transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
let [x, y, w, h] = area.xywh();
- let fixed_area = match self {
+ let [x, y, w, h] = self.content().layout(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();
+ }.into()).xywh();
let fixed_area = match self {
Self::X(fw, _) => [x, y, *fw, h],
Self::Y(fh, _) => [x, y, w, *fh],
@@ -103,51 +108,41 @@ transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
});
transform_xy_unit!("min/x" "min/y" "min/xy"|self: Min, area|{
- let area = Render::layout(&self.content(), area);
+ let [x, y, w, h] = self.content().layout(area).xywh();
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)],
- }
-});
+ Self::X(mw, _) => [x, y, w.max(*mw), h],
+ Self::Y(mh, _) => [x, y, w, h.max(*mh)],
+ Self::XY(mw, mh, _) => [x, y, w.max(*mw), 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.content().layout(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())
-});
+ 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(),
+transform_xy_unit!("shrink/x" "shrink/y" "shrink/xy"|self: Shrink, area|self.content().layout(
[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(),
+transform_xy_unit!("expand/x" "expand/y" "expand/xy"|self: Expand, area|self.content().layout(
[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()]
-});
+ let area = self.content().layout(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()]
-});
+ let area = self.content().layout(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 area = self.content().layout(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))]
-});
+ [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 area = self.content().layout(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))]
-});
+ [area.x().plus(dx), area.y().plus(dy), area.w().minus(dy.plus(dy)), area.h().minus(dy.plus(dy))] });
diff --git a/output/src/output.rs b/output/src/output.rs
index 4eb1036..bc9e2b9 100644
--- a/output/src/output.rs
+++ b/output/src/output.rs
@@ -1,5 +1,4 @@
use crate::*;
-use std::ops::Deref;
/// Render target.
pub trait Output: Send + Sync + Sized {
diff --git a/output/src/output_content.rs b/output/src/output_content.rs
index ef199db..392f49c 100644
--- a/output/src/output_content.rs
+++ b/output/src/output_content.rs
@@ -1,88 +1,67 @@
use crate::*;
/// Composable renderable with static dispatch.
-pub trait Content {
- /// Return a [Render]able of a specific type.
- fn content (&self) -> impl Render + '_ {
- ()
- }
- /// Perform layout. By default, delegates to [Self::content].
- fn layout (&self, area: E::Area) -> E::Area {
- self.content().layout(area)
- }
- /// Draw to output. By default, delegates to [Self::content].
- fn render (&self, output: &mut E) {
- self.content().render(output)
- }
-}
-
-/// Every pointer to [Content] is a [Content].
-impl> Content for &C {
- fn content (&self) -> impl Render + '_ { (*self).content() }
- fn layout (&self, area: E::Area) -> E::Area { (*self).layout(area) }
- fn render (&self, output: &mut E) { (*self).render(output) }
+pub trait Content: Sized {
+ /// Return opaque [Render]able.
+ fn content (&self) -> Option + '_> { Option::<()>::None }
}
/// The platonic ideal unit of [Content]: total emptiness at dead center (e=1vg^sqrt(-1))
-impl Content for () {
- fn layout (&self, area: E::Area) -> E::Area { area.center().to_area_pos().into() }
- fn render (&self, _: &mut E) {}
+impl Content for () {}
+
+impl Content for fn(&mut E) {
+ fn content (&self) -> Option + '_> {
+ Some(self)
+ }
+}
+
+impl> Content for fn()->T {
+ fn content (&self) -> Option + '_> {
+ Some(self())
+ }
}
impl> Content for Option {
- fn content (&self) -> impl Render + '_ {
- self.as_ref()
- }
- 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) {
- self.as_ref()
- .map(|content|content.render(output));
+ fn content (&self) -> Option + '_> {
+ if let Some(content) = self {
+ content.content()
+ } else {
+ None
+ }
}
}
/// You can render from a box.
impl Content for RenderBox {
- fn content (&self) -> impl Render + '_ { self.deref() }
- //fn boxed <'b> (self) -> RenderBox<'b, E> where Self: Sized + 'b { self }
+ fn content (&self) -> Option + '_> {
+ Some(self.deref())
+ }
}
/// You can render from an opaque pointer.
impl Content for &dyn Render where Self: Sized {
- fn content (&self) -> impl Render + '_ {
+ fn content (&self) -> Option + '_> {
#[allow(suspicious_double_ref_op)]
- self.deref()
- }
- fn layout (&self, area: E::Area) -> E::Area {
- #[allow(suspicious_double_ref_op)]
- Render::layout(self.deref(), area)
- }
- fn render (&self, output: &mut E) {
- #[allow(suspicious_double_ref_op)]
- Render::render(self.deref(), output)
+ Some(self.deref())
}
}
-/// Implement [Content] with custom rendering for a struct.
-#[macro_export] macro_rules! render {
- (|$self:ident:$Struct:ident $(<
- $($L:lifetime),* $($T:ident $(:$Trait:path)?),*
- >)?, $to:ident | $render:expr) => {
- impl <$($($L),*)? E: Output, $($T$(:$Trait)?),*> Content
- for $Struct $(<$($L),* $($T),*>>)? {
- fn render (&$self, $to: &mut E) { $render }
+/// Implement composable content for a struct.
+#[macro_export] macro_rules! content {
+ // Implement for all [Output]s.
+ (|$self:ident:$Struct:ty| $content:expr) => {
+ impl Content for $Struct {
+ fn content (&$self) -> impl Render + '_ { Some($content) }
}
};
+ // Implement for specific [Output].
($Output:ty:|
$self:ident:
- $Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?, $to:ident
- |$render:expr) => {
+ $Struct:ident$(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?
+ |$content:expr) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output>
for $Struct $(<$($($L)? $($T)?),+>)? {
- fn render (&$self, $to: &mut $Output) { $render }
+ fn content (&$self) -> impl Render<$Output> + '_ { $content }
}
};
}
diff --git a/output/src/output_render.rs b/output/src/output_render.rs
index 3027b0c..d1f97a9 100644
--- a/output/src/output_render.rs
+++ b/output/src/output_render.rs
@@ -2,46 +2,92 @@ use crate::*;
/// Renderable with dynamic dispatch.
pub trait Render {
- /// Compute layout.
- fn layout (&self, area: E::Area) -> E::Area;
/// Write data to display.
fn render (&self, output: &mut E);
+ /// Compute layout.
+ fn layout (&self, area: E::Area) -> E::Area { area }
/// Perform type erasure, turning `self` into an opaque [RenderBox].
fn boxed <'a> (self) -> Box + 'a> where Self: Sized + 'a {
Box::new(self) as Box + 'a>
}
+ /// Perform type erasure, turning `self` into an opaque [Rc].
+ fn rc <'a> (self) -> Rc + 'a> where Self: Sized + 'a {
+ Rc::new(self) as Rc + 'a>
+ }
}
-/// Every [Content] is also a [Render].
-/// However, the converse does not hold true.
-/// Instead, the [Content::content] method returns an
-/// opaque [Render] pointer.
-impl> Render for C {
- fn layout (&self, area: E::Area) -> E::Area { Content::layout(self, area) }
- fn render (&self, output: &mut E) { Content::render(self, output) }
+impl Render for () {
+ fn render (&self, _: &mut E) {}
}
-/// Opaque pointer to a renderable living on the heap.
+impl Render for fn(&mut E) {
+ fn render (&self, output: &mut E) {
+ self(output)
+ }
+}
+
+impl<'x, E: Output> Render for &(dyn Render + 'x) {
+ fn render (&self, output: &mut E) {
+ (*self).render(output)
+ }
+}
+
+impl> Render for Box {
+ fn render (&self, output: &mut E) {
+ (**self).render(output)
+ }
+}
+
+impl> Render for Option {
+ fn render (&self, output: &mut E) {
+ if let Some(render) = self {
+ render.render(output)
+ }
+ }
+}
+
+impl> Render for &R {
+ fn render (&self, output: &mut E) {
+ (*self).render(output)
+ }
+}
+
+impl> Render for &mut R {
+ fn render (&self, output: &mut E) {
+ (**self).render(output)
+ }
+}
+
+impl> Render for [R] {
+ fn render (&self, output: &mut E) {
+ for render in self.iter() {
+ render.render(output)
+ }
+ }
+}
+
+/// Opaque pointer to a renderable that lives on the heap.
///
/// Return this from [Content::content] to use dynamic dispatch.
pub type RenderBox = Box>;
-/// Implement [Content] with composable content for a struct.
-#[macro_export] macro_rules! content {
- // Implement for all [Output]s.
- (|$self:ident:$Struct:ty| $content:expr) => {
- impl Content for $Struct {
- fn content (&$self) -> impl Render + '_ { Some($content) }
+/// Implement custom rendering for a struct.
+#[macro_export] macro_rules! render {
+ (|$self:ident:$Struct:ident $(<
+ $($L:lifetime),* $($T:ident $(:$Trait:path)?),*
+ >)?, $to:ident | $render:expr) => {
+ impl <$($($L),*)? E: Output, $($T$(:$Trait)?),*> Content
+ for $Struct $(<$($L),* $($T),*>>)? {
+ fn render (&$self, $to: &mut E) { $render }
}
};
- // Implement for specific [Output].
($Output:ty:|
$self:ident:
- $Struct:ident$(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?
- |$content:expr) => {
+ $Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?, $to:ident
+ |$render:expr) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output>
for $Struct $(<$($($L)? $($T)?),+>)? {
- fn content (&$self) -> impl Render<$Output> + '_ { $content }
+ fn render (&$self, $to: &mut $Output) { $render }
}
};
}
diff --git a/output/src/output_thunk.rs b/output/src/output_thunk.rs
index 5a2cb5c..f505c38 100644
--- a/output/src/output_thunk.rs
+++ b/output/src/output_thunk.rs
@@ -11,65 +11,19 @@ impl, F: Fn()->T> Thunk {
}
}
impl, F: Fn()->T> Content for Thunk {
- fn content (&self) -> impl Render { (self.1)() }
-}
-
-/// Lazily-evaluated [Render]able with
-/// mandatory stack allocation and dynamic dispatch.
-pub struct ThunkBox(
- PhantomData,
- BoxBox>>,
-);
-impl ThunkBox {
- pub const fn new (thunk: BoxBox>>) -> Self {
- Self(PhantomData, thunk)
+ fn content (&self) -> Option> {
+ Some((self.1)())
}
}
-impl Content for ThunkBox {
- fn content (&self) -> impl Render { (&self.1)() }
-}
-impl FromBox>>> for ThunkBox {
- fn from (f: BoxBox>>) -> Self {
- Self(PhantomData, f)
- }
-}
-
-//impl<'a, E: Output, F: Fn()->Box + 'a> + 'a> From for ThunkBox<'a, E> {
- //fn from (f: F) -> Self {
- //Self(Default::default(), Box::new(f))
- //}
-//}
pub struct ThunkRender(PhantomData, F);
impl ThunkRender {
pub fn new (render: F) -> Self { Self(PhantomData, render) }
}
-impl Content for ThunkRender {
+impl Render for ThunkRender {
fn render (&self, to: &mut E) { (self.1)(to) }
}
-pub struct ThunkLayout<
- E: Output,
- F1: Fn(E::Area)->E::Area,
- F2: Fn(&mut E)
->(
- PhantomData,
- F1,
- F2
-);
-implE::Area, F2: Fn(&mut E)> ThunkLayout {
- pub fn new (layout: F1, render: F2) -> Self { Self(PhantomData, layout, render) }
-}
-impl Content for ThunkLayout
-where
- E: Output,
- F1: Fn(E::Area)->E::Area,
- F2: Fn(&mut E)
-{
- fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) }
- fn render (&self, to: &mut E) { (self.2)(to) }
-}
-
#[derive(Debug, Default)] pub struct Memo {
pub value: T,
pub view: Arc>
diff --git a/output/src/space.rs b/output/src/space.rs
deleted file mode 100644
index 3e850fd..0000000
--- a/output/src/space.rs
+++ /dev/null
@@ -1,281 +0,0 @@
-use crate::*;
-use Direction::*;
-
-/// A cardinal direction.
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[cfg_attr(test, derive(Arbitrary))]
-pub enum Direction {
- North, South, East, West, Above, Below
-}
-
-impl Direction {
- pub fn split_fixed (self, area: impl Area, a: N) -> ([N;4],[N;4]) {
- let [x, y, w, h] = area.xywh();
- match self {
- North => ([x, y.plus(h).minus(a), w, a], [x, y, w, h.minus(a)]),
- South => ([x, y, w, a], [x, y.plus(a), w, h.minus(a)]),
- East => ([x, y, a, h], [x.plus(a), y, w.minus(a), h]),
- West => ([x.plus(w).minus(a), y, a, h], [x, y, w.minus(a), h]),
- Above | Below => (area.xywh(), area.xywh())
- }
- }
-}
-
-/// A linear coordinate.
-pub trait Coordinate: Send + Sync + Copy
- + Add
- + Sub
- + Mul
- + Div
- + Ord + PartialEq + Eq
- + Debug + Display + Default
- + From + Into
- + Into
- + Into
-{
- fn zero () -> Self { 0.into() }
- fn plus (self, other: Self) -> Self;
- fn minus (self, other: Self) -> Self {
- if self >= other {
- self - other
- } else {
- 0.into()
- }
- }
-}
-
-impl Coordinate for u16 {
- fn plus (self, other: Self) -> Self {
- self.saturating_add(other)
- }
-}
-
-pub trait Area: From<[N;4]> + Debug + Copy {
- fn x (&self) -> N;
- fn y (&self) -> N;
- fn w (&self) -> N;
- fn h (&self) -> N;
- fn zero () -> [N;4] {
- [N::zero(), N::zero(), N::zero(), N::zero()]
- }
- fn from_position (pos: impl Size) -> [N;4] {
- let [x, y] = pos.wh();
- [x, y, 0.into(), 0.into()]
- }
- fn from_size (size: impl Size) -> [N;4] {
- let [w, h] = size.wh();
- [0.into(), 0.into(), w, h]
- }
- fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
- if self.w() < w || self.h() < h {
- Err(format!("min {w}x{h}").into())
- } else {
- Ok(self)
- }
- }
- fn xy (&self) -> [N;2] {
- [self.x(), self.y()]
- }
- fn wh (&self) -> [N;2] {
- [self.w(), self.h()]
- }
- fn xywh (&self) -> [N;4] {
- [self.x(), self.y(), self.w(), self.h()]
- }
- fn clip_h (&self, h: N) -> [N;4] {
- [self.x(), self.y(), self.w(), self.h().min(h)]
- }
- fn clip_w (&self, w: N) -> [N;4] {
- [self.x(), self.y(), self.w().min(w), self.h()]
- }
- fn clip (&self, wh: impl Size) -> [N;4] {
- [self.x(), self.y(), wh.w(), wh.h()]
- }
- fn set_w (&self, w: N) -> [N;4] {
- [self.x(), self.y(), w, self.h()]
- }
- fn set_h (&self, h: N) -> [N;4] {
- [self.x(), self.y(), self.w(), h]
- }
- fn x2 (&self) -> N {
- self.x().plus(self.w())
- }
- fn y2 (&self) -> N {
- self.y().plus(self.h())
- }
- fn lrtb (&self) -> [N;4] {
- [self.x(), self.x2(), self.y(), self.y2()]
- }
- fn center (&self) -> [N;2] {
- [self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())]
- }
- fn center_x (&self, n: N) -> [N;4] {
- let [x, y, w, h] = self.xywh();
- [(x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()]
- }
- fn center_y (&self, n: N) -> [N;4] {
- let [x, y, w, h] = self.xywh();
- [x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n]
- }
- fn center_xy (&self, [n, m]: [N;2]) -> [N;4] {
- let [x, y, w, h] = self.xywh();
- [(x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m]
- }
- fn centered (&self) -> [N;2] {
- [self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())]
- }
- fn iter_x (&self) -> impl Iterator
- where N: std::iter::Step {
- self.x()..(self.x()+self.w())
- }
- fn iter_y (&self) -> impl Iterator
- where N: std::iter::Step {
- self.y()..(self.y()+self.h())
- }
-}
-
-impl Area for (N, N, N, N) {
- fn x (&self) -> N { self.0 }
- fn y (&self) -> N { self.1 }
- fn w (&self) -> N { self.2 }
- fn h (&self) -> N { self.3 }
-}
-
-impl Area for [N;4] {
- fn x (&self) -> N { self[0] }
- fn y (&self) -> N { self[1] }
- fn w (&self) -> N { self[2] }
- fn h (&self) -> N { self[3] }
-}
-
-pub trait Size: From<[N;2]> + Debug + Copy {
- fn x (&self) -> N;
- fn y (&self) -> N;
- fn w (&self) -> N { self.x() }
- fn h (&self) -> N { self.y() }
- fn wh (&self) -> [N;2] { [self.x(), self.y()] }
- fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] }
- fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] }
- fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
- if self.w() < w || self.h() < h {
- Err(format!("min {w}x{h}").into())
- } else {
- Ok(self)
- }
- }
- fn zero () -> [N;2] {
- [N::zero(), N::zero()]
- }
- fn to_area_pos (&self) -> [N;4] {
- let [x, y] = self.wh();
- [x, y, 0.into(), 0.into()]
- }
- fn to_area_size (&self) -> [N;4] {
- let [w, h] = self.wh();
- [0.into(), 0.into(), w, h]
- }
-}
-
-impl