This commit is contained in:
facile pop culture reference 2026-07-31 06:47:30 +03:00
parent 94c26f06cc
commit fc01fd6ad3
40 changed files with 2075 additions and 1807 deletions

39
src/layout/align.rs Normal file
View file

@ -0,0 +1,39 @@
use crate::{*, draw::*, layout::*};
use Azimuth::*;
pub struct Align<T>(
pub(crate) Option<Azimuth>,
pub(crate) T,
);
impl<S: Screen, T: Draw<S>> Draw<S> for Align<T> {
fn layout (&self, area: XYWH<S::Unit>) -> Perhaps<XYWH<S::Unit>> {
let XYWH(x0, y0, w0, h0) = area;
Ok(align::<S>(area, self.1.layout(area)?, self.0))
}
fn draw (self, to: &mut S) -> Perhaps<XYWH<S::Unit>> {
Ok(self.layout(to.area())?.map(|area|to.clip(area, |to|self.1.draw(to))).transpose()?.flatten())
}
}
fn align <S: Screen> (
area0: XYWH<S::Unit>, area: Option<XYWH<S::Unit>>, azimuth: Option<Azimuth>
) -> Option<XYWH<S::Unit>> {
area.map(|XYWH(x, y, w, h)|{
let XYWH(x0, y0, w0, h0) = area0;
match azimuth {
Some(NW) => XYWH(x0, y0, w, h),
Some(N) => XYWH(x0 + w0.minus(w) / 2.into(), y0, w, h),
Some(NE) => XYWH((x0 + w0).minus(w), y0, w, h),
Some(W) => XYWH(x0, y0 + h0.minus(h) / 2.into(), w, h),
Some(C) => XYWH(x0 + w0.minus(w) / 2.into(), y0 + h0.minus(h) / 2.into(), w, h),
Some(E) => XYWH((x0 + w0).minus(w), y0 + h0.minus(h) / 2.into(), w, h),
Some(SW) => XYWH(x0, (y0 + h0).minus(h), w, h),
Some(S) => XYWH(x0 + w0.minus(w) / 2.into(), (y0 + h0).minus(h), w, h),
Some(SE) => XYWH((x0 + w0).minus(w), (y0 + h0).minus(h), w, h),
Some(X) => XYWH(x0 + w0.minus(w) / 2.into(), y, w, h),
Some(Y) => XYWH(x, y0 + h0.minus(h) / 2.into(), w, h),
None => XYWH(x, y, w, h)
}
})
}

21
src/layout/area.rs Normal file
View file

@ -0,0 +1,21 @@
use crate::{*, draw::*};
/// ```
/// use tengri::*;
/// let _ = area(None, "unareaed");
/// let _ = area(XYWH(1, 2, 3, 4), "southeast");
/// let _ = area(Some(XYWH(1, 2, 3, 4)), "southeast");
/// ```
pub fn area <S: Screen, T: Draw<S>, U: Into<Option<XYWH<S::Unit>>>> (
origin: U, it: T
) -> Area<S, T> {
Area(origin.into(), it)
}
pub struct Area<S: Screen, T: Draw<S>>(
pub Option<XYWH<S::Unit>>,
pub T
);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Area<S, T>, to: S|{
to.clip(self.0, |to|self.1.draw(to))
});

29
src/layout/exact.rs Normal file
View file

@ -0,0 +1,29 @@
use crate::{*, draw::*};
/// Set size of of drawing area.
///
/// ```
/// use tengri::Layout;
/// let _ = "".exact_w(1);
/// let _ = "".exact_h(1);
/// let _ = "".exact_wh(1, 1);
/// ```
pub enum Exact<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
W(I, X),
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Exact<T, I, X>, to: T|{
let area: XYWH<T::Unit> = to.area();
let (item, area) = match self {
Self::W(item, w1) =>
(item, XYWH(area.0, area.1, w1.into().unwrap_or(area.2), area.3)),
Self::H(item, h1) =>
(item, XYWH(area.0, area.1, area.2, h1.into().unwrap_or(area.3))),
Self::WH(item, w1, h1) =>
(item, XYWH(area.0, area.1, w1.into().unwrap_or(area.2), h1.into().unwrap_or(area.3))),
_ => return Ok(None)
};
to.clip(area, |to|item.draw(to))
});

41
src/layout/full.rs Normal file
View file

@ -0,0 +1,41 @@
use crate::{*, draw::*};
/// Use whole drawing area along one or both axes.
///
/// ```
/// # fn doctest_layout_full () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(0u16, 0, 80, 25);
/// assert_eq!("1".layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// assert_eq!("1".full_w().layout(area)?, Some(XYWH(0u16, 0, 80, 1)));
/// assert_eq!("1".full_h().layout(area)?, Some(XYWH(0u16, 0, 1, 25)));
/// assert_eq!("1".full_wh().layout(area)?, Some(XYWH(0u16, 0, 80, 25)));
/// # Ok(()) }
/// ```
pub enum Full<T: Screen, I: Draw<T>> {
__(PhantomData<T>),
W(I),
H(I),
WH(I),
}
impl_draw!(<T: Screen, I: Draw<T>,>|self: Full<T, I>, to: T|{
let XYWH(x0, y0, w0, h0) = to.area();
match self {
Self::W(item) => if let Some(XYWH(_, y, _, h)) = item.layout(to.area())? {
to.clip(XYWH(x0, y, w0, h), |to|item.draw(to))
} else {
Ok(None)
},
Self::H(item) => if let Some(XYWH(x, _, w, _)) = item.layout(to.area())? {
to.clip(XYWH(x, y0, w, h0), |to|item.draw(to))
} else {
Ok(None)
},
Self::WH(item) => if let Some(XYWH(..)) = item.layout(to.area())? {
to.clip(XYWH(x0, y0, w0, h0), |to|item.draw(to))
} else {
Ok(None)
},
_ => unreachable!(),
}
});

55
src/layout/max.rs Normal file
View file

@ -0,0 +1,55 @@
use crate::{*, draw::*};
/// Set maximum size of of drawing area.
///
/// ```
/// # fn doctest_layout_max () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(1u16, 1, 80, 25);
/// assert_eq!("12345".max_w(1).layout(area)?, Some(XYWH(1u16, 1, 1, 1)));
/// assert_eq!("12345".max_h(1).layout(area)?, Some(XYWH(1u16, 1, 1, 1)));
/// assert_eq!("12345".max_wh(1, 1).layout(area)?, Some(XYWH(1u16, 1, 5, 1)));
/// # Ok(()) }
/// ```
pub enum Max<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>> + Copy> {
__(PhantomData<T>),
W(I, X),
H(I, X),
WH(I, X, X),
}
impl<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>> + Copy> Draw<T> for Max<T, I, X> {
fn layout (&self, area: XYWH<T::Unit>) -> Perhaps<XYWH<T::Unit>> {
Ok(Some(match self {
Self::W(_, max_w) => XYWH(
area.0, area.1, (*max_w).into().map(|max|max.min(area.2)).unwrap_or(area.2),
area.3),
Self::H(_, max_h) => XYWH(
area.0, area.1, area.2,
(*max_h).into().map(|max|max.min(area.3)).unwrap_or(area.3)),
Self::WH(_, max_w, max_h) => XYWH(
area.0, area.1, (*max_w).into().map(|max|max.min(area.2)).unwrap_or(area.2),
(*max_h).into().map(|max|max.min(area.3)).unwrap_or(area.3)),
_ => return Ok(None)
}))
}
fn draw (self, to: &mut T) -> Perhaps<XYWH<T::Unit>> {
let area: XYWH<T::Unit> = to.area();
let (item, area) = match self {
Self::W(item, max_w) => (item, XYWH(
area.0, area.1, max_w.into().map(|max|max.min(area.2)).unwrap_or(area.2),
area.3
)),
Self::H(item, max_h) => (item, XYWH(
area.0, area.1, area.2,
max_h.into().map(|max|max.min(area.3)).unwrap_or(area.3)
)),
Self::WH(item, max_w, max_h) => (item, XYWH(
area.0, area.1, max_w.into().map(|max|max.min(area.2)).unwrap_or(area.2),
max_h.into().map(|max|max.min(area.3)).unwrap_or(area.3),
)),
_ => return Ok(None)
};
to.clip(area, draw(item))
}
}

40
src/layout/min.rs Normal file
View file

@ -0,0 +1,40 @@
use crate::{*, draw::*};
/// Only draw content if area is above a certain size.
///
/// ```
/// # fn doctest_layout_min () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(1u16, 1, 80, 25);
/// assert_eq!("1".min_w(5).layout(area)?, Some(XYWH(1u16, 1, 5, 1)));
/// assert_eq!("1".min_h(5).layout(area)?, Some(XYWH(1u16, 1, 1, 5)));
/// assert_eq!("1".min_wh(5, 5).layout(area)?, Some(XYWH(1u16, 1, 5, 5)));
/// assert_eq!("123456".min_w(5).layout(area)?, Some(XYWH(1u16, 1, 6, 1)));
/// # Ok(()) }
/// ```
pub enum Min<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
W(I, X),
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Min<T, I, X>, to: T|{
match self {
Self::__(_) => unreachable!(),
Self::W(item, w1) if let Some(XYWH(x, y, w, h)) = item.layout(to.area())? => {
let w = w1.into().map(|w1|w.max(w1)).unwrap_or(w);
to.clip(XYWH(x, y, w, h), |to|item.draw(to))
},
Self::H(item, h1) if let Some(XYWH(x, y, w, h)) = item.layout(to.area())? => {
let h = h1.into().map(|h1|h.max(h1)).unwrap_or(h);
to.clip(XYWH(x, y, w, h), |to|item.draw(to))
},
Self::WH(item, w1, h1) if let Some(XYWH(x, y, w, h)) = item.layout(to.area())? => {
let w = w1.into().map(|w1|w.max(w1)).unwrap_or(w);
let h = h1.into().map(|h1|h.max(h1)).unwrap_or(h);
to.clip(XYWH(x, y, w, h), |to|item.draw(to))
},
_ => Ok(None)
}
});

21
src/layout/origin.rs Normal file
View file

@ -0,0 +1,21 @@
use crate::{*, draw::*, layout::*};
pub struct Origin<T>(
pub(crate) Option<Azimuth>,
pub(crate) T
);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Origin<T>, _to: S|{
todo!()
});
/// Something that has `[0, 0]` at a particular point.
pub trait HasOrigin {
fn origin (&self) -> Azimuth;
}
impl<T: AsRef<Azimuth>> HasOrigin for T {
fn origin (&self) -> Azimuth {
*self.as_ref()
}
}

37
src/layout/pad.rs Normal file
View file

@ -0,0 +1,37 @@
use crate::{*, draw::*};
/// Define inner drawing area.
///
/// ```
/// use tengri::Layout;
/// let _ = "".pad_w(1);
/// let _ = "".pad_h(1);
/// let _ = "".pad_wh(1, 1);
/// ```
pub enum Pad<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
W(I, X),
H(I, X),
WH(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Pad<T, I, X>, to: T|{
let area = to.area();
let (item, area) = match self {
Self::W(item, w1) => {
let w1 = w1.into().unwrap_or(T::Unit::zero());
(item, XYWH(area.0 + w1, area.1, area.2.minus(w1 + w1), area.3))
},
Self::H(item, h1) => {
let h1 = h1.into().unwrap_or(T::Unit::zero());
(item, XYWH(area.0, area.1 + h1, area.2, area.3.minus(h1 + h1)))
},
Self::WH(item, w1, h1) => {
let w1 = w1.into().unwrap_or(T::Unit::zero());
let h1 = h1.into().unwrap_or(T::Unit::zero());
(item, XYWH(area.0 + w1, area.1 + h1, area.2.minus(w1 + w1), area.3.minus(h1 + h1)))
},
_ => return Ok(None)
};
item.draw(to)
});

24
src/layout/pull.rs Normal file
View file

@ -0,0 +1,24 @@
use crate::{*, draw::*};
/// Move content in the negative direction of one or both axes.
///
/// ```
/// # fn doctest_layout_pull () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(1u16, 1, 80, 25);
/// assert_eq!("1".layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// assert_eq!("1".pull_x(1).layout(area)?, Some(XYWH(0u16, 1, 1, 1)));
/// assert_eq!("1".pull_y(1).layout(area)?, Some(XYWH(1u16, 0, 1, 1)));
/// assert_eq!("1".pull_xy(1, 1).layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// # Ok(()) }
/// ```
pub enum Pull<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
X(I, X),
Y(I, X),
XY(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Pull<T, I, X>, _to: T|{
todo!()
});

42
src/layout/push.rs Normal file
View file

@ -0,0 +1,42 @@
use crate::{*, draw::*};
/// Move content in the positive direction of one or both axes.
///
/// ```
/// # fn doctest_layout_push () -> Result<(), Box<dyn std::error::Error>> {
/// use tengri::{Layout, Draw, XYWH};
/// let area = XYWH(0u16, 0, 80, 25);
/// assert_eq!("1".layout(area)?, Some(XYWH(0u16, 0, 1, 1)));
/// assert_eq!("1".push_x(1).layout(area)?, Some(XYWH(1u16, 0, 1, 1)));
/// assert_eq!("1".push_y(1).layout(area)?, Some(XYWH(0u16, 1, 1, 1)));
/// assert_eq!("1".push_xy(1, 1).layout(area)?, Some(XYWH(1u16, 1, 1, 1)));
/// # Ok(()) }
/// ```
pub enum Push<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>> {
__(PhantomData<T>),
X(I, X),
Y(I, X),
XY(I, X, X),
}
impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Push<T, I, X>, to: T|{
match self {
Self::__(_) => unreachable!(),
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = item.layout(to.area())? => {
to.clip(XYWH(
x + x1.into().unwrap_or_default(), y, w, h
), |to|item.draw(to))
},
Self::Y(item, y1) if let Some(XYWH(x, y, w, h)) = item.layout(to.area())? => {
to.clip(XYWH(
x, y + y1.into().unwrap_or_default(), w, h
), |to|item.draw(to))
},
Self::XY(item, x1, y1) if let Some(XYWH(x, y, w, h)) = item.layout(to.area())? => {
to.clip(XYWH(
x + x1.into().unwrap_or_default(), y + y1.into().unwrap_or_default(), w, h
), |to|item.draw(to))
},
_ => Ok(None)
}
});