more space/ and draw/ modules

- 26 errors and 16 doctest fails
- getting there, perpetually
This commit is contained in:
facile pop culture reference 2026-04-24 02:06:04 +03:00
parent 42a1807c2b
commit 145047b7ff
15 changed files with 269 additions and 232 deletions

View file

@ -1,85 +1,17 @@
use crate::*; use crate::*;
pub use crate::space::*; pub use crate::space::*;
/// Implement the [Draw] trait for a particular drawable and [Screen]. mod draw;
/// pub use self::draw::*;
/// ```
/// use tengri::{*, draw::*, term::*};
/// struct MyDrawable;
/// impl_draw!(|self: MyDrawable, to: Tui|{
/// todo!()
/// });
/// ```
#[macro_export] macro_rules! impl_draw ((|
$self:ident:$Self:ty, $to:ident:$To:ty
|$draw:block)=>{ impl Draw<$To> for $Self {
fn draw ($self, $to: &mut $To) -> Usually<XYWH<u16>> $draw
} });
/// Drawable that supports dynamic dispatch. mod view;
/// pub use self::view::*;
/// Drawables are composable, e.g. the [when] and [either] conditionals
/// or the layout constraints.
///
/// Drawables are consumable, i.e. the [Draw::draw] method receives an
/// owned `self` and does not return it, consuming the drawable.
///
/// To draw a thing multiple times, instead of explicitly constructing it
/// every time, implement the [View] trait instead, which will construct
/// a [Draw]able.
///
/// ```
/// use tengri::{*, draw::*};
/// struct TestScreen(bool);
/// impl Screen for TestScreen { type Unit = u16; }
/// impl X<u16> for TestScreen { fn x (&self) -> u16 { 0 } }
/// impl Y<u16> for TestScreen { fn y (&self) -> u16 { 0 } }
/// struct TestWidget(bool);
/// impl Draw<TestScreen> for TestWidget {
/// fn draw (self, screen: &mut TestScreen) -> Usually<XYWH<u16>> {
/// screen.0 |= self.0;
/// }
/// }
/// let mut screen = TestScreen(false);
/// TestWidget(false).draw(&mut screen);
/// TestWidget(true).draw(&mut screen);
/// TestWidget(false).draw(&mut screen);
/// ```
pub trait Draw<T: Screen> {
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>>;
}
impl<T: Screen, D: Draw<T>> Draw<T> for &D {
fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
todo!()
}
}
impl<T: Screen, D: Draw<T>> Draw<T> for Option<D> {
fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
todo!()
}
}
/// Emit a [Draw]able. mod thunk;
/// pub use self::thunk::*;
/// Speculative. How to avoid conflicts with [Draw] proper?
pub trait View<T: Screen> {
fn view (&self) -> impl Draw<T>;
}
pub const fn thunk <T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> (draw: F) -> Thunk<T, F> { mod screen;
Thunk(draw, std::marker::PhantomData) pub use self::screen::*;
}
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
pub struct Thunk<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>>(
pub F,
std::marker::PhantomData<T>
);
impl<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> Draw<T> for Thunk<T, F> {
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
(self.0)(to)
}
}
/// Only render when condition is true. /// Only render when condition is true.
/// ///
@ -104,36 +36,3 @@ pub const fn when <T: Screen> (condition: bool, draw: impl Draw<T>) -> impl Draw
pub const fn either <T: Screen> (condition: bool, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn either <T: Screen> (condition: bool, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> {
thunk(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) }) thunk(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) })
} }
/// Output target.
///
/// ```
/// use tengri::{*, draw::*};
///
/// struct TestOut<T: Screen<Unit = u16>>(T);
///
/// impl<T: Screen<Unit = u16>> Screen for TestOut {
/// type Unit = u16;
/// fn place_at <D: Draw<Self> + ?Sized> (&mut self, area: T, _: D) {
/// println!("placed: {area:?}");
/// ()
/// }
/// }
///
/// impl_draw!(|self: String, to: TestOut<u16>|{
/// to.area_mut().set_w(self.len() as u16);
/// });
/// ```
pub trait Screen: Space<Self::Unit> + Send + Sync + Sized {
type Unit: Coord;
/// Render drawable in area.
fn place <'t, T: Draw<Self> + ?Sized> (&mut self, content: &'t T) {
self.place_at(self.xywh(), content)
}
/// Render drawable in subarea specified by `area`
fn place_at <'t, T: Draw<Self> + ?Sized> (
&mut self, _area: XYWH<Self::Unit>, _content: &'t T
) {
unimplemented!()
}
}

60
src/draw/draw.rs Normal file
View file

@ -0,0 +1,60 @@
use super::*;
/// Implement the [Draw] trait for a particular drawable and [Screen].
///
/// ```
/// use tengri::{*, draw::*, term::*};
/// struct MyDrawable;
/// impl_draw!(|self: MyDrawable, to: Tui|{
/// todo!()
/// });
/// ```
#[macro_export] macro_rules! impl_draw ((|
$self:ident:$Self:ty, $to:ident:$To:ty
|$draw:block)=>{ impl Draw<$To> for $Self {
fn draw ($self, $to: &mut $To) -> Usually<XYWH<u16>> $draw
} });
/// Drawable that supports dynamic dispatch.
///
/// Drawables are composable, e.g. the [when] and [either] conditionals
/// or the layout constraints.
///
/// Drawables are consumable, i.e. the [Draw::draw] method receives an
/// owned `self` and does not return it, consuming the drawable.
///
/// To draw a thing multiple times, instead of explicitly constructing it
/// every time, implement the [View] trait instead, which will construct
/// a [Draw]able.
///
/// ```
/// use tengri::{*, draw::*};
/// struct MyScreen(bool);
/// impl Screen for MyScreen { type Unit = u16; }
/// impl X<u16> for MyScreen { fn x (&self) -> u16 { 0 } }
/// impl Y<u16> for MyScreen { fn y (&self) -> u16 { 0 } }
/// struct MyWidget(bool);
/// impl Draw<MyScreen> for MyWidget {
/// fn draw (self, screen: &mut MyScreen) -> Usually<XYWH<u16>> {
/// screen.0 |= self.0;
/// }
/// }
/// let mut screen = MyScreen(false);
/// MyWidget(false).draw(&mut screen);
/// MyWidget(true).draw(&mut screen);
/// MyWidget(false).draw(&mut screen);
/// ```
pub trait Draw<T: Screen> {
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>>;
}
impl<T: Screen, D: Draw<T>> Draw<T> for &D {
fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
todo!()
}
}
impl<T: Screen, D: Draw<T>> Draw<T> for Option<D> {
fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
todo!()
}
}

34
src/draw/screen.rs Normal file
View file

@ -0,0 +1,34 @@
use super::*;
/// Output target.
///
/// ```
/// use tengri::{*, draw::*};
///
/// struct TestOut<T: Screen<Unit = u16>>(T);
///
/// impl<T: Screen<Unit = u16>> Screen for TestOut {
/// type Unit = u16;
/// fn place_at <D: Draw<Self> + ?Sized> (&mut self, area: T, _: D) {
/// println!("placed: {area:?}");
/// ()
/// }
/// }
///
/// impl_draw!(|self: String, to: TestOut<u16>|{
/// to.area_mut().set_w(self.len() as u16);
/// });
/// ```
pub trait Screen: Space<Self::Unit> + Send + Sync + Sized {
type Unit: Coord;
/// Render drawable in area.
fn place <'t, T: Draw<Self> + ?Sized> (&mut self, content: &'t T) {
self.place_at(self.xywh(), content)
}
/// Render drawable in subarea specified by `area`
fn place_at <'t, T: Draw<Self> + ?Sized> (
&mut self, _area: XYWH<Self::Unit>, _content: &'t T
) {
unimplemented!()
}
}

16
src/draw/thunk.rs Normal file
View file

@ -0,0 +1,16 @@
use super::*;
pub const fn thunk <T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> (draw: F) -> Thunk<T, F> {
Thunk(draw, std::marker::PhantomData)
}
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
pub struct Thunk<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>>(
pub F,
std::marker::PhantomData<T>
);
impl<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> Draw<T> for Thunk<T, F> {
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
(self.0)(to)
}
}

8
src/draw/view.rs Normal file
View file

@ -0,0 +1,8 @@
use super::*;
/// Emit a [Draw]able.
///
/// Speculative. How to avoid conflicts with [Draw] proper?
pub trait View<T: Screen> {
fn view (&self) -> impl Draw<T>;
}

View file

@ -172,11 +172,11 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
/// # fn main () -> tengri::Usually<()> { /// # fn main () -> tengri::Usually<()> {
/// let state = State; /// let state = State;
/// let mut out = Tui::default(); /// let mut out = Tui::default();
/// tengri::eval_view_tui(&state, &mut out, "")?; /// tengri::eval::eval_view_tui(&state, &mut out, "")?;
/// tengri::eval_view_tui(&state, &mut out, "text Hello world!")?; /// tengri::eval::eval_view_tui(&state, &mut out, "text Hello world!")?;
/// tengri::eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?; /// tengri::eval::eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?;
/// tengri::eval_view_tui(&state, &mut out, "bg (g 2) (text Hello world!)")?; /// tengri::eval::eval_view_tui(&state, &mut out, "bg (g 2) (text Hello world!)")?;
/// tengri::eval_view_tui(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?; /// tengri::eval::eval_view_tui(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?;
/// # Ok(()) } /// # Ok(()) }
/// ``` /// ```
pub fn eval_view_tui <'a, S> ( pub fn eval_view_tui <'a, S> (

View file

@ -52,7 +52,7 @@ pub trait Audio {
/// Event enum for JACK events. /// Event enum for JACK events.
/// ///
/// ``` /// ```
/// let event = tengri::JackEvent::XRun; /// let event = tengri::sing::JackEvent::XRun; // kerpop
/// ``` /// ```
#[derive(Debug, Clone, PartialEq)] pub enum JackEvent { #[derive(Debug, Clone, PartialEq)] pub enum JackEvent {
ThreadInit, ThreadInit,
@ -70,7 +70,7 @@ pub trait Audio {
/// Generic notification handler that emits [JackEvent] /// Generic notification handler that emits [JackEvent]
/// ///
/// ``` /// ```
/// let notify = tengri::JackNotify(|_|{}); /// let notify = tengri::sing::JackNotify(|_|{});
/// ``` /// ```
pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T); pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);

View file

@ -1,6 +1,9 @@
use crate::{*, draw::*}; use crate::{*, draw::*};
#[cfg(test)] use proptest_derive::Arbitrary; #[cfg(test)] use proptest_derive::Arbitrary;
mod coord;
pub use self::coord::*;
mod xywh; mod xywh;
pub use self::xywh::*; pub use self::xywh::*;
@ -10,39 +13,11 @@ pub use self::origin::*;
mod split; mod split;
pub use self::split::*; pub use self::split::*;
/// A numeric type that can be used as coordinate. mod iter;
/// pub use self::iter::*;
/// FIXME: Replace with `num` crate?
/// FIXME: Use AsRef/AsMut? mod size;
/// pub use self::size::*;
/// ```
/// use tengri::draw::Coord;
/// let a: u16 = Coord::zero();
/// let b: u16 = a.plus(1);
/// let c: u16 = a.minus(2);
/// let d = a.atomic();
/// ```
pub trait Coord: Send + Sync + Copy
+ Add<Self, Output=Self>
+ Sub<Self, Output=Self>
+ Mul<Self, Output=Self>
+ Div<Self, Output=Self>
+ Ord + PartialEq + Eq
+ Debug + Display + Default
+ From<u16> + Into<u16>
+ Into<usize>
+ Into<f64>
+ std::iter::Step
{
/// Zero in own type.
fn zero () -> Self { 0.into() }
/// Addition.
fn plus (self, other: Self) -> Self;
/// Saturating subtraction.
fn minus (self, other: Self) -> Self { if self >= other { self - other } else { 0.into() } }
/// Convert to [AtomicUsize].
fn atomic (self) -> AtomicUsize { AtomicUsize::new(self.into()) }
}
/// Horizontal axis. /// Horizontal axis.
pub trait X<N: Coord> { pub trait X<N: Coord> {
@ -89,7 +64,7 @@ pub const fn w_exact <T: Screen> (w: T::Unit, c: impl Draw<T>) -> impl Draw<T> {
/// Shrink drawing area symmetrically. /// Shrink drawing area symmetrically.
/// ///
/// ``` /// ```
/// let padded = tengri::W(3).pad("Hello"); /// let padded = tengri::space::w_pad(3, "Hello");
/// ``` /// ```
pub const fn w_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> { pub const fn w_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> {
thunk(move|to: &mut T|draw.draw(todo!())) thunk(move|to: &mut T|draw.draw(todo!()))
@ -139,7 +114,7 @@ pub const fn h_exact <T: Screen> (h: T::Unit, c: impl Draw<T>) -> impl Draw<T> {
/// Shrink drawing area symmetrically. /// Shrink drawing area symmetrically.
/// ///
/// ``` /// ```
/// let padded = tengri::W::pad(3, "Hello"); /// let padded = tengri::space::w_pad(3, "Hello");
/// ``` /// ```
pub const fn h_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> { pub const fn h_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> {
thunk(move|to: &mut T|draw.draw(todo!())) thunk(move|to: &mut T|draw.draw(todo!()))
@ -170,7 +145,7 @@ pub const fn wh_pad <T: Screen> (w: T::Unit, h: T::Unit, draw: impl Draw<T>)
/// Only draw content if area is above a certain size. /// Only draw content if area is above a certain size.
/// ///
/// ``` /// ```
/// let min = tengri::wh_min(3, 5, "Hello"); // 5x5 /// let min = tengri::space::wh_min(3, 5, "Hello"); // 5x5
/// ``` /// ```
pub const fn wh_min <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>) pub const fn wh_min <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>)
-> impl Draw<T> -> impl Draw<T>
@ -181,7 +156,7 @@ pub const fn wh_min <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: i
/// Set the maximum width and/or height of the content. /// Set the maximum width and/or height of the content.
/// ///
/// ``` /// ```
/// let max = tengri::wh_max(Some(3), Some(5), "Hello"); /// let max = tengri::space::wh_max(Some(3), Some(5), "Hello");
/// ``` /// ```
pub const fn wh_max <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>) pub const fn wh_max <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>)
-> impl Draw<T> -> impl Draw<T>
@ -192,7 +167,7 @@ pub const fn wh_max <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: i
/// Set the maximum width and/or height of the content. /// Set the maximum width and/or height of the content.
/// ///
/// ``` /// ```
/// let exact = tengri::wh_exact(Some(3), Some(5), "Hello"); /// let exact = tengri::space::wh_exact(Some(3), Some(5), "Hello");
/// ``` /// ```
pub const fn wh_exact <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>) pub const fn wh_exact <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>)
-> impl Draw<T> -> impl Draw<T>
@ -202,7 +177,7 @@ pub const fn wh_exact <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw:
/// Limit size of drawing area /// Limit size of drawing area
/// ``` /// ```
/// let clipped = tengri::wh_clip(Some(3), Some(5), "Hello"); /// let clipped = tengri::space::wh_clip(Some(3), Some(5), "Hello");
/// ``` /// ```
pub const fn wh_clip <T: Screen> ( pub const fn wh_clip <T: Screen> (
w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T> w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>
@ -213,68 +188,3 @@ pub const fn wh_clip <T: Screen> (
pub const fn wh_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a } pub const fn wh_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a }
pub const fn w_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a } pub const fn w_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a }
pub const fn h_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a } pub const fn h_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a }
/// Iterate over a collection of renderables:
///
/// ```
/// use tengri::draw::{Origin::*, Split::*};
/// let _ = Below.iter([
/// NW.align(W(15).max(W(10).min("Leftbar"))),
/// NE.align(W(12).max(W(10).min("Rightbar"))),
/// Center.align(W(40).max(H(20.max("Center"))))
/// ].iter(), |x|x);
/// ```
pub fn iter <
S: Screen,
D: Draw<S>,
V: Fn()->I,
I: Iterator<Item = D>,
F: Fn(&D)->dyn Draw<S>,
> (_items: V, _cb: F) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_north <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_east <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_south <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_west <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
#[derive(Default, Debug)]
pub struct Size(AtomicUsize, AtomicUsize);
impl X<u16> for Size {
fn x (&self) -> u16 { 0 }
fn w (&self) -> u16 { self.0.load(Relaxed) as u16 }
}
impl Y<u16> for Size {
fn y (&self) -> u16 { 0 }
fn h (&self) -> u16 { self.1.load(Relaxed) as u16 }
}
impl Size {
pub const fn of <T: Screen> (&self, of: impl Draw<T>) -> impl Draw<T> {
thunk(move|to: &mut T|{
let area = of.draw(to)?;
self.0.store(area.w().into(), Relaxed);
self.1.store(area.h().into(), Relaxed);
Ok(area)
})
}
}

35
src/space/coord.rs Normal file
View file

@ -0,0 +1,35 @@
use super::*;
/// A numeric type that can be used as coordinate.
///
/// FIXME: Replace with `num` crate?
/// FIXME: Use AsRef/AsMut?
///
/// ```
/// use tengri::draw::Coord;
/// let a: u16 = Coord::zero();
/// let b: u16 = a.plus(1);
/// let c: u16 = a.minus(2);
/// let d = a.atomic();
/// ```
pub trait Coord: Send + Sync + Copy
+ Add<Self, Output=Self>
+ Sub<Self, Output=Self>
+ Mul<Self, Output=Self>
+ Div<Self, Output=Self>
+ Ord + PartialEq + Eq
+ Debug + Display + Default
+ From<u16> + Into<u16>
+ Into<usize>
+ Into<f64>
+ std::iter::Step
{
/// Zero in own type.
fn zero () -> Self { 0.into() }
/// Addition.
fn plus (self, other: Self) -> Self;
/// Saturating subtraction.
fn minus (self, other: Self) -> Self { if self >= other { self - other } else { 0.into() } }
/// Convert to [AtomicUsize].
fn atomic (self) -> AtomicUsize { AtomicUsize::new(self.into()) }
}

46
src/space/iter.rs Normal file
View file

@ -0,0 +1,46 @@
use super::*;
/// Iterate over a collection of renderables:
///
/// ```
/// use tengri::draw::{Origin::*, Split::*};
/// let _ = Below.iter([
/// NW.align(W(15).max(W(10).min("Leftbar"))),
/// NE.align(W(12).max(W(10).min("Rightbar"))),
/// Center.align(W(40).max(H(20.max("Center"))))
/// ].iter(), |x|x);
/// ```
pub fn iter <
S: Screen,
D: Draw<S>,
V: Fn()->I,
I: Iterator<Item = D>,
F: Fn(&D)->dyn Draw<S>,
> (_items: V, _cb: F) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_north <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_east <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_south <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}
pub fn iter_west <'a, S: Screen, D: 'a, I: Iterator<Item = D>, U: Draw<S>> (
_iter: impl Fn()->I, _draw: impl Fn(D)->U,
) -> impl Draw<S> {
thunk(move|_to: &mut S|{ todo!() })
}

View file

@ -73,7 +73,7 @@ impl<T: Screen, U: Draw<T>> Draw<T> for Anchor<U> {
/// ///
/// ``` /// ```
/// use tengri::draw::Origin; /// use tengri::draw::Origin;
/// let _ = Origin::NW.align(()) /// let _ = Origin::NW.align(());
/// ``` /// ```
#[cfg_attr(test, derive(Arbitrary))] #[cfg_attr(test, derive(Arbitrary))]
#[derive(Debug, Copy, Clone, Default)] pub enum Origin { #[derive(Debug, Copy, Clone, Default)] pub enum Origin {

28
src/space/size.rs Normal file
View file

@ -0,0 +1,28 @@
use super::*;
/// Uses [AtomicUsize] to measure size during\
/// rendering (which is normally read-only).
#[derive(Default, Debug)]
pub struct Size(AtomicUsize, AtomicUsize);
impl X<u16> for Size {
fn x (&self) -> u16 { 0 }
fn w (&self) -> u16 { self.0.load(Relaxed) as u16 }
}
impl Y<u16> for Size {
fn y (&self) -> u16 { 0 }
fn h (&self) -> u16 { self.1.load(Relaxed) as u16 }
}
impl Size {
pub const fn of <T: Screen> (&self, of: impl Draw<T>) -> impl Draw<T> {
thunk(move|to: &mut T|{
let area = of.draw(to)?;
self.0.store(area.w().into(), Relaxed);
self.1.store(area.h().into(), Relaxed);
Ok(area)
})
}
}

View file

@ -39,12 +39,12 @@ impl Split {
/// ``` /// ```
/// use tengri::draw::Split::*; /// use tengri::draw::Split::*;
/// let _ = Above.bsp((), ()); /// let _ = Above.half("", "");
/// let _ = Below.bsp((), ()); /// let _ = Below.half("", "");
/// let _ = North.bsp((), ()); /// let _ = North.half("", "");
/// let _ = South.bsp((), ()); /// let _ = South.half("", "");
/// let _ = East.bsp((), ()); /// let _ = East.half("", "");
/// let _ = West.bsp((), ()); /// let _ = West.half("", "");
/// ``` /// ```
pub const fn half <T: Screen> (&self, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn half <T: Screen> (&self, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> {
thunk(move|to: &mut T|{ thunk(move|to: &mut T|{

View file

@ -3,8 +3,9 @@ use super::*;
/// Point with size. /// Point with size.
/// ///
/// ``` /// ```
/// let xywh = tengri::XYWH(0u16, 0, 0, 0); /// use tengri::space::{XY, XYWH};
/// assert_eq!(tengri::XYWH(10u16, 10, 20, 20).center(), tengri::XY(20, 20)); /// let xywh = XYWH(0u16, 0, 0, 0);
/// assert_eq!(XYWH(10u16, 10, 20, 20).center(), XY(20, 20));
/// ``` /// ```
/// ///
/// * [ ] TODO: origin field (determines at which corner/side is X0 Y0) /// * [ ] TODO: origin field (determines at which corner/side is X0 Y0)

View file

@ -645,9 +645,9 @@ pub const fn border <T, S: BorderStyle> (on: bool, style: S, draw: impl Draw<Tui
/// Draw TUI content or its error message. /// Draw TUI content or its error message.
/// ///
/// ``` /// ```
/// let _ = tengri::tui::catcher(Ok(Some("hello"))); /// let _ = tengri::term::catcher(Ok(Some("hello")));
/// let _ = tengri::tui::catcher(Ok(None)); /// let _ = tengri::term::catcher(Ok(None));
/// let _ = tengri::tui::catcher(Err("draw fail".into())); /// let _ = tengri::term::catcher(Err("draw fail".into()));
/// ``` /// ```
pub fn catcher <T: Draw<Tui>> (result: Usually<T>) -> impl Draw<Tui> { pub fn catcher <T: Draw<Tui>> (result: Usually<T>) -> impl Draw<Tui> {
thunk(move|to: &mut Tui|match result { thunk(move|to: &mut Tui|match result {