refactor + not sure whats up with the double padding

This commit is contained in:
🪞👃🪞 2024-09-10 14:39:53 +03:00
parent 39407c9760
commit c51d1cf643
10 changed files with 388 additions and 393 deletions

View file

@ -1,5 +1,12 @@
use crate::*;
submod! {
focus
handle
keymap
layout
}
/// Entry point for main loop
pub trait App<T: Engine> {
fn run (self, context: T) -> Usually<T>;
@ -31,13 +38,122 @@ pub trait Engine: Send + Sync + Sized {
) -> Perhaps<Self::Area>;
}
submod! {
collect
component
exit
focus
handle
keymap
layout
//render
pub trait Widget: Send + Sync {
type Engine: Engine;
fn layout (&self, to: <<Self as Widget>::Engine as Engine>::Area) ->
Perhaps<<<Self as Widget>::Engine as Engine>::Area>
{
Ok(Some(to))
}
fn render (&self, to: &mut Self::Engine) ->
Perhaps<<<Self as Widget>::Engine as Engine>::Area>;
}
impl<'a, E: Engine> Widget for Box<dyn Widget<Engine = E> + 'a> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
(**self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
(**self).render(to)
}
}
impl<E: Engine> Widget for &dyn Widget<Engine = E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
(*self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
(*self).render(to)
}
}
impl<E: Engine> Widget for &mut dyn Widget<Engine = E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
(**self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
(**self).render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Arc<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.as_ref().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
self.as_ref().render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Mutex<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.lock().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
self.lock().unwrap().render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for RwLock<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.read().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
self.read().unwrap().render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Option<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten())
}
}
pub trait Content: Send + Sync {
type Engine: Engine;
fn content (&self) -> impl Widget<Engine = <Self as Content>::Engine>;
}
//impl<E> Content<E> for () where E: Engine {
//fn content (&self) -> impl Widget<E> {
//()
//}
//}
impl<E: Engine, W: Content<Engine = E>> Widget for W {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.content().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
match self.layout(to.area())? {
Some(area) => to.render_in(area, &self.content()),
None => Ok(None)
}
}
}
/// A UI component.
pub trait Component<E: Engine>: Widget<Engine = E> + Handle<E> {}
/// Everything that implements [Render] and [Handle] is a [Component].
impl<E: Engine, C: Widget<Engine = E> + Handle<E>> Component<E> for C {}
pub trait Exit: Send {
fn exited (&self) -> bool;
fn exit (&mut self);
fn boxed (self) -> Box<dyn Exit> where Self: Sized + 'static {
Box::new(self)
}
}
/// Marker trait for [Component]s that can [Exit]
pub trait ExitableComponent<E>: Exit + Component<E> where E: Engine {
/// Perform type erasure for collecting heterogeneous components.
fn boxed (self) -> Box<dyn ExitableComponent<E>> where Self: Sized + 'static {
Box::new(self)
}
}
impl<E: Engine, C: Component<E> + Exit> ExitableComponent<E> for C {}

View file

@ -1,121 +0,0 @@
use crate::*;
pub enum Collected<'a, E: Engine> {
Box(Box<dyn Widget<Engine = E> + 'a>),
Ref(&'a (dyn Widget<Engine = E> + 'a)),
}
impl<'a, E: Engine> Widget for Collected<'a, E> {
type Engine = E;
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
match self {
Self::Box(inner) => (*inner).layout(area),
Self::Ref(inner) => (*inner).layout(area),
}
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
match self {
Self::Box(inner) => (*inner).render(to),
Self::Ref(inner) => (*inner).render(to),
}
}
}
pub struct Collection<'a, E: Engine>(
pub Vec<Collected<'a, E>>
);
impl<'a, E: Engine> Collection<'a, E> {
pub fn new () -> Self {
Self(vec![])
}
}
pub trait Collect<'a, E: Engine> {
fn add_box (self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self;
fn add_ref (self, item: &'a dyn Widget<Engine = E>) -> Self;
fn add <R: Widget<Engine = E> + Sized + 'a> (self, item: R) -> Self
where Self: Sized
{
self.add_box(Box::new(item))
}
}
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.0.push(Collected::Box(item));
self
}
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.0.push(Collected::Ref(item));
self
}
}
pub struct Layers<
E: Engine,
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
>(pub F, PhantomData<E>);
impl<
E: Engine,
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
> Layers<E, F> {
pub fn new (build: F) -> Self {
Self(build, Default::default())
}
}
// this actually works, except for the type inference
//pub struct Layers<'a, E: Engine + 'a, I: std::iter::IntoIterator<Item = &'a dyn Render<E>>>(
//pub &'a I
//);
#[derive(Copy, Clone)]
pub enum Direction { Up, Down, Left, Right }
impl Direction {
pub fn is_down (&self) -> bool {
match self { Self::Down => true, _ => false }
}
pub fn is_right (&self) -> bool {
match self { Self::Right => true, _ => false }
}
}
pub struct Split<'a, E: Engine> {
pub items: Collection<'a, E>,
pub direction: Direction,
pub focus: Option<usize>
}
impl<'a, E: Engine> Split<'a, E> {
pub fn new (direction: Direction) -> Self {
Self {
items: Collection::new(),
direction,
focus: None
}
}
pub fn down () -> Self {
Self::new(Direction::Down)
}
pub fn right () -> Self {
Self::new(Direction::Right)
}
pub fn focus (mut self, focus: Option<usize>) -> Self {
self.focus = focus;
self
}
}
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.items = self.items.add_box(item);
self
}
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.items = self.items.add_ref(item);
self
}
}

View file

@ -1,103 +0,0 @@
use crate::*;
pub trait Widget: Send + Sync {
type Engine: Engine;
fn layout (&self, to: <<Self as Widget>::Engine as Engine>::Area) ->
Perhaps<<<Self as Widget>::Engine as Engine>::Area>
{
Ok(Some(to))
}
fn render (&self, to: &mut Self::Engine) ->
Perhaps<<<Self as Widget>::Engine as Engine>::Area>;
}
impl<'a, E: Engine> Widget for Box<dyn Widget<Engine = E> + 'a> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
(**self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
(**self).render(to)
}
}
impl<E: Engine> Widget for &dyn Widget<Engine = E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
(*self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
(*self).render(to)
}
}
impl<E: Engine> Widget for &mut dyn Widget<Engine = E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
(**self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
(**self).render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Arc<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.as_ref().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
self.as_ref().render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Mutex<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.lock().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
self.lock().unwrap().render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for RwLock<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.read().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
self.read().unwrap().render(to)
}
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Option<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten())
}
}
pub trait Content: Send + Sync {
type Engine: Engine;
fn content (&self) -> impl Widget<Engine = <Self as Content>::Engine>;
}
//impl<E> Content<E> for () where E: Engine {
//fn content (&self) -> impl Widget<E> {
//()
//}
//}
impl<E: Engine, W: Content<Engine = E>> Widget for W {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
self.content().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
match self.layout(to.area())? {
Some(area) => to.render_in(area, &self.content()),
None => Ok(None)
}
}
}
/// A UI component.
pub trait Component<E: Engine>: Widget<Engine = E> + Handle<E> {}
/// Everything that implements [Render] and [Handle] is a [Component].
impl<E: Engine, C: Widget<Engine = E> + Handle<E>> Component<E> for C {}

View file

@ -1,32 +0,0 @@
use crate::*;
pub trait Exit: Send {
fn exited (&self) -> bool;
fn exit (&mut self);
fn boxed (self) -> Box<dyn Exit> where Self: Sized + 'static {
Box::new(self)
}
}
#[macro_export] macro_rules! exit {
($T:ty) => {
impl Exit for $T {
fn exited (&self) -> bool {
self.exited
}
fn exit (&mut self) {
self.exited = true
}
}
}
}
/// Marker trait for [Component]s that can [Exit]
pub trait ExitableComponent<E>: Exit + Component<E> where E: Engine {
/// Perform type erasure for collecting heterogeneous components.
fn boxed (self) -> Box<dyn ExitableComponent<E>> where Self: Sized + 'static {
Box::new(self)
}
}
impl<E: Engine, C: Component<E> + Exit> ExitableComponent<E> for C {}

View file

@ -1,7 +1,137 @@
use crate::*;
pub enum Collected<'a, E: Engine> {
Box(Box<dyn Widget<Engine = E> + 'a>),
Ref(&'a (dyn Widget<Engine = E> + 'a)),
}
impl<'a, E: Engine> Widget for Collected<'a, E> {
type Engine = E;
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
match self {
Self::Box(inner) => (*inner).layout(area),
Self::Ref(inner) => (*inner).layout(area),
}
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
match self {
Self::Box(inner) => (*inner).render(to),
Self::Ref(inner) => (*inner).render(to),
}
}
}
pub struct Collection<'a, E: Engine>(
pub Vec<Collected<'a, E>>
);
impl<'a, E: Engine> Collection<'a, E> {
pub fn new () -> Self {
Self(vec![])
}
}
pub trait Collect<'a, E: Engine> {
fn add_box (self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self;
fn add_ref (self, item: &'a dyn Widget<Engine = E>) -> Self;
fn add <R: Widget<Engine = E> + Sized + 'a> (self, item: R) -> Self
where Self: Sized
{
self.add_box(Box::new(item))
}
}
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.0.push(Collected::Box(item));
self
}
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.0.push(Collected::Ref(item));
self
}
}
pub struct Layers<
E: Engine,
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
>(pub F, PhantomData<E>);
impl<
E: Engine,
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
> Layers<E, F> {
pub fn new (build: F) -> Self {
Self(build, Default::default())
}
}
#[derive(Copy, Clone)]
pub enum Direction {
Up,
Down,
Left,
Right,
}
impl Direction {
pub fn is_down (&self) -> bool {
match self { Self::Down => true, _ => false }
}
pub fn is_right (&self) -> bool {
match self { Self::Right => true, _ => false }
}
}
pub struct Split<'a, E: Engine> {
pub items: Collection<'a, E>,
pub direction: Direction,
pub focus: Option<usize>
}
impl<'a, E: Engine> Split<'a, E> {
pub fn new (direction: Direction) -> Self {
Self {
items: Collection::new(),
direction,
focus: None
}
}
pub fn down () -> Self {
Self::new(Direction::Down)
}
pub fn right () -> Self {
Self::new(Direction::Right)
}
pub fn focus (mut self, focus: Option<usize>) -> Self {
self.focus = focus;
self
}
}
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.items = self.items.add_box(item);
self
}
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.items = self.items.add_ref(item);
self
}
}
/// Override X and Y coordinates, aligning to corner, side, or center of area
pub enum Align<L> { Center(L), NW(L), N(L), NE(L), W(L), E(L), SW(L), S(L), SE(L) }
pub enum Align<L> {
Center(L),
NW(L),
N(L),
NE(L),
W(L),
E(L),
SW(L),
S(L),
SE(L)
}
impl<T> Align<T> {
pub fn inner (&self) -> &T {
@ -20,7 +150,24 @@ impl<T> Align<T> {
}
/// Enforce minimum size of drawing area
pub enum Min<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
pub enum Min<U: Number, T> {
/// Enforce minimum width
W(U, T),
/// Enforce minimum height
H(U, T),
/// Enforce minimum width and height
WH(U, U, T),
}
impl<N: Number, T> Min<N, T> {
fn inner (&self) -> &T {
match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Min<E::Unit, T> {
type Engine = E;
@ -43,18 +190,31 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Min<E::Unit, T> {
// 🡘 🡙 ←🡙→
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))
.map(|to|self.inner().render(to))
.transpose()
.map(|x|x.flatten())
}
}
/// Enforce maximum size of drawing area
pub enum Max<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
pub enum Max<U: Number, T> {
/// Enforce maximum width
W(U, T),
/// Enforce maximum height
H(U, T),
/// Enforce maximum width and height
WH(U, U, T),
}
impl<N: Number, T> Max<N, T> {
fn inner (&self) -> &T {
match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Max<E:: Unit, T> {
type Engine = E;
@ -76,18 +236,31 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Max<E:: Unit, T> {
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
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))
.map(|to|self.inner().render(to))
.transpose()
.map(|x|x.flatten())
}
}
/// Expand drawing area
pub enum Outset<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
pub enum Outset<N: Number, T> {
/// Increase width
W(N, T),
/// Increase height
H(N, T),
/// Increase width and height
WH(N, N, T)
}
impl<N: Number, T> Outset<N, T> {
fn inner (&self) -> &T {
match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
type Engine = E;
@ -100,25 +273,38 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
item.layout([area.x(), area.y() - *h, area.w(), area.h() + *h].into())
},
Self::WH(w, h, item) => if area.x() < *w || area.y() < *h { Ok(None) } else {
item.layout([area.x()-*w, area.y() - *h, area.w() + *w, area.h() + *h].into())
item.layout([area.x()- *w, area.y() - *h, area.w() + *w, area.h() + *h].into())
}
}
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
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))
.map(|to|self.inner().render(to))
.transpose()
.map(|x|x.flatten())
}
}
/// Shrink drawing area
pub enum Inset<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
pub enum Inset<N: Number, T> {
/// Decrease width
W(N, T),
/// Decrease height
H(N, T),
/// Decrease width and height
WH(N, N, T),
}
impl<N: Number, T: Widget> Inset<N, T> {
fn inner (&self) -> &T {
match self {
Self::W(_, inner) => inner,
Self::H(_, inner) => inner,
Self::WH(_, _, inner) => inner,
}
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
type Engine = E;
@ -138,18 +324,28 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
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))
.map(|to|self.inner().render(to))
.transpose()
.map(|x|x.flatten())
}
}
/// Move origin point of drawing area
pub enum Offset<U: Number, T: Widget> { X(U, T), Y(U, T), XY(U, U, T), }
pub enum Offset<N: Number, T: Widget> {
X(N, T),
Y(N, T),
XY(N, N, T),
}
impl<N: Number, T: Widget> Offset<N, T> {
fn inner (&self) -> &T {
match self {
Self::X(_, inner) => inner,
Self::Y(_, inner) => inner,
Self::XY(_, _, inner) => inner,
}
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Offset<E::Unit, T> {
type Engine = E;
@ -169,11 +365,7 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Offset<E::Unit, T> {
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
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))
.map(|to|self.inner().render(to))
.transpose()
.map(|x|x.flatten())
}

View file

@ -1,87 +0,0 @@
use crate::*;
///// Render to output.
//pub trait Render<E: Engine>: Send + Sync {
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered>;
//}
//impl<E: Engine> Render<E> for () {
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
//Ok(None)
//}
//}
///// Options can be rendered optionally.
//impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
//match self {
//Some(component) => component.render(to),
//None => Ok(None)
//}
//}
//}
///// Boxed references can be rendered.
//impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> {
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
//(**self).render(to)
//}
//}
//impl<'a, E: Engine> Render<E> for Box<dyn Layout<E> + 'a> {
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
//(**self).render(to)
//}
//}
//impl<'a, E: Engine> Render<E> for Box<dyn Component<E> + 'a> {
//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) -> 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) -> 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) -> 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) -> 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) -> Perhaps<E::Rendered> {
//self.read().unwrap().render(to)
//}
//}
// FIXME: components are now 2 thunks (layout and render).
// maybe this resolves the conflict describe below?
///// Boxed closures can be rendered.
/////
///// 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) -> Perhaps<E::Rendered> + Send + Sync + 'a> {
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
//(*self)(to)
//}
//}

View file

@ -58,6 +58,19 @@ where
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = Tui>)->Usually<()>)->Usually<()>
{
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
let [x, y, ..] = area;
let mut w = 0;
let mut h = 0;
(self.0)(&mut |layer| {
if let Some(layer_area) = layer.layout(area)? {
w = w.max(layer_area.w());
h = h.max(layer_area.h());
}
Ok(())
})?;
Ok(Some([x, y, w, h]))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
self.layout(to.area())?
.map(|area|(self.0)(&mut |layer| {
@ -74,9 +87,10 @@ impl<T: Widget<Engine = Tui>> Widget for Align<T> {
Ok(self.inner().layout(outer_area)?.map(|inner_area|match self {
Self::Center(_) => {
let [_, _, w, h] = inner_area.xywh();
let offset_x = (outer_area.w() - w) / 2;
let offset_y = (outer_area.h() - h) / 2;
[outer_area.x() + offset_x, outer_area.y() + offset_y, w, h]
let offset_x = (outer_area.w() / 2).saturating_sub(w / 2);
let offset_y = (outer_area.h() / 2).saturating_sub(h / 2);
let result = [outer_area.x() + offset_x, outer_area.y() + offset_y, w, h];
result
},
Self::NW(_) => { todo!() },
Self::N(_) => { todo!() },