mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 20:26:42 +01:00
the wild Layout trait appears
This commit is contained in:
parent
7c652135ad
commit
d37bd3e0c5
7 changed files with 576 additions and 595 deletions
|
|
@ -4,40 +4,26 @@ use crate::*;
|
|||
pub struct Cond;
|
||||
|
||||
impl Cond {
|
||||
/// Render `item` when `cond` is true.
|
||||
pub fn when <E: Engine, A: Render<E>> (cond: bool, item: A) -> When<E, A> {
|
||||
When(cond, item, Default::default())
|
||||
/// Show an item conditionally.
|
||||
pub fn when <E: Engine> (cond: bool, item: Box<dyn Layout<E>>) -> When<E> {
|
||||
When(cond, item)
|
||||
}
|
||||
/// Render `item` if `cond` is true, otherwise render `other`.
|
||||
pub fn either <E: Engine, A: Render<E>, B: Render<E>> (cond: bool, item: A, other: B) -> Either<E, A, B> {
|
||||
Either(cond, item, other, Default::default())
|
||||
/// Show either of two items.
|
||||
pub fn either <E: Engine> (cond: bool, a: Box<dyn Layout<E>>, b: Box<dyn Layout<E>>) -> Either<E> {
|
||||
Either(cond, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders `self.1` when `self.0` is true.
|
||||
pub struct When<E: Engine, A: Render<E>>(bool, A, PhantomData<E>);
|
||||
|
||||
impl<E: Engine, A: Render<E>> Render<E> for When<E, A> {
|
||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||
let Self(cond, item, ..) = self;
|
||||
if *cond { item.min_size(to) } else { Ok(Some([0.into(), 0.into()].into())) }
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||
let Self(cond, item, ..) = self;
|
||||
if *cond { item.render(to) } else { Ok(()) }
|
||||
pub struct When<E>(bool, Box<dyn Layout<E>>);
|
||||
impl<E: Engine> Layout<E> for When<E> {
|
||||
fn layout (self, _: &mut E::Output) -> Option<Box<dyn Layout<E>>> {
|
||||
if self.0 { Some(self.1) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders `self.1` when `self.0` is true, otherwise renders `self.2`
|
||||
pub struct Either<E: Engine, A: Render<E>, B: Render<E>>(bool, A, B, PhantomData<E>);
|
||||
|
||||
impl<E: Engine, A: Render<E>, B: Render<E>> Render<E> for Either<E, A, B> {
|
||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||
let Self(cond, item, other, ..) = self;
|
||||
if *cond { item.min_size(to) } else { other.min_size(to) }
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||
let Self(cond, item, other, ..) = self;
|
||||
if *cond { item.render(to) } else { other.render(to) }
|
||||
pub struct Either<E: Engine>(bool, Box<dyn Layout<E>>, Box<dyn Layout<E>>);
|
||||
impl<E: Engine> Layout<E> for Either<E> {
|
||||
fn layout (self, _: &mut E::Output) -> Option<Box<dyn Layout<E>>> {
|
||||
Some(if self.0 { self.1 } else { self.2 })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use crate::*;
|
||||
use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}};
|
||||
|
||||
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
|
||||
|
||||
impl Direction {
|
||||
pub fn is_north (&self) -> bool { matches!(self, Self::North) }
|
||||
pub fn is_south (&self) -> bool { matches!(self, Self::South) }
|
||||
|
|
@ -46,13 +48,12 @@ pub struct Measure<E: Engine> {
|
|||
pub y: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
render!(Measure<E>
|
||||
|self, layout|Ok(Some(layout)),
|
||||
|self, render|{
|
||||
self.x.store(render.area().w().into(), Relaxed);
|
||||
self.y.store(render.area().h().into(), Relaxed);
|
||||
Ok(())
|
||||
});
|
||||
impl<E: Engine> Render<E> for Measure<E> {
|
||||
fn render (&self, to: &mut E::Output) {
|
||||
self.x.store(to.area().w().into(), Relaxed);
|
||||
self.y.store(to.area().h().into(), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Clone for Measure<E> {
|
||||
fn clone (&self) -> Self {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue