From da25b28ebf2e4227dc0ec6f6843208c6d558b4f6 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 30 Dec 2024 20:08:02 +0100 Subject: [PATCH] wip: big flat pt.6: content trait shines --- layout/src/transform.rs | 327 ++++++++++++++-------------------------- 1 file changed, 112 insertions(+), 215 deletions(-) diff --git a/layout/src/transform.rs b/layout/src/transform.rs index 77a3ae93..731f2a16 100644 --- a/layout/src/transform.rs +++ b/layout/src/transform.rs @@ -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> $Enum { 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> Render for $Enum { + fn min_size (&$self1, $to1: E::Size) -> Perhaps { + $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> Render for Padding { fn render (&self, to: &mut E::Output) -> Usually<()> { @@ -127,24 +232,6 @@ impl> Render for Padding { } } -transform_xy_unit!(Margin); -impl> Render for Margin { - fn min_size (&self, to: E::Size) -> Perhaps { - 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> Align { pub fn c (w: T) -> Self { Self::Center(w) } @@ -197,193 +284,3 @@ impl> Render for Align { }) } } - -impl> Shrink { - fn inner (&self) -> &T { - match self { - Self::X(_, i) => i, - Self::Y(_, i) => i, - Self::XY(_, _, i) => i, - } - } -} - -impl> Expand { - fn inner (&self) -> &T { - match self { - Self::X(_, i) => i, - Self::Y(_, i) => i, - Self::XY(_, _, i) => i, - } - } -} - -impl> Render for Shrink { - fn min_size (&self, to: E::Size) -> Perhaps { - 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> Render for Expand { - fn min_size (&self, to: E::Size) -> Perhaps { - 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> Fill { - 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> Render for Fill { - fn min_size (&self, to: E::Size) -> Perhaps { - 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> Fixed { - 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> Render for Fixed { - fn min_size (&self, to: E::Size) -> Perhaps { - 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> Min { - pub fn inner (&self) -> &T { - match self { - Self::X(_, i) => i, - Self::Y(_, i) => i, - Self::XY(_, _, i) => i, - } - } -} - -impl> Render for Min { - fn min_size (&self, to: E::Size) -> Perhaps { - 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> Max { - fn inner (&self) -> &T { - match self { - Self::X(_, i) => i, - Self::Y(_, i) => i, - Self::XY(_, _, i) => i, - } - } -} - -impl> Render for Max { - fn min_size (&self, to: E::Size) -> Perhaps { - 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(())) - } -}