change Layout to output minimum size (breaks Align::Center?)

This commit is contained in:
🪞👃🪞 2024-09-15 01:31:26 +03:00
parent 0737769232
commit 1a0e06dc66
13 changed files with 232 additions and 162 deletions

View file

@ -307,7 +307,7 @@ impl<E: Engine> std::fmt::Debug for JackDevice<E> {
impl<E: Engine> Widget for JackDevice<E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
self.state.read().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {

View file

@ -34,8 +34,8 @@ pub trait Engine: Send + Sync + Sized {
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>
fn layout (&self, to: <<Self as Widget>::Engine as Engine>::Size) ->
Perhaps<<<Self as Widget>::Engine as Engine>::Size>
{
Ok(Some(to))
}
@ -44,7 +44,7 @@ pub trait Widget: Send + Sync {
}
impl<'a, E: Engine> Widget for Box<dyn Widget<Engine = E> + 'a> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
(**self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -53,7 +53,7 @@ impl<'a, E: Engine> Widget for Box<dyn Widget<Engine = E> + 'a> {
}
impl<E: Engine> Widget for &dyn Widget<Engine = E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
(*self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -62,7 +62,7 @@ impl<E: Engine> Widget for &dyn Widget<Engine = E> {
}
impl<E: Engine> Widget for &mut dyn Widget<Engine = E> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
(**self).layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -71,7 +71,7 @@ impl<E: Engine> Widget for &mut dyn Widget<Engine = E> {
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Arc<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
self.as_ref().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -80,7 +80,7 @@ impl<E: Engine, W: Widget<Engine = E>> Widget for Arc<W> {
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Mutex<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
self.lock().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -89,7 +89,7 @@ impl<E: Engine, W: Widget<Engine = E>> Widget for Mutex<W> {
}
impl<E: Engine, W: Widget<Engine = E>> Widget for RwLock<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
self.read().unwrap().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -98,7 +98,7 @@ impl<E: Engine, W: Widget<Engine = E>> Widget for RwLock<W> {
}
impl<E: Engine, W: Widget<Engine = E>> Widget for Option<W> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten())
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
@ -117,12 +117,12 @@ pub trait Content: Send + Sync {
//}
impl<E: Engine, W: Content<Engine = E>> Widget for W {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
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()),
match self.layout(to.area().wh().into())? {
Some(wh) => to.render_in(to.area().clip(wh).into(), &self.content()),
None => Ok(None)
}
}
@ -394,45 +394,74 @@ impl<T> Align<T> {
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Align<T> {
type Engine = E;
fn layout (&self, outer_area: E::Area) -> Perhaps<E::Area> {
Ok(match self {
Self::Center(_) => self.inner().layout(outer_area)?.map(|inner_area|{
let [_, _, w, h] = inner_area.xywh();
let offset_x = (outer_area.w() / 2.into()) - (w / 2.into());
let offset_y = (outer_area.h() / 2.into()) - (h / 2.into());
let result = [outer_area.x() + offset_x, outer_area.y() + offset_y, w, h];
result.into()
}),
Self::X(_) => self.inner().layout(outer_area)?.map(|inner_area|{
let [_, y, w, h] = inner_area.xywh();
let offset_x = (outer_area.w() - w) / 2.into();
let result = [outer_area.x() + offset_x, y, w, h];
result.into()
}),
Self::Y(_) => self.inner().layout(outer_area)?.map(|inner_area|{
let [x, _, w, h] = inner_area.xywh();
let offset_y = (outer_area.h() / 2.into()) - (h / 2.into());
let result = [x, outer_area.y() + offset_y, w, h];
result.into()
}),
Self::NW(_) => { todo!() },
Self::N(_) => { todo!() },
Self::NE(_) => { todo!() },
Self::W(_) => { todo!() },
Self::E(_) => { todo!() },
Self::SW(_) => { todo!() },
Self::S(_) => { todo!() },
Self::SE(_) => { todo!() },
fn align<T, N: Number, R: Area<N> + From<[N;4]>> (align: &Align<T>, outer: R, inner: R) -> Option<R> {
if outer.w() < inner.w() || outer.h() < inner.h() {
None
} else {
let [ox, oy, ow, oh] = outer.xywh();
let [ix, iy, iw, ih] = inner.xywh();
Some(match align {
Align::Center(_) => [ox + (ow - iw) / 2.into(), oy + (oh - ih) / 2.into(), iw, ih,].into(),
Align::X(_) => [ox + (ow - iw) / 2.into(), iy, iw, ih,].into(),
Align::Y(_) => [ix, oy + (oh - ih) / 2.into(), iw, ih,].into(),
Align::NW(_) => [ox, oy, iw, ih,].into(),
Align::N(_) => [ox + (ow - iw) / 2.into(), oy, iw, ih,].into(),
Align::NE(_) => [ox + ow - iw, oy, iw, ih,].into(),
Align::W(_) => [ox, oy + (oh - ih) / 2.into(), iw, ih,].into(),
Align::E(_) => [ox + ow - iw, oy + (oh - ih) / 2.into(), iw, ih,].into(),
Align::SW(_) => [ox, oy + oh - ih, iw, ih,].into(),
Align::S(_) => [ox + (ow - iw) / 2.into(), oy + oh - ih, iw, ih,].into(),
Align::SE(_) => [ox + ow - iw, oy + oh - ih, iw, ih,].into(),
})
}
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Align<T> {
type Engine = E;
fn layout (&self, outer_area: E::Size) -> Perhaps<E::Size> {
self.inner().layout(outer_area)
//Ok(match self {
//Self::Center(_) => self.inner().layout(outer_area)?.map(|inner_area|{
//let [_, _, w, h] = inner_area.xywh();
//let offset_x = (outer_area.w() / 2.into()) - (w / 2.into());
//let offset_y = (outer_area.h() / 2.into()) - (h / 2.into());
//let result = [outer_area.x() + offset_x, outer_area.y() + offset_y, w, h];
//result.into()
//}),
//Self::X(_) => self.inner().layout(outer_area)?.map(|inner_area|{
//let [_, y, w, h] = inner_area.xywh();
//let offset_x = (outer_area.w() - w) / 2.into();
//let result = [outer_area.x() + offset_x, y, w, h];
//result.into(
//}),
//Self::Y(_) => self.inner().layout(outer_area)?.map(|inner_area|{
//let [x, _, w, h] = inner_area.xywh();
//let offset_y = (outer_area.h() / 2.into()) - (h / 2.into());
//let result = [x, outer_area.y() + offset_y, w, h];
//result.into()
//}),
//Self::NW(_) => { todo!() },
//Self::N(_) => { todo!() },
//Self::NE(_) => { todo!() },
//Self::W(_) => { todo!() },
//Self::E(_) => { todo!() },
//Self::SW(_) => { todo!() },
//Self::S(_) => { todo!() },
//Self::SE(_) => { todo!() },
//})
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
if let Some(area) = self.layout(to.area())? {
to.render_in(area, self.inner())
let outer_area = to.area();
Ok(if let Some(inner_size) = self.layout(outer_area.wh().into())? {
let inner_area = outer_area.clip(inner_size);
if let Some(aligned) = align(&self, outer_area.into(), inner_area.into()) {
to.render_in(aligned, self.inner())?
} else {
None
}
} else {
Ok(None)
}
None
})
}
}
@ -468,16 +497,18 @@ impl<N: Number, T> Min<N, T> {
}
impl<E: Engine, T: Widget<Engine = E>> Widget for Min<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().layout(to)?.map(|to|match *self {
Self::X(w, _) => [to.x(), to.y(), to.w().max(w), to.h()],
Self::Y(h, _) => [to.x(), to.y(), to.w(), to.h().max(h)],
Self::XY(w, h, _) => [to.x(), to.y(), to.w().max(w), to.h().max(h)],
Self::X(w, _) => [to.w().max(w), to.h()],
Self::Y(h, _) => [to.w(), to.h().max(h)],
Self::XY(w, h, _) => [to.w().max(w), to.h().max(h)],
}.into()))
}
// TODO: 🡘 🡙 ←🡙→
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
Ok(self.layout(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.flatten())
}
}
@ -499,15 +530,17 @@ impl<N: Number, T> Max<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Max<E:: Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().layout(to)?.map(|to|match *self {
Self::X(w, _) => [to.x(), to.y(), to.w().min(w), to.h()],
Self::Y(h, _) => [to.x(), to.y(), to.w(), to.h().min(h)],
Self::XY(w, h, _) => [to.x(), to.y(), to.w().min(w), to.h().min(h)],
Self::X(w, _) => [to.w().min(w), to.h()],
Self::Y(h, _) => [to.w(), to.h().min(h)],
Self::XY(w, h, _) => [to.w().min(w), to.h().min(h)],
}.into()))
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
Ok(self.layout(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.flatten())
}
}
@ -529,15 +562,17 @@ impl<N: Number, T> Grow<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Grow<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().layout(to)?.map(|to|match *self {
Self::X(w, _) => [to.x(), to.y(), to.w() + w, to.h()],
Self::Y(h, _) => [to.x(), to.y(), to.w(), to.h() + h],
Self::XY(w, h, _) => [to.x(), to.y(), to.w() + w, to.h() + h],
Self::X(w, _) => [to.w() + w, to.h()],
Self::Y(h, _) => [to.w(), to.h() + h],
Self::XY(w, h, _) => [to.w() + w, to.h() + h],
}.into()))
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
Ok(self.layout(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.flatten())
}
}
@ -559,15 +594,17 @@ impl<N: Number, T: Widget> Shrink<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Shrink<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().layout(to)?.map(|to|match *self {
Self::X(w, _) => [to.x(), to.y(), to.w() - w, to.h()],
Self::Y(h, _) => [to.x(), to.y(), to.w(), to.h() - h],
Self::XY(w, h, _) => [to.x(), to.y(), to.w() - w, to.h() - h]
Self::X(w, _) => [to.w() - w, to.h()],
Self::Y(h, _) => [to.w(), to.h() - h],
Self::XY(w, h, _) => [to.w() - w, to.h() - h]
}.into()))
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
Ok(self.layout(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.flatten())
}
}
@ -605,7 +642,7 @@ impl<N: Number, T: Widget> Outset<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
match *self {
Self::X(x, ref inner) => Shrink::X(x + x, inner as &dyn Widget<Engine = E>),
Self::Y(y, ref inner) => Shrink::Y(y + y, inner as &dyn Widget<Engine = E>),
@ -623,7 +660,7 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
match *self {
Self::X(x, ref inner) => Grow::X(x + x, inner as &dyn Widget<Engine = E>),
Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget<Engine = E>),
@ -663,15 +700,17 @@ impl<N: Number, T: Widget> Plus<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Plus<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(self.inner().layout(to)?.map(|to|match *self {
Self::X(x, _) => [to.x() + x, to.y(), to.w(), to.h()],
Self::Y(y, _) => [to.x(), to.y() + y, to.w(), to.h()],
Self::XY(x, y, _) => [to.x() + x, to.y() + y, to.w(), to.h()]
}.into()))
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
self.inner().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
let area = to.area();
Ok(self.layout(area.wh().into())?
.map(|size|to.render_in(match *self {
Self::X(x, _) => [area.x() + x, area.y(), size.w(), size.h()],
Self::Y(y, _) => [area.x(), area.y() + y, size.w(), size.h()],
Self::XY(x, y, _) => [area.x() + x, area.y() + y, size.w(), size.h()],
}.into(), self.inner())).transpose()?.flatten())
}
}
@ -699,15 +738,17 @@ impl<N: Number, T: Widget> Minus<N, T> {
impl<E: Engine, T: Widget<Engine = E>> Widget for Minus<E::Unit, T> {
type Engine = E;
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
Ok(self.inner().layout(to)?.map(|to|match *self {
Self::X(x, _) => [to.x().minus(x), to.y(), to.w(), to.h()],
Self::Y(y, _) => [to.x(), to.y().minus(y), to.w(), to.h()],
Self::XY(x, y, _) => [to.x().minus(x), to.y().minus(y), to.w(), to.h()]
}.into()))
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
self.inner().layout(to)
}
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
Ok(self.layout(to.area())?.map(|a|to.render_in(a, self.inner())).transpose()?.flatten())
let area = to.area();
Ok(self.layout(area.wh().into())?
.map(|size|to.render_in(match *self {
Self::X(x, _) => [area.x().minus(x), area.y(), size.w(), size.h()],
Self::Y(y, _) => [area.x(), area.y().minus(y), size.w(), size.h()],
Self::XY(x, y, _) => [area.x().minus(x), area.y().minus(y), size.w(), size.h()],
}.into(), self.inner())).transpose()?.flatten())
}
}

View file

@ -1,10 +1,20 @@
use crate::*;
// TODO: return impl Point and impl Size instead of [N;x]
// to disambiguate between usage of 2-"tuple"s
pub trait Size<N: Number> {
fn x (&self) -> N;
fn y (&self) -> N;
fn w (&self) -> N { self.x() }
fn h (&self) -> N { self.y() }
#[inline] fn w (&self) -> N { self.x() }
#[inline] fn h (&self) -> N { self.y() }
#[inline] 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)
}
}
}
impl<N: Number> Size<N> for (N, N) {
@ -24,39 +34,39 @@ pub trait Area<N: Number>: Copy {
fn h (&self) -> N;
fn x2 (&self) -> N { self.x() + self.w() }
fn y2 (&self) -> N { self.y() + self.h() }
fn wh (&self) -> [N;2] {
#[inline] fn wh (&self) -> [N;2] {
[self.w(), self.h()]
}
fn xywh (&self) -> [N;4] {
#[inline] fn xywh (&self) -> [N;4] {
[self.x(), self.y(), self.w(), self.h()]
}
fn lrtb (&self) -> [N;4] {
#[inline] fn lrtb (&self) -> [N;4] {
[self.x(), self.x2(), self.y(), self.y2()]
}
fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
#[inline] 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 clip (&self, wh: impl Size<N>) -> [N;4] {
#[inline] fn clip (&self, wh: impl Size<N>) -> [N;4] {
[self.x(), self.y(), wh.w(), wh.h()]
}
}
impl<N: Number> Area<N> 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 }
#[inline] fn x (&self) -> N { self.0 }
#[inline] fn y (&self) -> N { self.1 }
#[inline] fn w (&self) -> N { self.2 }
#[inline] fn h (&self) -> N { self.3 }
}
impl<N: Number> Area<N> 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] }
#[inline] fn x (&self) -> N { self[0] }
#[inline] fn y (&self) -> N { self[1] }
#[inline] fn w (&self) -> N { self[2] }
#[inline] fn h (&self) -> N { self[3] }
}
macro_rules! impl_axis_common { ($A:ident $T:ty) => {

View file

@ -24,7 +24,7 @@ struct TestArea(u16, u16);
impl Widget for TestArea {
type Engine = TestEngine;
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some([to[0], to[1], self.0, self.1]))
}
fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> {

View file

@ -246,15 +246,15 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C
impl Widget for &str {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
let [x, y, ..] = area;
fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
// TODO: line breaks
Ok(Some([x, y, self.len() as u16, 1]))
Ok(Some([self.len() as u16, 1]))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
let area = self.layout(to.area())?.unwrap();
to.blit(&self, area.x(), area.y(), None)?;
Ok(Some(area))
let [x, y, ..] = to.area();
let [w, h] = self.layout(to.area().wh())?.unwrap();
to.blit(&self, x, y, None)?;
Ok(Some([x, y, w, h]))
}
}
@ -262,12 +262,12 @@ pub struct Styled<T: Widget<Engine = Tui>>(pub Option<Style>, pub T);
impl Widget for Styled<&str> {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
Ok(Some([area.x(), area.y(), self.1.len() as u16, 1]))
fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some([self.1.len() as u16, 1]))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
let area = self.layout(to.area())?.unwrap();
Ok(Some([area.x(), area.y(), self.1.len() as u16, 1]))
let _ = self.layout(to.area().wh())?.unwrap();
Ok(Some([to.area.x(), to.area.y(), self.1.len() as u16, 1]))
}
}
@ -275,8 +275,8 @@ pub struct Background(pub Color);
impl Widget for Background {
type Engine = Tui;
fn layout (&self, [x,y,_,_]: [u16;4]) -> Perhaps<[u16;4]> {
Ok(Some([x,y,0,0]))
fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some([0,0]))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
to.fill_bg(to.area(), self.0);
@ -286,19 +286,17 @@ impl Widget for Background {
impl<T: Widget<Engine = Tui>> Widget for Fixed<u16, T> {
type Engine = Tui;
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
Ok(match self {
Self::X(w, _) => (to.w() < *w).then(||[to.x() + *w, to.y(), to.w() - *w, to.h()]),
Self::Y(h, _) => (to.h() < *h).then(||[to.x(), to.y() + *h, to.w(), to.h() - *h]),
Self::XY(w, h, _) => (to.w() < *w || to.h() < *h).then(||[
to.x() + *w, to.y() + *h, to.w() - *w, to.h() - *h
])
Self::X(w, _) => (to.w() < *w).then(||[to.w() - *w, to.h()]),
Self::Y(h, _) => (to.h() < *h).then(||[to.w(), to.h() - *h]),
Self::XY(w, h, _) => (to.w() < *w && to.h() < *h).then(||[to.w() - *w, to.h() - *h])
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
// 🡘 🡙 ←🡙→
if let Some(area) = self.layout(to.area())? {
to.render_in(area, self.inner())
if let Some(size) = self.layout(to.area().wh())? {
to.render_in(to.area().clip(size), self.inner())
} else {
Ok(None)
}
@ -310,7 +308,7 @@ where
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = Tui>)->Usually<()>)->Usually<()>
{
type Engine = Tui;
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
let mut w = 0;
let mut h = 0;
match self.1 {
@ -320,7 +318,7 @@ where
return Ok(())
}
let area = Plus::Y(h, component as &dyn Widget<Engine = Tui>).layout(to)?;
if let Some([_, _, width, height]) = area {
if let Some([width, height]) = area {
h += height;
w = w.max(width)
}
@ -333,7 +331,7 @@ where
return Ok(())
}
let area = Plus::X(w, component as &dyn Widget<Engine = Tui>).layout(to)?;
if let Some([_, _, width, height]) = area {
if let Some([width, height]) = area {
w += width;
h = h.max(height)
}
@ -342,7 +340,7 @@ where
},
_ => todo!()
};
Ok(Some([to.x(), to.y(), w, h]))
Ok(Some([w, h]))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
let area = to.area();
@ -386,8 +384,7 @@ 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;
fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
let mut w = 0;
let mut h = 0;
(self.0)(&mut |layer| {
@ -397,11 +394,14 @@ where
}
Ok(())
})?;
Ok(Some([x, y, w, h]))
Ok(Some([w, h]))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
self.layout(to.area())?
.map(|area|(self.0)(&mut |layer|to.render_in(area, &layer).map(|_|())).map(|_|area))
self.layout(to.area().wh())?
.map(|size|(self.0)(&mut |layer|{
to.render_in(to.area().clip(size), &layer).map(|_|())
})
.map(|_|to.area()))
.transpose()
}
}
@ -410,7 +410,7 @@ pub struct Border<S: BorderStyle>(pub S);
impl<S: BorderStyle> Widget for Border<S> {
type Engine = Tui;
fn layout (&self, to: [u16;4]) -> Perhaps<[u16;4]> {
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
Outset::XY(1, 1, "").layout(to)
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
@ -558,7 +558,7 @@ macro_rules! border {
}
impl Widget for $T {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some(area))
}
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {