mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
247 lines
9 KiB
Rust
247 lines
9 KiB
Rust
use crate::*;
|
|
use super::*;
|
|
use Direction::*;
|
|
|
|
impl Direction {
|
|
pub fn is_north (&self) -> bool { matches!(self, Self::North) }
|
|
pub fn is_south (&self) -> bool { matches!(self, Self::South) }
|
|
pub fn is_east (&self) -> bool { matches!(self, Self::West) }
|
|
pub fn is_west (&self) -> bool { matches!(self, Self::East) }
|
|
/// Return next direction clockwise
|
|
pub fn cw (&self) -> Self {
|
|
match self {
|
|
Self::North => Self::East,
|
|
Self::South => Self::West,
|
|
Self::West => Self::North,
|
|
Self::East => Self::South,
|
|
}
|
|
}
|
|
/// Return next direction counterclockwise
|
|
pub fn ccw (&self) -> Self {
|
|
match self {
|
|
Self::North => Self::West,
|
|
Self::South => Self::East,
|
|
Self::West => Self::South,
|
|
Self::East => Self::North,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<E: Engine, A: Render<E>, B: Render<E>> Render<E> for Split<E, A, B> {
|
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
Ok(Some(to))
|
|
}
|
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
let (a, b) = to.area().split_fixed(self.1, self.2);
|
|
Ok(if self.0 {
|
|
to.render_in(a.into(), &self.4)?;
|
|
to.render_in(b.into(), &self.3)?;
|
|
} else {
|
|
to.render_in(a.into(), &self.3)?;
|
|
to.render_in(b.into(), &self.4)?;
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<E: Engine, X: Render<E>, Y: Render<E>> Default for Bsp<E, X, Y> {
|
|
fn default () -> Self {
|
|
Self::Null(Default::default())
|
|
}
|
|
}
|
|
|
|
impl<E: Engine, X: Render<E>, Y: Render<E>> Render<E> for Bsp<E, X, Y> {
|
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
Ok(Some(match self {
|
|
Self::Null(_) => [0.into(), 0.into()].into(),
|
|
Self::S(a, b) => {
|
|
let a = a.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
let b = b.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
[a.w().max(b.w()), a.h() + b.h()].into()
|
|
},
|
|
Self::E(a, b) => {
|
|
let a = a.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
let b = b.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
[a.w() + b.w(), a.h().max(b.h())].into()
|
|
},
|
|
Self::W(a, b) => {
|
|
let a = a.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
let b = b.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
[a.w() + b.w(), a.h().max(b.h())].into()
|
|
},
|
|
Self::N(a, b) => {
|
|
let a = a.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
let b = b.min_size(to)?.unwrap_or([0.into(), 0.into()].into());
|
|
[a.w().max(b.w()), a.h() + b.h()].into()
|
|
},
|
|
_ => todo!()
|
|
}))
|
|
}
|
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
let n = [0.into(), 0.into()].into();
|
|
let s = to.area().wh().into();
|
|
Ok(match self {
|
|
Self::Null(_) => {},
|
|
Self::S(a, b) => {
|
|
let s_a = a.min_size(s)?.unwrap_or(n);
|
|
let _ = b.min_size(s)?.unwrap_or(n);
|
|
let h = s_a.h().into();
|
|
to.render_in(to.area().clip_h(h).into(), a)?;
|
|
to.render_in(to.area().shrink_y(h).push_y(h).into(), b)?;
|
|
},
|
|
Self::E(a, b) => {
|
|
let s_a = a.min_size(s)?.unwrap_or(n);
|
|
let _ = b.min_size(s)?.unwrap_or(n);
|
|
let w = s_a.w().into();
|
|
to.render_in(to.area().clip_w(w).into(), a)?;
|
|
to.render_in(to.area().push_x(w).shrink_x(w).into(), b)?;
|
|
},
|
|
Self::W(a, b) => {
|
|
let s_a = a.min_size(s)?.unwrap_or(n);
|
|
let _ = b.min_size(s)?.unwrap_or(n);
|
|
let w = (to.area().w() - s_a.w()).into();
|
|
to.render_in(to.area().push_x(w).into(), a)?;
|
|
to.render_in(to.area().shrink_x(w).into(), b)?;
|
|
},
|
|
Self::N(a, b) => {
|
|
let s_a = a.min_size(s)?.unwrap_or(n);
|
|
let _ = b.min_size(s)?.unwrap_or(n);
|
|
let h = to.area().h() - s_a.h();
|
|
to.render_in(to.area().push_y(h).into(), a)?;
|
|
to.render_in(to.area().shrink_y(h).into(), b)?;
|
|
},
|
|
_ => todo!()
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<E: Engine, F> Render<E> for Stack<E, F>
|
|
where
|
|
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
|
{
|
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
match self.1 {
|
|
|
|
South => {
|
|
let mut w: E::Unit = 0.into();
|
|
let mut h: E::Unit = 0.into();
|
|
(self.0)(&mut |component: &dyn Render<E>| {
|
|
let max = to.h().minus(h);
|
|
if max > E::Unit::zero() {
|
|
let item = Max::y(max, Push::y(h, component));
|
|
let size = item.min_size(to)?.map(|size|size.wh());
|
|
if let Some([width, height]) = size {
|
|
h = h + height.into();
|
|
w = w.max(width);
|
|
}
|
|
}
|
|
Ok(())
|
|
})?;
|
|
Ok(Some([w, h].into()))
|
|
},
|
|
|
|
East => {
|
|
let mut w: E::Unit = 0.into();
|
|
let mut h: E::Unit = 0.into();
|
|
(self.0)(&mut |component: &dyn Render<E>| {
|
|
let max = to.w().minus(w);
|
|
if max > E::Unit::zero() {
|
|
let item = Max::x(max, Push::x(h, component));
|
|
let size = item.min_size(to)?.map(|size|size.wh());
|
|
if let Some([width, height]) = size {
|
|
w = w + width.into();
|
|
h = h.max(height);
|
|
}
|
|
}
|
|
Ok(())
|
|
})?;
|
|
Ok(Some([w, h].into()))
|
|
},
|
|
|
|
North => {
|
|
let mut w: E::Unit = 0.into();
|
|
let mut h: E::Unit = 0.into();
|
|
(self.0)(&mut |component: &dyn Render<E>| {
|
|
let max = to.h().minus(h);
|
|
if max > E::Unit::zero() {
|
|
let item = Max::y(to.h() - h, component);
|
|
let size = item.min_size(to)?.map(|size|size.wh());
|
|
if let Some([width, height]) = size {
|
|
h = h + height.into();
|
|
w = w.max(width);
|
|
}
|
|
}
|
|
Ok(())
|
|
})?;
|
|
Ok(Some([w, h].into()))
|
|
},
|
|
|
|
West => {
|
|
let w: E::Unit = 0.into();
|
|
let h: E::Unit = 0.into();
|
|
(self.0)(&mut |component: &dyn Render<E>| {
|
|
if w < to.w() {
|
|
todo!();
|
|
}
|
|
Ok(())
|
|
})?;
|
|
Ok(Some([w, h].into()))
|
|
},
|
|
}
|
|
}
|
|
|
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
let area = to.area();
|
|
let mut w = 0.into();
|
|
let mut h = 0.into();
|
|
match self.1 {
|
|
South => {
|
|
(self.0)(&mut |item| {
|
|
if h < area.h() {
|
|
let item = Max::y(area.h() - h, Push::y(h, item));
|
|
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
|
if let Some([width, height]) = show {
|
|
item.render(to)?;
|
|
h = h + height;
|
|
if width > w { w = width }
|
|
};
|
|
}
|
|
Ok(())
|
|
})?;
|
|
},
|
|
East => {
|
|
(self.0)(&mut |item| {
|
|
if w < area.w() {
|
|
let item = Max::x(area.w() - w, Push::x(w, item));
|
|
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
|
if let Some([width, height]) = show {
|
|
item.render(to)?;
|
|
w = width + w;
|
|
if height > h { h = height }
|
|
};
|
|
}
|
|
Ok(())
|
|
})?;
|
|
},
|
|
North => {
|
|
(self.0)(&mut |item| {
|
|
if h < area.h() {
|
|
let show = item.min_size([area.w(), area.h().minus(h)].into())?.map(|s|s.wh());
|
|
if let Some([width, height]) = show {
|
|
Shrink::y(height, Push::y(area.h() - height, item))
|
|
.render(to)?;
|
|
h = h + height;
|
|
if width > w { w = width }
|
|
};
|
|
}
|
|
Ok(())
|
|
})?;
|
|
},
|
|
_ => todo!()
|
|
};
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)] #[test] fn test_bsp () {
|
|
// TODO
|
|
}
|