the wild Layout trait appears

This commit is contained in:
🪞👃🪞 2024-12-31 00:38:47 +01:00
parent 7c652135ad
commit d37bd3e0c5
7 changed files with 576 additions and 595 deletions

View file

@ -11,7 +11,7 @@ macro_rules! content_enum {
pub enum $Enum<E: Engine, T: Render<E>> {
_Unused(PhantomData<E>), $($Variant(T)),+
}
impl<E: Engine, T: Render<E>> Content<E> for $Enum<E, T> {
impl<E: Engine, T: Render<E>> $Enum<E, T> {
fn content (&self) -> Option<impl Render<E>> {
match self {
Self::_Unused(_) => None,
@ -25,36 +25,25 @@ macro_rules! content_enum {
/// Defines an enum that transforms its content
/// along either the X axis, the Y axis, or both.
macro_rules! transform_xy {
($Enum:ident $(
|$self1:ident, $to1:ident|$min_size:expr,
|$self2:ident, $to2:ident|$render:expr
)?) => {
(|$self:ident : $Enum:ident, $to:ident|$render:expr) => {
content_enum!($Enum: X, Y, XY);
impl<E: Engine, T: Render<E>> $Enum<E, T> {
pub fn x (item: T) -> Self { Self::X(item) }
pub fn y (item: T) -> Self { Self::Y(item) }
pub fn xy (item: T) -> Self { Self::XY(item) }
}
$(
impl<E: Engine, T: Render<E>> Render<E> for $Enum<E, T> {
fn min_size (&$self1, $to1: E::Size) -> Perhaps<E::Size> {
$min_size
}
fn render (&$self2, $to2: &mut E::Output) -> Usually<()> {
$render
}
impl<E: Engine, T: Render<E>> Render<E> for $Enum<E, T> {
fn render (&$self, $to: &mut <E as Engine>::Output) {
$render
}
)?
}
}
}
/// Defines an enum that transforms its content parametrically
/// along either the X axis, the Y axis, or both
macro_rules! transform_xy_unit {
($Enum:ident $(
|$self1:ident, $to1:ident|$min_size:expr,
|$self2:ident, $to2:ident|$render:expr
)?) => {
(|$self:ident : $Enum:ident, $to:ident|$render:expr) => {
pub enum $Enum<E: Engine, T: Render<E>> {
X(E::Unit, T), Y(E::Unit, T), XY(E::Unit, E::Unit, T),
}
@ -77,151 +66,83 @@ macro_rules! transform_xy_unit {
}
}
}
impl<E: Engine, T: Render<E>> Content<E> for $Enum<E, T> {
impl<E: Engine, T: Render<E>> $Enum<E, T> {
fn content (&self) -> Option<impl Render<E>> {
Some(match self {
Self::X(_, content) => content,
Self::Y(_, content) => content,
Self::X(_, content) => content,
Self::Y(_, content) => content,
Self::XY(_, _, content) => content,
})
}
}
$(
impl<E: Engine, T: Render<E>> Render<E> for $Enum<E, T> {
fn min_size (&$self1, $to1: E::Size) -> Perhaps<E::Size> {
$min_size
}
fn render (&$self2, $to2: &mut E::Output) -> Usually<()> {
$render
}
impl<E: Engine, T: Render<E>> Render<E> for $Enum<E, T> {
fn render (&$self, $to: &mut E::Output) -> Usually<()> {
$render
}
)?
}
}
}
transform_xy!(Fill
|self, to|{
let area = self.content().min_size(to.into())?;
if let Some(area) = area {
Ok(Some(match self {
Self::X(_) => [to.w().into(), area.h()],
Self::Y(_) => [area.w(), to.h().into()],
Self::XY(_) => [to.w().into(), to.h().into()],
_ => unreachable!(),
}.into()))
} else {
Ok(None)
}
},
|self, to|self.content().render(to));
transform_xy!(|self: Fill, to|todo!());
transform_xy_unit!(Fixed
|self, to|{
Ok(match self {
Self::X(w, _) =>
if to.w() >= *w { Some([*w, to.h()].into()) } else { None },
Self::Y(h, _) =>
if to.h() >= *h { Some([to.w(), *h].into()) } else { None },
Self::XY(w, h, _)
=> if to.w() >= *w && to.h() >= *h { Some([*w, *h].into()) } else { None },
})
},
|self, to|{
// 🡘 🡙 ←🡙→
if let Some(size) = self.min_size(to.area().wh().into())? {
to.render_in(to.area().clip(size).into(), &self.content())
} else {
Ok(())
}
});
transform_xy_unit!(|self: Fixed, to|{
let [x, y, w, h] = to.area().xywh();
to.render_in(match self {
Self::X(fw, _) => [x, y, fw, h],
Self::Y(fh, _) => [x, y, w, fh],
Self::XY(fw, fh, _) => [x, y, fw, fh],
}, self.content())
});
transform_xy_unit!(Shrink
|self, to|Ok(self.content().min_size(to)?
.map(|wh|wh.wh())
.map(|[w, h]|[
w.minus(self.dx()).into(),
h.minus(self.dy()).into()
].into())),
|self, to|Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), &self.content()))
.transpose()?.unwrap_or(())));
transform_xy_unit!(|self: Shrink, to|to.render_in(
[to.x(), to.y(), to.w().minus(self.dx()), to.h().minus(self.dy())],
self.content()));
transform_xy_unit!(Expand
|self, to|Ok(self.content().min_size(to)?.map(|to|match *self {
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())),
|self, to|Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), &self.content()))
.transpose()?.unwrap_or(())));
transform_xy_unit!(|self: Expand, to|to.render_in(
[to.x(), to.y(), to.w() + self.dx(), to.h() + self.dy()],
self.content()));
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
transform_xy_unit!(|self: Min, to|to.render_in(match self {
Self::X(mw, _) => [to.x(), to.y(), to.w().max(mw), to.h()],
Self::Y(mh, _) => [to.x(), to.y(), to.w(), to.h().max(mh)],
Self::XY(mw, mh, _) => [to.x(), to.y(), to.w().max(mw), to.h().max(mh)]
}, self.content()));
transform_xy_unit!(Min
|self, to|Ok(self.content().min_size(to)?.map(|to|match *self {
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())),
|self, to|Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), &self.content()))
.transpose()?.unwrap_or(())));
transform_xy_unit!(|self: Max, to|to.render_in(match self {
Self::X(mw, _) => [to.x(), to.y(), to.w().min(mw), to.h()],
Self::Y(mh, _) => [to.x(), to.y(), to.w(), to.h().min(mh)],
Self::XY(mw, mh, _) => [to.x(), to.y(), to.w().min(mw), to.h().min(mh)],
}, self.content()));
transform_xy_unit!(Max
|self, to|Ok(self.content().min_size(to)?.map(|to|match *self {
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())),
|self, to|Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), &self.content()))
.transpose()?.unwrap_or(())));
transform_xy_unit!(|self: Push, to|to.render_in(
[to.x() + self.dx(), to.y() + self.dy(), to.w(), to.h()],
self.content()));
transform_xy_unit!(Push
|self, to|self.content().min_size(to),
|self, to|Ok(if let Some(size) = self.min_size(to.area().wh().into())? {
to.render_in([
to.area().x() + self.dx(),
to.area().y() + self.dy(),
size.w(),
size.h(),
].into(), &self.content())?;
}));
transform_xy_unit!(|self: Pull, to|to.render_in(
[to.x().minus(self.dx()), to.y().minus(self.dy()), to.w(), to.h()],
self.content()));
transform_xy_unit!(Pull
|self, to|self.content().min_size(to),
|self, to|Ok(if let Some(size) = self.min_size(to.area().wh().into())? {
to.render_in([
to.area().x().minus(self.dx()),
to.area().y().minus(self.dy()),
size.w(),
size.h(),
].into(), &self.content())?;
}));
transform_xy_unit!(|self: Margin, to|{
let dx = self.dx();
let dy = self.dy();
to.render_in([
to.x().minus(dx),
to.y().minus(dy),
to.w() + dy + dy,
to.h() + dy + dy,
])
});
transform_xy_unit!(Margin
|self, to|match *self {
Self::X(x, ref content) => Expand::x(x + x, content),
Self::Y(y, ref content) => Expand::y(y + y, content),
Self::XY(x, y, ref content) => Expand::xy(x + x, y + y, content),
}.min_size(to),
|self, to|match *self {
Self::X(x, ref content) => Push::x(x, content),
Self::Y(y, ref content) => Push::y(y, content),
Self::XY(x, y, ref content) => Push::xy(x, y, content),
}.render(to));
transform_xy_unit!(Padding);
impl<E: Engine, T: Render<E>> Render<E> for Padding<E, T> {
fn render (&self, to: &mut E::Output) -> Usually<()> {
match self {
Self::X(x, content) => Push::x(*x, Shrink::x(*x, content)),
Self::Y(y, content) => Push::y(*y, Shrink::y(*y, content)),
Self::XY(x, y, content) => Push::xy(*x, *y, Shrink::xy(*x, *y, content)),
}.render(to)
}
}
transform_xy_unit!(|self: Padding, to|{
let dx = self.dx();
let dy = self.dy();
to.render_in([
to.x() + dx,
to.y() + dy,
to.w().minus(dy + dy),
to.h().minus(dy + dy),
])
});
content_enum!(Align: Center, X, Y, NW, N, NE, E, SE, S, SW, W);
impl<E: Engine, T: Render<E>> Align<E, T> {