mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-07-17 07:56:56 +02:00
more space/ and draw/ modules
- 26 errors and 16 doctest fails - getting there, perpetually
This commit is contained in:
parent
42a1807c2b
commit
145047b7ff
15 changed files with 269 additions and 232 deletions
117
src/draw.rs
117
src/draw.rs
|
|
@ -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
60
src/draw/draw.rs
Normal 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
34
src/draw/screen.rs
Normal 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
16
src/draw/thunk.rs
Normal 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
8
src/draw/view.rs
Normal 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>;
|
||||||
|
}
|
||||||
10
src/eval.rs
10
src/eval.rs
|
|
@ -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> (
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
118
src/space.rs
118
src/space.rs
|
|
@ -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
35
src/space/coord.rs
Normal 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
46
src/space/iter.rs
Normal 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!() })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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
28
src/space/size.rs
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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|{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue