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::*;
pub use crate::space::*;
/// 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
} });
mod draw;
pub use self::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 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!()
}
}
mod view;
pub use self::view::*;
/// Emit a [Draw]able.
///
/// Speculative. How to avoid conflicts with [Draw] proper?
pub trait View<T: Screen> {
fn view (&self) -> impl Draw<T>;
}
mod thunk;
pub use self::thunk::*;
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)
}
}
mod screen;
pub use self::screen::*;
/// 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> {
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!()
}
}