wip: big flat pt.6: content trait shines

This commit is contained in:
🪞👃🪞 2024-12-30 20:08:02 +01:00
parent 18b2d8c48b
commit da25b28ebf

View file

@ -22,17 +22,34 @@ 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) => {
($Enum:ident $(
|$self1:ident, $to1:ident|$min_size:expr,
|$self2:ident, $to2: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
}
}
)?
}
}
/// 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,
@ -82,17 +99,93 @@ macro_rules! transform_xy_unit {
}
}
transform_xy!(Fill);
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_unit!(Fixed);
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!(Shrink);
transform_xy_unit!(Shrink
|self, to|Ok(
self.content().min_size(to)?.map(|to|match *self {
Self::X(w, _) => [
if to.w() > w { to.w() - w } else { 0.into() },
to.h()
],
Self::Y(h, _) => [
to.w(),
if to.h() > h { to.h() - h } else { 0.into() }
],
Self::XY(w, h, _) => [
if to.w() > w { to.w() - w } else { 0.into() },
if to.h() > h { to.h() - h } else { 0.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!(Expand);
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!(Min);
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
transform_xy_unit!(Max);
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!(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!(Push
|self, to|self.content().min_size(to),
@ -116,6 +209,18 @@ transform_xy_unit!(Pull
].into(), &self.content())?;
}));
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<()> {
@ -127,24 +232,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Padding<E, T> {
}
}
transform_xy_unit!(Margin);
impl<E: Engine, T: Render<E>> Render<E> for Margin<E, T> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
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)
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
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)
}
}
content_enum!(Align: Center, X, Y, NW, N, NE, E, SE, S, SW, W);
impl<E: Engine, T: Render<E>> Align<E, T> {
pub fn c (w: T) -> Self { Self::Center(w) }
@ -197,193 +284,3 @@ impl<E: Engine, T: Render<E>> Render<E> for Align<E, T> {
})
}
}
impl<E: Engine, T: Render<E>> Shrink<E, T> {
fn inner (&self) -> &T {
match self {
Self::X(_, i) => i,
Self::Y(_, i) => i,
Self::XY(_, _, i) => i,
}
}
}
impl<E: Engine, T: Render<E>> Expand<E, T> {
fn inner (&self) -> &T {
match self {
Self::X(_, i) => i,
Self::Y(_, i) => i,
Self::XY(_, _, i) => i,
}
}
}
impl<E: Engine, T: Render<E>> Render<E> for Shrink<E, T> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().min_size(to)?.map(|to|match *self {
Self::X(w, _) => [
if to.w() > w { to.w() - w } else { 0.into() },
to.h()
],
Self::Y(h, _) => [
to.w(),
if to.h() > h { to.h() - h } else { 0.into() }
],
Self::XY(w, h, _) => [
if to.w() > w { to.w() - w } else { 0.into() },
if to.h() > h { to.h() - h } else { 0.into() }
],
}.into()))
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.unwrap_or(()))
}
}
impl<E: Engine, T: Render<E>> Render<E> for Expand<E, T> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().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()))
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.unwrap_or(()))
}
}
impl<E: Engine, W: Render<E>> Fill<E, W> {
fn inner (&self) -> &W {
match self {
Self::X(inner) => &inner,
Self::Y(inner) => &inner,
Self::XY(inner) => &inner,
_ => unreachable!(),
}
}
pub fn w (fill: W) -> Self {
Self::X(fill)
}
pub fn h (fill: W) -> Self {
Self::Y(fill)
}
pub fn wh (fill: W) -> Self {
Self::XY(fill)
}
}
impl<E: Engine, W: Render<E>> Render<E> for Fill<E, W> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
let area = self.inner().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)
}
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
self.inner().render(to)
}
}
impl<E: Engine, T: Render<E>> Fixed<E, T> {
pub fn inner (&self) -> &T {
match self {
Self::X(_, i) => i,
Self::Y(_, i) => i,
Self::XY(_, _, i) => i,
}
}
pub fn w (x: E::Unit, w: T) -> Self {
Self::X(x, w)
}
pub fn h (y: E::Unit, w: T) -> Self {
Self::Y(y, w)
}
pub fn wh (x: E::Unit, y: E::Unit, w: T) -> Self {
Self::XY(x, y, w)
}
}
impl<E: Engine, T: Render<E>> Render<E> for Fixed<E, T> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
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 },
_ => unreachable!(),
})
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
// 🡘 🡙 ←🡙→
if let Some(size) = self.min_size(to.area().wh().into())? {
to.render_in(to.area().clip(size).into(), self.inner())
} else {
Ok(())
}
}
}
impl<E: Engine, T: Render<E>> Min<E, T> {
pub fn inner (&self) -> &T {
match self {
Self::X(_, i) => i,
Self::Y(_, i) => i,
Self::XY(_, _, i) => i,
}
}
}
impl<E: Engine, T: Render<E>> Render<E> for Min<E, T> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().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()))
}
// TODO: 🡘 🡙 ←🡙→
fn render (&self, to: &mut E::Output) -> Usually<()> {
Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.unwrap_or(()))
}
}
impl<E: Engine, T: Render<E>> Max<E, T> {
fn inner (&self) -> &T {
match self {
Self::X(_, i) => i,
Self::Y(_, i) => i,
Self::XY(_, _, i) => i,
}
}
}
impl<E: Engine, T: Render<E>> Render<E> for Max<E, T> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
Ok(self.inner().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()))
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
Ok(self.min_size(to.area().wh().into())?
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
.transpose()?.unwrap_or(()))
}
}