uuugh
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
🪞👃🪞 2025-09-09 01:07:19 +03:00
parent ca862b9802
commit 3ebdf9e71f
38 changed files with 602 additions and 1108 deletions

View file

@ -10,22 +10,25 @@
)* }; )* };
); );
/// Define a trait an implement it for read-only wrapper types. */ /// Define a trait and implement it for read-only wrapper types.
#[macro_export] macro_rules! flex_trait ( #[macro_export] macro_rules! flex_trait (
($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(<$dtt:tt>)? $(+$dep2:ident $(<$dtt2:tt>)?)*)? { ($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(<$dtt:tt>)? $(+$dep2:ident $(<$dtt2:tt>)?)*)? {
$(fn $fn:ident (&$self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)* $(fn $fn:ident $(<$($fl:lifetime),*>)? (& $($fl2:lifetime)* $self:ident $(, $arg:ident:$ty:ty)*) $(-> $ret:ty)? $body:block)*
}) => { }) => {
pub trait $Trait $(<$($A: $T),+>)? $(:$dep $(<$dtt>)? $(+$dep2 $(<$dtt2>)?)*)? { pub trait $Trait $(<$($A: $T),+>)? $(:$dep $(<$dtt>)? $(+$dep2 $(<$dtt2>)?)*)? {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret $body)* $(fn $fn $(<$($fl),*>)? (& $($fl2)* $self $(,$arg:$ty)*) $(-> $ret)? $body)*
} }
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ { impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* $(fn $fn $(<$($fl),*>)? (& $($fl2)* $self $(,$arg:$ty)*) $(-> $ret)? { (*$self).$fn($($arg),*) })*
} }
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ { impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (**$self).$fn($($arg),*) })* $(fn $fn $(<$($fl),*>)? (& $($fl2)* $self $(,$arg:$ty)*) $(-> $ret)? { (**$self).$fn($($arg),*) })*
} }
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<_T_> { impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<_T_> {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* $(fn $fn $(<$($fl),*>)? (& $($fl2)* $self $(,$arg:$ty)*) $(-> $ret)? { (*$self).$fn($($arg),*) })*
}
impl<$($($A: $T,)+)?> $Trait $(<$($A),+>)? for Box<dyn $Trait $(<$($A),+>)?> {
$(fn $fn $(<$($fl),*>)? (& $($fl2)* $self $(,$arg:$ty)*) $(-> $ret)? { (**$self).$fn($($arg),*) })*
} }
//impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { //impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> {
//$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { //$(fn $fn (&$self $(,$arg:$ty)*) -> $ret {
@ -40,21 +43,24 @@
//} //}
}); });
/// Define a trait an implement it for read-only wrapper types. */ /// Define a trait an implement it for read-only wrapper types. */
#[macro_export] macro_rules! flex_trait_unsized ( #[macro_export] macro_rules! flex_trait_sized (
($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(<$dtt:tt>)? $(+$dep2:ident $(<$dtt2:tt>)?)*)? { ($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(<$dtt:tt>)? $(+$dep2:ident $(<$dtt2:tt>)?)*)? {
$(fn $fn:ident (&$self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)* $(fn $fn:ident (&$self:ident $(, $arg:ident:$ty:ty)*) $(-> $ret:ty)? $body:block)*
}) => { }) => {
pub trait $Trait $(<$($A: $T),+>)? : $($dep $(<$dtt>+)? $($dep2 $(<$dtt2>)?)*+)? ?Sized { pub trait $Trait $(<$($A: $T),+>)? : $($dep $(<$dtt>+)? $($dep2 $(<$dtt2>)?)*+)? Sized {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret $body)* $(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? $body)*
} }
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ { impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* $(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? { (*$self).$fn($($arg),*) })*
} }
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ { impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (**$self).$fn($($arg),*) })* $(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? { (**$self).$fn($($arg),*) })*
} }
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<_T_> { impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<_T_> {
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* $(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? { (*$self).$fn($($arg),*) })*
}
impl<$($($A: $T,)+)?> $Trait $(<$($A),+>)? for Box<dyn $Trait $(<$($A),+>)?> {
$(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? { (**$self).$fn($($arg),*) })*
} }
//impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { //impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> {
//$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { //$(fn $fn (&$self $(,$arg:$ty)*) -> $ret {

View file

@ -1,40 +1,110 @@
use crate::*; use crate::*;
pub trait HasContent<O: Out> { fn content (&self) -> impl Content<O>; }
/// Composable renderable with static dispatch. pub trait Content<O: Out>: Draw<O> + Layout<O> {}
pub trait Content<E: Out>: Sized { impl<O: Out, T: Draw<O> + Layout<O>> Content<O> for T {}
/// Return opaque [Draw]able. impl<'a, O: Out> AsRef<dyn Draw<O> + 'a> for dyn Content<O> + 'a { fn as_ref (&self) -> &(dyn Draw<O> + 'a) { self } }
fn content (&self) -> impl Draw<E> + Layout<E> + '_ { () } impl<'a, O: Out> AsRef<dyn Layout<O> + 'a> for dyn Content<O> + 'a { fn as_ref (&self) -> &(dyn Layout<O> + 'a) { self } }
/// Drawable with dynamic dispatch.
pub trait Draw<O: Out> { fn draw (&self, to: &mut O); }
impl<O: Out> Draw<O> for () { fn draw (&self, to: &mut O) {} }
impl<O: Out> Draw<O> for fn(&mut O) { fn draw (&self, to: &mut O) { (*self)(to) } }
impl<O: Out> Draw<O> for Box<dyn Draw<O>> { fn draw (&self, to: &mut O) { (**self).draw(to) } }
impl<O: Out, D: Draw<O>> Draw<O> for &D { fn draw (&self, to: &mut O) { (*self).draw(to) } }
impl<O: Out, D: Draw<O>> Draw<O> for &mut D { fn draw (&self, to: &mut O) { (**self).draw(to) } }
/// Drawable area of display.
pub trait Layout<O: Out> {
fn x (&self, to: O::Area) -> O::Unit { to.x() }
fn y (&self, to: O::Area) -> O::Unit { to.y() }
fn min_w (&self, to: O::Area) -> O::Unit { 0.into() }
fn max_w (&self, to: O::Area) -> O::Unit { to.w() }
fn w (&self, to: O::Area) -> O::Unit {
to.w().max(self.min_w(to)).min(self.max_w(to))
} }
fn min_h (&self, to: O::Area) -> O::Unit { 0.into() }
/// The platonic ideal unit of [Content]: fn max_h (&self, to: O::Area) -> O::Unit { to.h() }
/// total emptiness at dead center (e=1vg^sqrt(-1)) fn h (&self, to: O::Area) -> O::Unit {
impl<E: Out> Content<E> for () {} to.h().max(self.min_h(to)).min(self.max_h(to))
}
impl<E: Out, T: Draw<E> + Layout<E>> Content<E> for fn()->T { fn layout (&self, to: O::Area) -> O::Area {
fn content (&self) -> impl Draw<E> + Layout<E> + '_ { [self.x(to), self.y(to), self.w(to), self.h(to)].into()
self()
} }
} }
/// Implement composable content for a struct. impl<O: Out> Layout<O> for () {
#[macro_export] macro_rules! content { fn x (&self, a: O::Area) -> O::Unit { a.x() }
fn y (&self, a: O::Area) -> O::Unit { a.y() }
// Implement for all [Out]s. fn w (&self, _: O::Area) -> O::Unit { 0.into() }
(|$self:ident:$Struct:ty| $content:expr) => { fn min_w (&self, _: O::Area) -> O::Unit { 0.into() }
impl<E: Out> Content<E> for $Struct { fn max_w (&self, _: O::Area) -> O::Unit { 0.into() }
fn content (&$self) -> impl Draw<E> + Layout<E> + '_ { Some($content) } fn h (&self, _: O::Area) -> O::Unit { 0.into() }
fn min_h (&self, _: O::Area) -> O::Unit { 0.into() }
fn max_h (&self, _: O::Area) -> O::Unit { 0.into() }
fn layout (&self, a: O::Area) -> O::Area { [a.x(), a.y(), 0.into(), 0.into()].into() }
} }
};
// Implement for specific [Out]. impl<O: Out, L: Layout<O>> Layout<O> for &L {
($Out:ty:| fn x (&self, a: O::Area) -> O::Unit { (*self).x(a) }
$self:ident: fn y (&self, a: O::Area) -> O::Unit { (*self).y(a) }
$Struct:ident$(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)? fn w (&self, a: O::Area) -> O::Unit { (*self).w(a) }
|$content:expr) => { fn min_w (&self, a: O::Area) -> O::Unit { (*self).min_w(a) }
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Out> fn max_w (&self, a: O::Area) -> O::Unit { (*self).max_w(a) }
for $Struct $(<$($($L)? $($T)?),+>)? { fn h (&self, a: O::Area) -> O::Unit { (*self).h(a) }
fn content (&$self) -> impl Draw<$Out> + Layout<$Out> + '_ { $content } fn min_h (&self, a: O::Area) -> O::Unit { (*self).min_h(a) }
fn max_h (&self, a: O::Area) -> O::Unit { (*self).max_h(a) }
fn layout (&self, a: O::Area) -> O::Area { (*self).layout(a) }
} }
};
impl<O: Out, L: Layout<O>> Layout<O> for &mut L {
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
fn min_w (&self, a: O::Area) -> O::Unit { (**self).min_w(a) }
fn max_w (&self, a: O::Area) -> O::Unit { (**self).max_w(a) }
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
fn min_h (&self, a: O::Area) -> O::Unit { (**self).min_h(a) }
fn max_h (&self, a: O::Area) -> O::Unit { (**self).max_h(a) }
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
}
impl<O: Out> Layout<O> for Box<dyn Layout<O>> {
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
fn min_w (&self, a: O::Area) -> O::Unit { (**self).min_w(a) }
fn max_w (&self, a: O::Area) -> O::Unit { (**self).max_w(a) }
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
fn min_h (&self, a: O::Area) -> O::Unit { (**self).min_h(a) }
fn max_h (&self, a: O::Area) -> O::Unit { (**self).max_h(a) }
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
}
impl<O: Out, L: Layout<O>> Layout<O> for Option<L> {
fn x (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.x(to)).unwrap_or(to.x())
}
fn y (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.y(to)).unwrap_or(to.y())
}
fn min_w (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.min_w(to)).unwrap_or(0.into())
}
fn max_w (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.max_w(to)).unwrap_or(0.into())
}
fn w (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.w(to)).unwrap_or(0.into())
}
fn min_h (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.min_h(to)).unwrap_or(0.into())
}
fn max_h (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.max_h(to)).unwrap_or(0.into())
}
fn h (&self, to: O::Area) -> O::Unit {
self.as_ref().map(|c|c.h(to)).unwrap_or(0.into())
}
fn layout (&self, to: O::Area) -> O::Area {
self.as_ref().map(|c|c.layout([self.x(to), self.y(to), self.w(to), self.h(to)].into()))
.unwrap_or([to.x(), to.y(), 0.into(), 0.into()].into())
}
} }

View file

@ -1,94 +1,27 @@
use crate::*; use crate::*;
/// Drawable with dynamic dispatch. pub struct Bound<O: Out, D>(pub O::Area, pub D);
pub trait Draw<O: Out> {
/// Write data to display. impl<O: Out, D: Content<O>> HasContent<O> for Bound<O, D> {
fn draw (&self, to: &mut O); fn content (&self) -> &impl Content<O> { &self.1 }
} }
impl<O: Out> Draw<O> for fn(&mut O) { impl<O: Out, T> Layout<O> for Bound<O, T> {
fn x (&self, _: O::Area) -> O::Unit { self.0.x() }
fn y (&self, _: O::Area) -> O::Unit { self.0.y() }
fn w (&self, _: O::Area) -> O::Unit { self.0.w() }
fn min_w (&self, _: O::Area) -> O::Unit { self.0.w() }
fn max_w (&self, _: O::Area) -> O::Unit { self.0.w() }
fn h (&self, _: O::Area) -> O::Unit { self.0.h() }
fn min_h (&self, _: O::Area) -> O::Unit { self.0.w() }
fn max_h (&self, _: O::Area) -> O::Unit { self.0.w() }
}
impl<O: Out, T: Draw<O>> Draw<O> for Bound<O, T> {
fn draw (&self, to: &mut O) { fn draw (&self, to: &mut O) {
self(to) let area = to.area();
} *to.area_mut() = self.0;
} self.1.draw(to);
*to.area_mut() = area;
impl<O: Out> Draw<O> for () { fn draw (&self, _: &mut O) {} }
impl<O: Out, T: Draw<O>> Draw<O> for &T {
fn draw (&self, to: &mut O) { (*self).draw(to) }
}
impl<'x, O: Out> Draw<O> for &(dyn Draw<O> + 'x) {
fn draw (&self, to: &mut O) {
(*self).draw(to)
}
}
impl<'x, O: Out> Draw<O> for &mut (dyn Draw<O> + 'x) {
fn draw (&self, to: &mut O) {
(**self).draw(to)
}
}
impl<O: Out, T: Draw<O>> Draw<O> for RwLock<T> {
fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) }
}
impl<O: Out, T: Draw<O>> Draw<O> for [T] {
fn draw (&self, to: &mut O) {
for draw in self.iter() {
draw.draw(to)
}
}
}
//impl<O: Out, T: Draw<O>> Draw<O> for &mut T {
//fn draw (&self, to: &mut O) {
//(**self).draw(to)
//}
//}
//impl<O: Out, T: Iterator<Item = U>, U: Draw<O>> Draw<O> for &mut T {
//fn draw (&self, to: &mut O) {
//for draw in *self {
//draw.draw(to)
//}
//}
//}
/// Implement custom drawing for a struct.
#[macro_export] macro_rules! draw {
// Implement for all [Out] backends.
(|$self:ident:$Struct:ident $(<
$($L:lifetime),* $($T:ident $(:$Trait:path)?),*
>)?, $to:ident | $draw:expr) => {
impl <$($($L),*)? O: Out, $($($T$(:$Trait)?),*)?> Draw<O>
for $Struct $(<$($L),* $($T),*>)? {
fn draw (&$self, $to: &mut O) { $draw }
}
};
// Implement for a specific [Out] backend.
($O:ty:|
$self:ident:
$Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?, $to:ident
|$draw:expr) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Draw<$O>
for $Struct $(<$($($L)? $($T)?),+>)? {
fn draw (&$self, $to: &mut $O) { $draw }
}
};
}
draw!(|self: Arc<T: Draw<O>>, to|(**self).draw(to));
draw!(|self: Box<T: Draw<O>>, to|(**self).draw(to));
//draw!(|self: Option<T: Draw<O>>, to|if let Some(draw) = self { draw.draw(to) });
impl<O: Out, T: Draw<O>> Draw<O> for Option<T> {
fn draw (&self, to: &mut O) {
if let Some(draw) = self {
draw.draw(to)
}
} }
} }

View file

@ -1,98 +1,10 @@
use crate::*; use crate::*;
pub trait Layout<O: Out> {
fn x (&self, area: O::Area) -> O::Unit {
area.x()
}
fn y (&self, area: O::Area) -> O::Unit {
area.y()
}
fn min_w (&self, _area: O::Area) -> O::Unit {
0.into()
}
fn max_w (&self, area: O::Area) -> O::Unit {
area.w()
}
fn min_h (&self, _area: O::Area) -> O::Unit {
0.into()
}
fn max_h (&self, area: O::Area) -> O::Unit {
area.h()
}
fn layout (&self, area: O::Area) -> O::Area {
O::Area::from([
self.x(area),
self.y(area),
area.w().max(self.min_w(area)).min(self.max_w(area)),
area.h().max(self.min_h(area)).min(self.max_h(area)),
])
}
}
#[macro_export] macro_rules! layout {
// Implement for all [Out] backends.
(|$self:ident:$Struct:ident $(<
$($L:lifetime),* $($T:ident $(:$Trait:path)?),*
>)?, $to:ident|$($method:ident = |$area:ident|$body:expr;)*) => {
impl <$($($L),*)? O: Out, $($($T$(:$Trait)?),*)?> Layout<O>
for $Struct $(<$($L),* $($T),*>)? {
$(fn $method (&$self, $area: O::Area) -> O::Area {
$body
})*
}
};
// Implement for a specific [Out] backend.
($O:ty:|
$self:ident:
$Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?,
$to:ident
|$($method:ident = |$area:ident|$body:expr;)*) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Layout<$O>
for $Struct $(<$($($L)? $($T)?),+>)? {
$(fn $method (&$self, $area: <$O as Out>::Area) -> <$O as Out>::Area {
$body
})*
}
};
}
impl<O: Out> Layout<O> for () {}
impl<O: Out, L: Layout<O>> Layout<O> for &L { /*FIXME*/ }
impl<O: Out, L: Layout<O>> Layout<O> for RwLock<L> { /*FIXME*/ }
impl<O: Out, L: Layout<O>> Layout<O> for Option<L> { /*FIXME*/ }
//impl<O: Out> Layout<O> for fn(&mut O) {}
impl<O: Out, L: Layout<O>> Layout<O> for Arc<L> {
fn layout (&self, to: O::Area) -> O::Area {
(**self).layout(to)
}
}
impl<'x, O: Out> Layout<O> for &(dyn Draw<O> + 'x) {
fn layout (&self, to: O::Area) -> O::Area {
Fill::xy(self).layout(to)
}
}
mod layout_align; pub use self::layout_align::*; mod layout_align; pub use self::layout_align::*;
mod layout_bsp; pub use self::layout_bsp::*; mod layout_bsp; pub use self::layout_bsp::*;
mod layout_cond; pub use self::layout_cond::*; mod layout_cond; pub use self::layout_cond::*;
mod layout_expand; pub use self::layout_expand::*;
mod layout_fill; pub use self::layout_fill::*;
mod layout_fixed; pub use self::layout_fixed::*;
mod layout_map; pub use self::layout_map::*; mod layout_map; pub use self::layout_map::*;
mod layout_margin; pub use self::layout_margin::*; mod layout_pad; pub use self::layout_pad::*;
mod layout_max; pub use self::layout_max::*; mod layout_move; pub use self::layout_move::*;
mod layout_min; pub use self::layout_min::*; mod layout_size; pub use self::layout_size::*;
mod layout_padding; pub use self::layout_padding::*;
mod layout_pull; pub use self::layout_pull::*;
mod layout_push; pub use self::layout_push::*;
mod layout_shrink; pub use self::layout_shrink::*;
mod layout_stack; //pub use self::layout_stack::*; mod layout_stack; //pub use self::layout_stack::*;

View file

@ -6,7 +6,7 @@
//! assert_eq!(Draw::layout(item, area), expected); //! assert_eq!(Draw::layout(item, area), expected);
//! }; //! };
//! //!
//! let four = ||Fixed::xy(4, 4, ""); //! let four = ||Fixed::XY(4, 4, "");
//! test(area, &Align::nw(four()), [10, 10, 4, 4]); //! test(area, &Align::nw(four()), [10, 10, 4, 4]);
//! test(area, &Align::n(four()), [18, 10, 4, 4]); //! test(area, &Align::n(four()), [18, 10, 4, 4]);
//! test(area, &Align::ne(four()), [26, 10, 4, 4]); //! test(area, &Align::ne(four()), [26, 10, 4, 4]);
@ -16,7 +16,7 @@
//! test(area, &Align::sw(four()), [10, 26, 4, 4]); //! test(area, &Align::sw(four()), [10, 26, 4, 4]);
//! test(area, &Align::w(four()), [10, 18, 4, 4]); //! test(area, &Align::w(four()), [10, 18, 4, 4]);
//! //!
//! let two_by_four = ||Fixed::xy(4, 2, ""); //! let two_by_four = ||Fixed::XY(4, 2, "");
//! test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]); //! test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]);
//! test(area, &Align::n(two_by_four()), [18, 10, 4, 2]); //! test(area, &Align::n(two_by_four()), [18, 10, 4, 2]);
//! test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]); //! test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]);
@ -27,13 +27,12 @@
//! test(area, &Align::w(two_by_four()), [10, 19, 4, 2]); //! test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
//! ``` //! ```
use crate::*; use crate::*;
use Alignment::*;
/// 9th of area to place. /// 9th of area to place.
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Copy, Clone, Default)]
pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
pub struct Align<T>(Alignment, T); pub struct Align<T>(Alignment, T);
impl<T> Align<T> { impl<T> Align<T> {
#[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) } #[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) }
#[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) } #[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) }
@ -47,39 +46,24 @@ impl<T> Align<T> {
#[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) } #[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) }
#[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) } #[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) }
} }
impl<O: Out, T: Content<O>> Draw<O> for Align<T> {
impl<E: Out, T: Layout<E>> Layout<E> for Align<T> { fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), &self.1).draw(to) }
fn layout (&self, on: E::Area) -> E::Area { }
self.0.align(on, &self.1) impl<O: Out, T: Layout<O>> Layout<O> for Align<T> {
fn x (&self, to: O::Area) -> O::Unit {
match self.0 {
NW | W | SW => to.x(),
N | Center | S => to.x().plus(to.w() / 2.into()).minus(self.1.w(to) / 2.into()),
NE | E | SE => to.x().plus(to.w()).minus(self.1.w(to)),
_ => todo!(),
} }
} }
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Align<T> { fn y (&self, to: O::Area) -> O::Unit {
fn draw (&self, to: &mut E) { match self.0 {
to.place_at(self.layout(to.area()), &self.1) NW | N | NE => to.y(),
W | Center | E => to.y().plus(to.h() / 2.into()).minus(self.1.h(to) / 2.into()),
SW | S | SE => to.y().plus(to.h()).minus(self.1.h(to)),
_ => todo!(),
} }
} }
impl Alignment {
fn align <E: Out> (&self, on: E::Area, content: &impl Layout<E>) -> E::Area {
use Alignment::*;
let it = content.layout(on).xywh();
let cx = on.x()+(on.w().minus(it.w())/2.into());
let cy = on.y()+(on.h().minus(it.h())/2.into());
let fx = (on.x()+on.w()).minus(it.w());
let fy = (on.y()+on.h()).minus(it.h());
let [x, y] = match self {
Center => [cx, cy],
X => [cx, it.y()],
Y => [it.x(), cy],
NW => [on.x(), on.y()],
N => [cx, on.y()],
NE => [fx, on.y()],
W => [on.x(), cy],
E => [fx, cy],
SW => [on.x(), fy],
S => [cx, fy],
SE => [fx, fy],
};
[x, y, it.w(), it.h()].into()
}
} }

View file

@ -1,7 +1,6 @@
use crate::*; use crate::*;
use Direction::*;
/// A split or layer. /// A binary split or layer.
pub struct Bsp<Head, Tail>( pub struct Bsp<Head, Tail>(
pub(crate) Direction, pub(crate) Direction,
/// First element. /// First element.
@ -19,31 +18,79 @@ impl<Head, Tail> Bsp<Head, Tail> {
#[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) } #[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) }
} }
impl< impl<O: Out, Head: Content<O>, Tail: Content<O>> Draw<O> for Bsp<Head, Tail> {
O: Out,
Head: Draw<O> + Layout<O>,
Tail: Draw<O> + Layout<O>
> Draw<O> for Bsp<Head, Tail> {
fn draw (&self, to: &mut O) { fn draw (&self, to: &mut O) {
let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2); match self.0 {
if self.0 == Below { South => {
to.place_at(a, &self.1); panic!("{}", self.1.h(to.area()));
to.place_at(b, &self.2); let area_1 = self.1.layout(to.area());
} else { let area_2 = self.2.layout([
to.place_at(b, &self.2); to.area().x(),
to.place_at(a, &self.1); to.area().y().plus(area_1.h()),
to.area().w(),
to.area().h().minus(area_1.h())
].into());
panic!("{area_1:?} {area_2:?}");
to.place_at(area_1, &self.1);
to.place_at(area_2, &self.2);
},
_ => todo!("{:?}", self.0)
}
//let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2);
//panic!("{a:?} {b:?}");
//if self.0 == Below {
//to.place_at(a, &self.1);
//to.place_at(b, &self.2);
//} else {
//to.place_at(b, &self.2);
//to.place_at(a, &self.1);
//}
} }
} }
}
impl<O: Out, Head: Layout<O>, Tail: Layout<O>> Layout<O> for Bsp<Head, Tail> { impl<O: Out, Head: Layout<O>, Tail: Layout<O>> Layout<O> for Bsp<Head, Tail> {
fn w (&self, area: O::Area) -> O::Unit {
match self.0 {
North | South | Above | Below => self.1.w(area).max(self.2.w(area)),
East | West => self.1.min_w(area).plus(self.2.w(area)),
}
}
fn min_w (&self, area: O::Area) -> O::Unit {
match self.0 {
North | South | Above | Below => self.1.min_w(area).max(self.2.min_w(area)),
East | West => self.1.min_w(area).plus(self.2.min_w(area)),
}
}
fn max_w (&self, area: O::Area) -> O::Unit {
match self.0 {
North | South | Above | Below => self.1.max_w(area).max(self.2.max_w(area)),
East | West => self.1.max_w(area).plus(self.2.max_w(area)),
}
}
fn h (&self, area: O::Area) -> O::Unit {
match self.0 {
East | West | Above | Below => self.1.h(area).max(self.2.h(area)),
North | South => self.1.h(area).plus(self.2.h(area)),
}
}
fn min_h (&self, area: O::Area) -> O::Unit {
match self.0 {
East | West | Above | Below => self.1.min_h(area).max(self.2.min_h(area)),
North | South => self.1.min_h(area).plus(self.2.min_h(area)),
}
}
fn max_h (&self, area: O::Area) -> O::Unit {
match self.0 {
North | South | Above | Below => self.1.max_h(area).max(self.2.max_h(area)),
East | West => self.1.max_h(area).plus(self.2.max_h(area)),
}
}
fn layout (&self, area: O::Area) -> O::Area { fn layout (&self, area: O::Area) -> O::Area {
bsp_areas(area, self.0, &self.1, &self.2)[2] bsp_areas(area, self.0, &self.1, &self.2)[2]
} }
} }
fn bsp_areas <O: Out> ( fn bsp_areas <O: Out, A: Layout<O>, B: Layout<O>> (
area: O::Area, direction: Direction, a: &impl Layout<O>, b: &impl Layout<O>, area: O::Area, direction: Direction, a: &A, b: &B,
) -> [O::Area;3] { ) -> [O::Area;3] {
let [x, y, w, h] = area.xywh(); let [x, y, w, h] = area.xywh();
let [aw, ah] = a.layout(area).wh(); let [aw, ah] = a.layout(area).wh();

View file

@ -2,54 +2,45 @@ use crate::*;
/// Show an item only when a condition is true. /// Show an item only when a condition is true.
pub struct When<O, T>(bool, T, PhantomData<O>); pub struct When<O, T>(bool, T, PhantomData<O>);
impl<O, T> When<O, T> { impl<O: Out, T: Content<O>> When<O, T> {
/// Create a binary condition. /// Create a binary condition.
pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) } pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) }
} }
impl<O: Out, T: Layout<O>> Layout<O> for When<O, T> { impl<O: Out, T: Layout<O>> Layout<O> for When<O, T> {
fn layout (&self, to: O::Area) -> O::Area { fn layout (&self, to: O::Area) -> O::Area {
let Self(cond, item, ..) = self; let Self(cond, item, ..) = self;
let mut area = O::Area::zero(); if *cond { item.layout(to) } else { O::Area::zero().into() }
if *cond {
let item_area = item.layout(to);
area[0] = item_area.x();
area[1] = item_area.y();
area[2] = item_area.w();
area[3] = item_area.h();
}
area.into()
} }
} }
impl<O: Out, T: Draw<O>> Draw<O> for When<O, T> { impl<O: Out, T: Content<O>> Draw<O> for When<O, T> {
fn draw (&self, to: &mut O) { fn draw (&self, to: &mut O) {
let Self(cond, item, ..) = self; let Self(cond, item, ..) = self;
if *cond { item.draw(to) } if *cond { Bound(self.layout(to.area()), item).draw(to) }
} }
} }
/// Show one item if a condition is true and another if the condition is false /// Show one item if a condition is true and another if the condition is false
pub struct Either<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>>(pub bool, pub A, pub B, pub PhantomData<E>); pub struct Either<E: Out, A, B>(pub bool, pub A, pub B, pub PhantomData<E>);
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Either<E, A, B> { impl<E: Out, A: Content<E>, B: Content<E>> Either<E, A, B> {
/// Create a ternary view condition. /// Create a ternary view condition.
pub const fn new (c: bool, a: A, b: B) -> Self { pub const fn new (c: bool, a: A, b: B) -> Self {
Self(c, a, b, PhantomData) Self(c, a, b, PhantomData)
} }
} }
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Layout<E> for Either<E, A, B> { impl<E: Out, A: Layout<E>, B: Layout<E>> Layout<E> for Either<E, A, B> {
fn layout (&self, to: E::Area) -> E::Area { fn layout (&self, to: E::Area) -> E::Area {
let Self(cond, a, b, ..) = self; let Self(cond, a, b, ..) = self;
if *cond { a.layout(to) } else { b.layout(to) } if *cond { a.layout(to) } else { b.layout(to) }
} }
} }
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Draw<E> for Either<E, A, B> { impl<E: Out, A: Content<E>, B: Content<E>> Draw<E> for Either<E, A, B> {
fn draw (&self, to: &mut E) { fn draw (&self, to: &mut E) {
let Self(cond, a, b, ..) = self; let Self(cond, a, b, ..) = self;
if *cond { a.draw(to) } else { b.draw(to) } let area = self.layout(to.area());
if *cond { Bound(area, a).draw(to) } else { Bound(area, b).draw(to) }
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -116,7 +107,7 @@ impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Draw<E> for Either<
//return Ok(Some(match words.next() { //return Ok(Some(match words.next() {
//Some(Token{value: Key($x),..}) => Self::x(content), //Some(Token{value: Key($x),..}) => Self::x(content),
//Some(Token{value: Key($y),..}) => Self::y(content), //Some(Token{value: Key($y),..}) => Self::y(content),
//Some(Token{value: Key($xy),..}) => Self::xy(content), //Some(Token{value: Key($xy),..}) => Self::XY(content),
//_ => unreachable!() //_ => unreachable!()
//})) //}))
//} else { //} else {
@ -134,7 +125,7 @@ impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Draw<E> for Either<
//state.give_or_fail(words, ||"y: no unit")?, //state.give_or_fail(words, ||"y: no unit")?,
//state.give_or_fail(words, ||"y: no content")?, //state.give_or_fail(words, ||"y: no content")?,
//), //),
//Some(Token { value: Key($x), .. }) => Self::xy( //Some(Token { value: Key($x), .. }) => Self::XY(
//state.give_or_fail(words, ||"xy: no unit x")?, //state.give_or_fail(words, ||"xy: no unit x")?,
//state.give_or_fail(words, ||"xy: no unit y")?, //state.give_or_fail(words, ||"xy: no unit y")?,
//state.give_or_fail(words, ||"xy: no content")? //state.give_or_fail(words, ||"xy: no content")?

View file

@ -1,39 +0,0 @@
use crate::*;
pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Expand<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self { Self::X(x, item) }
#[inline] pub const fn y (y: U, item: A) -> Self { Self::Y(y, item) }
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self { Self::XY(x, y, item) }
}
impl<O: Out, T: Draw<O> + Layout<O>> Content<O> for Expand<O::Unit, T> {
fn content (&self) -> impl Draw<O> + Layout<O> + '_ {
use Expand::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<O: Out, T: Draw<O> + Layout<O>> Draw<O> for Expand<O::Unit, T> {
fn draw (&self, to: &mut O) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Expand<U, T> {
#[inline] pub fn dx (&self) -> U {
use Expand::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Expand::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<O: Out, T: Layout<O>> Layout<O> for Expand<O::Unit, T> {
fn layout (&self, to: O::Area) -> O::Area {
[to.x(), to.y(), to.w().plus(self.dx()), to.h().plus(self.dy())].into()
}
}

View file

@ -1,55 +0,0 @@
use crate::*;
pub enum Fill<A> {
/// Use maximum width of area.
X(A),
/// Use maximum height of area.
Y(A),
/// Use maximum width and height of area.
XY(A)
}
impl<T> Fill<T> {
#[inline] pub const fn x (item: T) -> Self {
Self::X(item)
}
#[inline] pub const fn y (item: T) -> Self {
Self::Y(item)
}
#[inline] pub const fn xy (item: T) -> Self {
Self::XY(item)
}
#[inline] pub const fn has_x (&self) -> bool {
matches!(self, Self::X(_) | Self::XY(_))
}
#[inline] pub const fn has_y (&self) -> bool {
matches!(self, Self::Y(_) | Self::XY(_))
}
#[inline] pub const fn content (&self) -> &T {
use Fill::*;
match self { X(item) | Y(item) | XY(item) => item }
}
}
impl<O: Out, T: Draw<O>> Draw<O> for Fill<T> {
fn draw (&self, to: &mut O) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<O: Out, T: Draw<O>> Layout<O> for Fill<T> {
fn min_w (&self, area: O::Area) -> O::Unit {
if self.has_x() {
area.w()
} else {
0.into()
}
}
fn min_h (&self, area: O::Area) -> O::Unit {
if self.has_y() {
area.h()
} else {
0.into()
}
}
}

View file

@ -1,47 +0,0 @@
use crate::*;
pub enum Fixed<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Fixed<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Fixed::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<U: Coordinate, T> Fixed<U, T> {
#[inline] pub fn dx (&self) -> U {
use Fixed::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Fixed::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<O: Out, T: Draw<O>> Draw<O> for Fixed<O::Unit, T> {
fn draw (&self, to: &mut O) {
let area = Layout::<O>::layout(&self, to.area());
to.place_at(area, &self.content())
}
}
impl<O: Out, T> Layout<O> for Fixed<O::Unit, T> {
fn layout (&self, area: O::Area) -> O::Area {
[area.x(), area.y(), match self {
Fixed::X(w, _) | Fixed::XY(w, _, _) => *w, _ => area.w()
}, match self {
Fixed::Y(h, _) | Fixed::XY(_, h, _) => *h, _ => area.h()
}].into()
}
}

View file

@ -31,7 +31,7 @@ macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{
O, A, Push<O::Unit, Align<Fixed<O::Unit, Fill<B>>>>, I, F, fn(A, usize)->B O, A, Push<O::Unit, Align<Fixed<O::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
> where > where
O: Out, O: Out,
B: Draw<O> + Layout<O>, B: Draw<O>,
I: Iterator<Item = A> + Send + Sync + 'a, I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a F: Fn() -> I + Send + Sync + 'a
{ {
@ -61,14 +61,14 @@ macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{
} }
}); });
impl_map_direction!(east, x, w); impl_map_direction!(east, X, w);
impl_map_direction!(south, y, n); impl_map_direction!(south, Y, n);
impl_map_direction!(west, x, e); impl_map_direction!(west, X, e);
impl_map_direction!(north, y, s); impl_map_direction!(north, Y, s);
impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where
O: Out, O: Out,
B: Draw<O> + Layout<O>, B: Layout<O>,
I: Iterator<Item = A> + Send + Sync + 'a, I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a,
G: Fn(A, usize)->B + Send + Sync G: Fn(A, usize)->B + Send + Sync
@ -94,7 +94,7 @@ impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where
} }
impl<'a, O, A, B, I, F, G> Draw<O> for Map<O, A, B, I, F, G> where impl<'a, O, A, B, I, F, G> Draw<O> for Map<O, A, B, I, F, G> where
O: Out, O: Out,
B: Draw<O> + Layout<O>, B: Content<O>,
I: Iterator<Item = A> + Send + Sync + 'a, I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a,
G: Fn(A, usize)->B + Send + Sync G: Fn(A, usize)->B + Send + Sync
@ -115,25 +115,25 @@ impl<'a, O, A, B, I, F, G> Draw<O> for Map<O, A, B, I, F, G> where
#[inline] pub fn map_south<O: Out>( #[inline] pub fn map_south<O: Out>(
item_offset: O::Unit, item_offset: O::Unit,
item_height: O::Unit, item_height: O::Unit,
item: impl Draw<O> + Layout<O> item: impl Content<O>
) -> impl Draw<O> + Layout<O> { ) -> impl Content<O> {
Push::y(item_offset, Fixed::y(item_height, Fill::x(item))) Push::Y(item_offset, Fixed::Y(item_height, Fill::X(item)))
} }
#[inline] pub fn map_south_west<O: Out>( #[inline] pub fn map_south_west<O: Out>(
item_offset: O::Unit, item_offset: O::Unit,
item_height: O::Unit, item_height: O::Unit,
item: impl Draw<O> + Layout<O> item: impl Content<O>
) -> impl Draw<O> + Layout<O> { ) -> impl Content<O> {
Push::y(item_offset, Align::nw(Fixed::y(item_height, Fill::x(item)))) Push::Y(item_offset, Align::nw(Fixed::Y(item_height, Fill::X(item))))
} }
#[inline] pub fn map_east<O: Out>( #[inline] pub fn map_east<O: Out>(
item_offset: O::Unit, item_offset: O::Unit,
item_width: O::Unit, item_width: O::Unit,
item: impl Draw<O> + Layout<O> item: impl Content<O>
) -> impl Draw<O> + Layout<O> { ) -> impl Content<O> {
Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item)))) Push::X(item_offset, Align::w(Fixed::X(item_width, Fill::Y(item))))
} }

View file

@ -1,50 +0,0 @@
use crate::*;
pub enum Margin<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Margin<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Margin::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Margin<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Margin<U, T> {
#[inline] pub fn dx (&self) -> U {
use Margin::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Margin::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Margin<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let area = self.content().layout(area);
let dx = self.dx();
let dy = self.dy();
[
area.x().minus(dx),
area.y().minus(dy),
area.w().plus(dy.plus(dy)),
area.h().plus(dy.plus(dy)),
].into()
}
}

View file

@ -1,47 +0,0 @@
use crate::*;
pub enum Max<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Max<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Max::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Max<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Max<U, T> {
#[inline] pub fn dx (&self) -> U {
use Max::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Max::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Max<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let [x, y, w, h] = self.content().layout(area).xywh();
match self {
Self::X(mw, _) => [x, y, w.min(*mw), h],
Self::Y(mh, _) => [x, y, w, h.min(*mh)],
Self::XY(mw, mh, _) => [x, y, w.min(*mw), h.min(*mh)],
}.into()
}
}

View file

@ -1,47 +0,0 @@
use crate::*;
pub enum Min<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Min<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Min::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Min<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Min<U, T> {
#[inline] pub fn dx (&self) -> U {
use Min::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Min::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Min<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let [x, y, w, h] = self.content().layout(area).xywh();
match self {
Self::X(mw, _) => [x, y, w.max(*mw), h],
Self::Y(mh, _) => [x, y, w, h.max(*mh)],
Self::XY(mw, mh, _) => [x, y, w.max(*mw), h.max(*mh)],
}.into()
}
}

View file

@ -0,0 +1,33 @@
use crate::*;
/// Increment X and/or Y coordinate.
pub enum Push<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Push<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } }
}
impl<U: Coordinate, T> Push<U, T> {
#[inline] pub fn dx (&self) -> U { match self { Self::X(x, ..) | Self::XY(x, _, _) => *x, Self::Y(_, _) => 0.into() } }
#[inline] pub fn dy (&self) -> U { match self { Self::Y(y, ..) | Self::XY(_, y, _) => *y, Self::X(_, _) => 0.into() } }
}
impl<O: Out, T: Content<O>> Draw<O> for Push<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<O: Out, T: Layout<O>> Layout<O> for Push<O::Unit, T> {
fn x (&self, area: O::Area) -> O::Unit { area.x().plus(self.dx()) }
fn y (&self, area: O::Area) -> O::Unit { area.y().plus(self.dy()) }
}
/// Decrement X and/or Y coordinate.
pub enum Pull<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Pull<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } }
}
impl<U: Coordinate, T> Pull<U, T> {
#[inline] pub fn dx (&self) -> U { match self { Self::X(x, ..) | Self::XY(x, _, _) => *x, Self::Y(_, _) => 0.into() } }
#[inline] pub fn dy (&self) -> U { match self { Self::Y(y, ..) | Self::XY(_, y, _) => *y, Self::X(_, _) => 0.into() } }
}
impl<O: Out, T: Content<O>> Draw<O> for Pull<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<O: Out, T: Layout<O>> Layout<O> for Pull<O::Unit, T> {
fn x (&self, area: O::Area) -> O::Unit { area.x().minus(self.dx()) }
fn y (&self, area: O::Area) -> O::Unit { area.y().minus(self.dy()) }
}

View file

@ -0,0 +1,27 @@
use crate::*;
use Pad::*;
pub enum Pad<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Pad<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } }
}
impl<U: Coordinate, T> Pad<U, T> {
#[inline] pub fn dx (&self) -> U { match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } }
#[inline] pub fn dy (&self) -> U { match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } }
}
impl<O: Out, T: Content<O>> Draw<O> for Pad<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<O: Out, T: Layout<O>> Layout<O> for Pad<O::Unit, T> {
fn x (&self, area: O::Area) -> O::Unit {
area.x().plus(self.dx())
}
fn y (&self, area: O::Area) -> O::Unit {
area.x().plus(self.dx())
}
fn w (&self, area: O::Area) -> O::Unit {
area.w().minus(self.dx() * 2.into())
}
fn h (&self, area: O::Area) -> O::Unit {
area.h().minus(self.dy() * 2.into())
}
}

View file

@ -1,50 +0,0 @@
use crate::*;
pub enum Padding<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Padding<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Padding::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Padding<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Padding<U, T> {
#[inline] pub fn dx (&self) -> U {
use Padding::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Padding::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Padding<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let area = self.content().layout(area);
let dx = self.dx();
let dy = self.dy();
[
area.x().plus(dx),
area.y().plus(dy),
area.w().minus(dy.plus(dy)),
area.h().minus(dy.plus(dy))
].into()
}
}

View file

@ -1,48 +0,0 @@
use crate::*;
pub enum Pull<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Pull<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Pull::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Pull<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Pull<U, T> {
#[inline] pub fn dx (&self) -> U {
use Pull::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Pull::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Pull<E::Unit, T> {
fn layout (&self, to: E::Area) -> E::Area {
let area = self.content().layout(to);
[
area.x().minus(self.dx()),
area.y().minus(self.dy()),
area.w(),
area.h()
].into()
}
}

View file

@ -1,43 +0,0 @@
use crate::*;
pub enum Push<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Push<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Push::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Push<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Push<U, T> {
#[inline] pub fn dx (&self) -> U {
use Push::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Push::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Push<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let area = self.content().layout(area);
[area.x().plus(self.dx()), area.y().plus(self.dy()), area.w(), area.h()].into()
}
}

View file

@ -1,43 +0,0 @@
use crate::*;
pub enum Shrink<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Shrink<U, A> {
#[inline] pub const fn x (x: U, item: A) -> Self {
Self::X(x, item)
}
#[inline] pub const fn y (y: U, item: A) -> Self {
Self::Y(y, item)
}
#[inline] pub const fn xy (x: U, y: U, item: A) -> Self {
Self::XY(x, y, item)
}
#[inline] pub const fn content (&self) -> &A {
use Shrink::*;
match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Shrink<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<U: Coordinate, T> Shrink<U, T> {
#[inline] pub fn dx (&self) -> U {
use Shrink::*;
match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, }
}
#[inline] pub fn dy (&self) -> U {
use Shrink::*;
match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, }
}
}
impl<E: Out, T: Layout<E>> Layout<E> for Shrink<E::Unit, T> {
fn layout (&self, to: E::Area) -> E::Area {
let area = self.content().layout(to);
[area.x(), area.y(), area.w().minus(self.dx()), area.h().minus(self.dy())].into()
}
}

View file

@ -0,0 +1,121 @@
use crate::*;
pub enum Fill<A> { X(A), Y(A), XY(A) }
impl<A> Fill<A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(c) | Self::Y(c) | Self::XY(c) => c } }
#[inline] pub const fn dx (&self) -> bool { match self { Self::X(_) | Self::XY(_) => true, _ => false } }
#[inline] pub const fn dy (&self) -> bool { match self { Self::Y(_) | Self::XY(_) => true, _ => false } }
}
impl<O: Out, T: Content<O>> Draw<O> for Fill<T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<O: Out, T: Layout<O>> Layout<O> for Fill<T> {
fn x (&self, area: O::Area) -> O::Unit { if self.dx() { area.x() } else { self.inner().x(area) } }
fn y (&self, area: O::Area) -> O::Unit { if self.dy() { area.y() } else { self.inner().y(area) } }
fn w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w(area) } }
fn min_w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().min_w(area) } }
fn max_w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().max_w(area) } }
fn h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h(area) } }
fn min_h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().min_h(area) } }
fn max_h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().max_h(area) } }
}
/// Set fixed size for content.
pub enum Fixed<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Fixed<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
}
impl<U: Copy, A> Fixed<U, A> {
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
}
impl<O: Out, T: Content<O>> Draw<O> for Fixed<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<O: Out, T: Layout<O>> Layout<O> for Fixed<O::Unit, T> {
fn w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w(area)) }
fn min_w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().min_w(area)) }
fn max_w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().max_w(area)) }
fn h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h(area)) }
fn min_h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().min_h(area)) }
fn max_h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().max_h(area)) }
}
pub enum Max<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Max<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
}
impl<U: Copy, A> Max<U, A> {
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
}
impl<O: Out, T: Content<O>> Draw<O> for Max<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<E: Out, T: Layout<E>> Layout<E> for Max<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let [x, y, w, h] = self.inner().layout(area).xywh();
match self {
Self::X(mw, _) => [x, y, w.min(*mw), h],
Self::Y(mh, _) => [x, y, w, h.min(*mh)],
Self::XY(mw, mh, _) => [x, y, w.min(*mw), h.min(*mh)],
}.into()
}
}
pub enum Min<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Min<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
}
impl<U: Copy, A> Min<U, A> {
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
}
impl<O: Out, T: Content<O>> Draw<O> for Min<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<E: Out, T: Layout<E>> Layout<E> for Min<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let [x, y, w, h] = self.inner().layout(area).xywh();
match self {
Self::X(mw, _) => [x, y, w.max(*mw), h],
Self::Y(mh, _) => [x, y, w, h.max(*mh)],
Self::XY(mw, mh, _) => [x, y, w.max(*mw), h.max(*mh)],
}.into()
}
}
pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Expand<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
}
impl<U: Copy + Default, A> Expand<U, A> {
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
}
impl<O: Out, T: Content<O>> Draw<O> for Expand<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<O: Out, T: Layout<O>> Layout<O> for Expand<O::Unit, T> {
fn w (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dx().unwrap_or_default()) }
fn h (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dy().unwrap_or_default()) }
}
pub enum Shrink<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
impl<U, A> Shrink<U, A> {
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
}
impl<U: Copy, A> Shrink<U, A> {
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
}
impl<O: Out, T: Content<O>> Draw<O> for Shrink<O::Unit, T> {
fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) }
}
impl<E: Out, T: Layout<E>> Layout<E> for Shrink<E::Unit, T> {
fn layout (&self, to: E::Area) -> E::Area {
let area = self.inner().layout(to);
let dx = self.dx().unwrap_or_default();
let dy = self.dy().unwrap_or_default();
[area.x(), area.y(), area.w().minus(dx), area.h().minus(dy)].into()
}
}

View file

@ -4,6 +4,9 @@
#![feature(const_precise_live_drops)] #![feature(const_precise_live_drops)]
#![feature(type_changing_struct_update)] #![feature(type_changing_struct_update)]
#![feature(anonymous_lifetime_in_impl_trait)] #![feature(anonymous_lifetime_in_impl_trait)]
#![feature(const_option_ops)]
#![feature(const_trait_impl)]
#![feature(const_default)]
//#![feature(non_lifetime_binders)] //#![feature(non_lifetime_binders)]
pub(crate) use self::Direction::*; pub(crate) use self::Direction::*;
@ -25,7 +28,7 @@ pub trait Out: Send + Sync + Sized {
type Area: Area<Self::Unit>; type Area: Area<Self::Unit>;
/// Render drawable in area specified by `T::layout(self.area())` /// Render drawable in area specified by `T::layout(self.area())`
#[inline] fn place <'t, T: Draw<Self> + Layout<Self> + ?Sized> ( #[inline] fn place <'t, T: Content<Self> + ?Sized> (
&mut self, content: &'t T &mut self, content: &'t T
) { ) {
self.place_at(content.layout(self.area()), content) self.place_at(content.layout(self.area()), content)

View file

@ -84,8 +84,8 @@ macro_rules! test_op_transform {
h in u16::MIN..u16::MAX, h in u16::MIN..u16::MAX,
) { ) {
if let Some(op) = match (op_x, op_y) { if let Some(op) = match (op_x, op_y) {
(Some(x), Some(y)) => Some($Op::xy(x, y, content)), (Some(x), Some(y)) => Some($Op::XY(x, y, content)),
(Some(x), None) => Some($Op::x(x, content)), (Some(x), None) => Some($Op::X(x, content)),
(None, Some(y)) => Some($Op::y(y, content)), (None, Some(y)) => Some($Op::y(y, content)),
_ => None _ => None
} { } {
@ -104,8 +104,7 @@ test_op_transform!(proptest_op_push, Push);
test_op_transform!(proptest_op_pull, Pull); test_op_transform!(proptest_op_pull, Pull);
test_op_transform!(proptest_op_shrink, Shrink); test_op_transform!(proptest_op_shrink, Shrink);
test_op_transform!(proptest_op_expand, Expand); test_op_transform!(proptest_op_expand, Expand);
test_op_transform!(proptest_op_margin, Margin); test_op_transform!(proptest_op_padding, Pad);
test_op_transform!(proptest_op_padding, Padding);
proptest! { proptest! {
#[test] fn proptest_op_bsp ( #[test] fn proptest_op_bsp (

View file

@ -76,6 +76,6 @@ impl<E: Out> Measure<E> {
format!("{}x{}", self.w(), self.h()).into() format!("{}x{}", self.w(), self.h()).into()
} }
pub fn of <T: Draw<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> { pub fn of <T: Draw<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> {
Bsp::b(Fill::xy(self), item) Bsp::b(Fill::XY(self), item)
} }
} }

View file

@ -1,43 +1,19 @@
use crate::*; use crate::*;
/// Lazily-evaluated [Draw]able. pub struct Lazy<O, T, F>(F, PhantomData<(O, T)>);
pub struct Lazy<E, T, F>(PhantomData<(E, T)>, F); impl<O: Out, T: Content<O>, F: Fn()->T> Lazy<O, T, F> { pub const fn new (thunk: F) -> Self { Self(thunk, PhantomData) } }
impl<E: Out, T: Draw<E> + Layout<E>, F: Fn()->T> Lazy<E, T, F> {
pub const fn new (thunk: F) -> Self { pub struct Thunk<O: Out, F: Fn(&mut O)>(PhantomData<O>, F);
Self(PhantomData, thunk) impl<O: Out, F: Fn(&mut O)> Thunk<O, F> { pub const fn new (draw: F) -> Self { Self(PhantomData, draw) } }
} impl<O: Out, F: Fn(&mut O)> Layout<O> for Thunk<O, F> {}
} impl<O: Out, F: Fn(&mut O)> Draw<O> for Thunk<O, F> {
impl<E: Out, T: Draw<E> + Layout<E>, F: Fn()->T> Content<E> for Lazy<E, T, F> { fn draw (&self, to: &mut O) { (self.1)(to) }
fn content (&self) -> impl Draw<E> + Layout<E> + '_ {
(self.1)()
}
}
pub struct Thunk<E: Out, F: Fn(&mut E)>(PhantomData<E>, F);
impl<E: Out, F: Fn(&mut E)> Thunk<E, F> {
pub const fn new (draw: F) -> Self { Self(PhantomData, draw) }
}
impl<E: Out, F: Fn(&mut E)> Draw<E> for Thunk<E, F> {
fn draw (&self, to: &mut E) { (self.1)(to) }
}
impl<E: Out, F: Fn(&mut E)> Layout<E> for Thunk<E, F> {
fn layout (&self, to: E::Area) -> E::Area { to }
}
#[derive(Debug, Default)] pub struct Memo<T, U> {
pub value: T,
pub view: Arc<RwLock<U>>
} }
#[derive(Debug, Default)] pub struct Memo<T, U> { pub value: T, pub view: Arc<RwLock<U>> }
impl<T: PartialEq, U> Memo<T, U> { impl<T: PartialEq, U> Memo<T, U> {
pub fn new (value: T, view: U) -> Self { pub fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } }
Self { value, view: Arc::new(view.into()) } pub fn update <R> (&mut self, newval: T, draw: impl Fn(&mut U, &T, &T)->R) -> Option<R> {
}
pub fn update <R> (
&mut self,
newval: T,
draw: impl Fn(&mut U, &T, &T)->R
) -> Option<R> {
if newval != self.value { if newval != self.value {
let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value); let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value);
self.value = newval; self.value = newval;
@ -48,6 +24,4 @@ impl<T: PartialEq, U> Memo<T, U> {
} }
/// Clear a pre-allocated buffer, then write into it. /// Clear a pre-allocated buffer, then write into it.
#[macro_export] macro_rules! rewrite { #[macro_export] macro_rules! rewrite { ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } } }
($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } }
}

View file

@ -84,52 +84,62 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> (
Some("fill") => output.place(&{ Some("fill") => output.place(&{
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap()); let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
match frags.next() { match frags.next() {
Some("xy") | None => Fill::XY(a),
Some("x") => Fill::X(a), Some("x") => Fill::X(a),
Some("y") => Fill::Y(a), Some("y") => Fill::Y(a),
Some("xy") => Fill::XY(a),
frag => unimplemented!("fill/{frag:?}") frag => unimplemented!("fill/{frag:?}")
} }
}), }),
Some("fixed") => output.place(&{ Some("fixed") => output.place(&{
let axis = frags.next(); let axis = frags.next();
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") => arg2, _ => panic!() }; let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap()); let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
match axis { match axis {
Some("xy") | None => Fixed::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
Some("x") => Fixed::X(state.from(arg0?)?.unwrap(), cb), Some("x") => Fixed::X(state.from(arg0?)?.unwrap(), cb),
Some("y") => Fixed::Y(state.from(arg0?)?.unwrap(), cb), Some("y") => Fixed::Y(state.from(arg0?)?.unwrap(), cb),
Some("xy") => Fixed::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})", frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})",
head.src()?.unwrap_or_default().split("/").next()) head.src()?.unwrap_or_default().split("/").next())
} }
}), }),
Some("min") => output.place(&{ Some("min") => output.place(&{
let c = match frags.next() { let axis = frags.next();
Some("x") | Some("y") => arg1, Some("xy") => arg2, _ => panic!() let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
}; let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
let cb = Thunk::new(move|output: &mut O|state.view(output, &c).unwrap()); match axis {
match frags.next() { Some("xy") | None => Min::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
Some("x") => Min::X(state.from(arg0?)?.unwrap(), cb), Some("x") => Min::X(state.from(arg0?)?.unwrap(), cb),
Some("y") => Min::Y(state.from(arg0?)?.unwrap(), cb), Some("y") => Min::Y(state.from(arg0?)?.unwrap(), cb),
Some("xy") => Min::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
frag => unimplemented!("min/{frag:?}") frag => unimplemented!("min/{frag:?}")
} }
}), }),
Some("max") => output.place(&{ Some("max") => output.place(&{
let c = match frags.next() { let axis = frags.next();
Some("x") | Some("y") => arg1, Some("xy") => arg2, _ => panic!() let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
}; let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
let cb = Thunk::new(move|output: &mut O|state.view(output, &c).unwrap()); match axis {
match frags.next() { Some("xy") | None => Max::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
Some("x") => Max::X(state.from(arg0?)?.unwrap(), cb), Some("x") => Max::X(state.from(arg0?)?.unwrap(), cb),
Some("y") => Max::Y(state.from(arg0?)?.unwrap(), cb), Some("y") => Max::Y(state.from(arg0?)?.unwrap(), cb),
Some("xy") => Max::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
frag => unimplemented!("max/{frag:?}") frag => unimplemented!("max/{frag:?}")
} }
}), }),
Some("push") => output.place(&{
let axis = frags.next();
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
match axis {
Some("xy") | None => Push::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
Some("x") => Push::X(state.from(arg0?)?.unwrap(), cb),
Some("y") => Push::Y(state.from(arg0?)?.unwrap(), cb),
frag => unimplemented!("push/{frag:?}")
}
}),
_ => return Ok(false) _ => return Ok(false)
}; };

View file

@ -1,25 +1,11 @@
use crate::*; use crate::*;
pub struct FieldH<Theme, Label, Value>(pub Theme, pub Label, pub Value); pub struct FieldH<Theme, Label, Value>(pub Theme, pub Label, pub Value);
impl<O: Out, T, L: Draw<O>, V: Draw<O>> Layout<O> for FieldH<T, L, V> where Self: Content<O> { impl<O: Out, T, L: Content<O>, V: Content<O>> HasContent<O> for FieldH<T, L, V> {
fn layout (&self, to: O::Area) -> O::Area { fn content (&self) -> impl Content<O> { Bsp::e(&self.1, &self.2) }
self.content().layout(to)
}
}
impl<O: Out, T, L: Draw<O>, V: Draw<O>> Draw<O> for FieldH<T, L, V> where Self: Content<O> {
fn draw (&self, to: &mut O) {
self.content().draw(to)
}
} }
pub struct FieldV<Theme, Label, Value>(pub Theme, pub Label, pub Value); pub struct FieldV<Theme, Label, Value>(pub Theme, pub Label, pub Value);
impl<O: Out, T, L: Draw<O>, V: Draw<O>> Layout<O> for FieldV<T, L, V> where Self: Content<O> { impl<O: Out, T, L: Content<O>, V: Content<O>> HasContent<O> for FieldV<T, L, V> {
fn layout (&self, to: O::Area) -> O::Area { fn content (&self) -> impl Content<O> { Bsp::s(&self.1, &self.2) }
self.content().layout(to)
}
}
impl<O: Out, T, L: Draw<O>, V: Draw<O>> Draw<O> for FieldV<T, L, V> where Self: Content<O> {
fn draw (&self, to: &mut O) {
self.content().draw(to)
}
} }

View file

@ -28,10 +28,8 @@ impl ExampleCommand {
} }
} }
tui_draw!(|self: Example, to|{ impl Draw<TuiOut> for Example {
to.place(&self.content()); fn content (&self) -> impl Draw<TuiOut> {
});
content!(TuiOut: |self: Example|{
let index = self.0 + 1; let index = self.0 + 1;
let wh = self.1.wh(); let wh = self.1.wh();
let src = Self::VIEWS.get(self.0).unwrap_or(&""); let src = Self::VIEWS.get(self.0).unwrap_or(&"");
@ -40,7 +38,8 @@ content!(TuiOut: |self: Example|{
let code = Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", src)))); let code = Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", src))));
let content = ();//Tui::bg(Color::Rgb(10, 10, 60), View(self, CstIter::new(src))); let content = ();//Tui::bg(Color::Rgb(10, 10, 60), View(self, CstIter::new(src)));
self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content))) self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content)))
}); }
}
impl View<TuiOut, ()> for Example { impl View<TuiOut, ()> for Example {
fn view_expr <'a> (&'a self, to: &mut TuiOut, expr: &'a impl DslExpr) -> Usually<()> { fn view_expr <'a> (&'a self, to: &mut TuiOut, expr: &'a impl DslExpr) -> Usually<()> {
if evaluate_output_expression(self, to, expr)? if evaluate_output_expression(self, to, expr)?

View file

@ -1,50 +1,12 @@
#[allow(unused)] use crate::*; #[allow(unused)] use crate::*;
impl Tui { impl Tui {
pub const fn fg <T> (color: Color, w: T) -> TuiForeground<T> { pub const fn fg <T> (color: Color, w: T) -> Foreground<Color, T> { Foreground(color, w) }
TuiForeground(Foreground(color, w)) pub const fn bg <T> (color: Color, w: T) -> Background<Color, T> { Background(color, w) }
pub const fn fg_bg <T> (fg: Color, bg: Color, w: T) -> Background<Color, Foreground<Color, T>> { Background(bg, Foreground(fg, w)) }
pub const fn modify <T> (enable: bool, modifier: Modifier, w: T) -> Modify<T> { Modify(enable, modifier, w) }
pub const fn bold <T> (enable: bool, w: T) -> Modify<T> { Self::modify(enable, Modifier::BOLD, w) }
pub const fn border <S, T> (enable: bool, style: S, w: T) -> Bordered<S, T> { Bordered(enable, style, w) }
} }
pub const fn bg <T> (color: Color, w: T) -> TuiBackground<T> {
TuiBackground(Background(color, w))
}
pub const fn fg_bg <T> (fg: Color, bg: Color, w: T) -> TuiBackground<TuiForeground<T>> {
TuiBackground(Background(bg, TuiForeground(Foreground(fg, w))))
}
pub const fn modify <T> (enable: bool, modifier: Modifier, w: T) -> Modify<T> {
Modify(enable, modifier, w)
}
pub const fn bold <T> (enable: bool, w: T) -> Modify<T> {
Self::modify(enable, Modifier::BOLD, w)
}
pub const fn border <S, T> (enable: bool, style: S, w: T) -> Bordered<S, T> {
Bordered(enable, style, w)
}
}
#[macro_export] macro_rules! tui_layout ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{
impl Layout<TuiOut> for $Self {
fn layout (&$self, $to: [u16;4]) -> [u16;4] {
$expr
}
}
});
#[macro_export] macro_rules! tui_draw ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{
impl Draw<TuiOut> for $Self {
fn draw (&$self, $to: &mut TuiOut) {
$expr
}
}
});
#[macro_export] macro_rules! tui_content ((|$self:ident:$Self:ty|$sexpr:expr)=>{
impl Content<TuiOut> for $Self {
fn content (&$self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ {
$expr
}
}
});
mod tui_border; pub use self::tui_border::*; mod tui_border; pub use self::tui_border::*;
mod tui_button; pub use self::tui_button::*; mod tui_button; pub use self::tui_button::*;
mod tui_color; pub use self::tui_color::*; mod tui_color; pub use self::tui_color::*;
@ -54,67 +16,41 @@ mod tui_phat; pub use self::tui_phat::*;
mod tui_repeat; pub use self::tui_repeat::*; mod tui_repeat; pub use self::tui_repeat::*;
mod tui_scroll; pub use self::tui_scroll::*; mod tui_scroll; pub use self::tui_scroll::*;
mod tui_string; pub use self::tui_string::*; mod tui_string; pub use self::tui_string::*;
mod tui_number; //pub use self::tui_number::*; mod tui_number; //pub use self::tui_number::*;
mod tui_tryptich; //pub use self::tui_tryptich::*; mod tui_tryptich; //pub use self::tui_tryptich::*;
pub struct TuiForeground<T>(pub(crate) Foreground<Color, T>);
pub struct TuiBackground<T>(pub(crate) Background<Color, T>);
pub struct Modify<T>(pub bool, pub Modifier, pub T); pub struct Modify<T>(pub bool, pub Modifier, pub T);
pub struct Styled<T>(pub Option<Style>, pub T); pub struct Styled<T>(pub Option<Style>, pub T);
impl<T: Draw<TuiOut>> Draw<TuiOut> for Foreground<Color, T> {
impl<T: Layout<TuiOut>> Layout<TuiOut> for TuiForeground<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.0.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for TuiForeground<T> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
let area = self.layout(to.area()); let area = self.layout(to.area());
to.fill_fg(area, self.0.0); to.fill_fg(area, self.0.0);
to.place_at(area, &self.0.1); to.place_at(area, &self.0.1);
} }
} }
impl<T: Draw<TuiOut>> Draw<TuiOut> for Background<Color, T> {
impl<T: Layout<TuiOut>> Layout<TuiOut> for TuiBackground<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.0.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for TuiBackground<T> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
let area = self.layout(to.area()); let area = self.layout(to.area());
to.fill_bg(area, self.0.0); to.fill_bg(area, self.0.0);
to.place_at(area, &self.0.1); to.place_at(area, &self.0.1);
} }
} }
impl<T: Draw<TuiOut>> Layout<TuiOut> for Modify<T> {}
impl<T: Layout<TuiOut>> Layout<TuiOut> for Modify<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.2.layout(to)
}
}
impl<T: Draw<TuiOut>> Draw<TuiOut> for Modify<T> { impl<T: Draw<TuiOut>> Draw<TuiOut> for Modify<T> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
to.fill_mod(to.area(), self.0, self.1); to.fill_mod(to.area(), self.0, self.1);
self.2.draw(to) self.2.draw(to)
} }
} }
impl<T: Draw<TuiOut>> Layout<TuiOut> for Styled<T> {}
impl<T: Layout<TuiOut>> Layout<TuiOut> for Styled<T> { impl<T: Draw<TuiOut>> Draw<TuiOut> for Styled<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.1.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for Styled<T> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
to.place(&self.1); to.place(&self.1);
// TODO write style over area // TODO write style over area
} }
} }
//impl<T: Draw<TuiOut> + Layout<TuiOut>> Content<TuiOut> for Result<T, Box<dyn std::error::Error>> { //impl<T: Draw<TuiOut>> Content<TuiOut> for Result<T, Box<dyn std::error::Error>> {
//fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ { //fn content (&self) -> impl Draw<TuiOut> + '_ {
//Bsp::a(self.as_ref().ok(), self.as_ref().err().map( //Bsp::a(self.as_ref().ok(), self.as_ref().err().map(
//|e|Tui::fg_bg(Color::Rgb(255,255,255), Color::Rgb(32,32,32), e.to_string()) //|e|Tui::fg_bg(Color::Rgb(255,255,255), Color::Rgb(32,32,32), e.to_string())
//)) //))

View file

@ -1,47 +1,45 @@
use crate::*; use crate::*;
impl<S: BorderStyle, W: Draw<TuiOut> + Layout<TuiOut>> Content<TuiOut> for Bordered<S, W> { impl<S: BorderStyle, W: Content<TuiOut>> HasContent<TuiOut> for Bordered<S, W> {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ { fn content (&self) -> impl Content<TuiOut> {
Fill::xy(lay!( Fill::XY(lay!( When::new(self.0, Border(self.0, self.1)), Pad::XY(1, 1, &self.2) ))
When::new(self.0, Border(self.0, self.1)),
Padding::xy(1, 1, &self.2)
))
} }
} }
impl<S: BorderStyle> Draw<TuiOut> for Border<S> { impl<S: BorderStyle> Draw<TuiOut> for Border<S> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
if self.0 { let Border(enabled, style) = self.0;
if enabled {
let area = to.area(); let area = to.area();
if area.w() > 0 && area.y() > 0 { if area.w() > 0 && area.y() > 0 {
to.blit(&self.1.nw(), area.x(), area.y(), self.1.style()); to.blit(&style.border_nw(), area.x(), area.y(), style.style());
to.blit(&self.1.ne(), area.x() + area.w() - 1, area.y(), self.1.style()); to.blit(&style.border_ne(), area.x() + area.w() - 1, area.y(), style.style());
to.blit(&self.1.sw(), area.x(), area.y() + area.h() - 1, self.1.style()); to.blit(&style.border_sw(), area.x(), area.y() + area.h() - 1, style.style());
to.blit(&self.1.se(), area.x() + area.w() - 1, area.y() + area.h() - 1, self.1.style()); to.blit(&style.border_se(), area.x() + area.w() - 1, area.y() + area.h() - 1, style.style());
for x in area.x()+1..area.x()+area.w()-1 { for x in area.x()+1..area.x()+area.w()-1 {
to.blit(&self.1.n(), x, area.y(), self.1.style()); to.blit(&style.border_n(), x, area.y(), style.style());
to.blit(&self.1.s(), x, area.y() + area.h() - 1, self.1.style()); to.blit(&style.border_s(), x, area.y() + area.h() - 1, style.style());
} }
for y in area.y()+1..area.y()+area.h()-1 { for y in area.y()+1..area.y()+area.h()-1 {
to.blit(&self.1.w(), area.x(), y, self.1.style()); to.blit(&style.border_w(), area.x(), y, style.style());
to.blit(&self.1.e(), area.x() + area.w() - 1, y, self.1.style()); to.blit(&style.border_e(), area.x() + area.w() - 1, y, style.style());
} }
} }
} }
} }
} }
pub trait BorderStyle: Draw<TuiOut> + Layout<TuiOut> + Copy { pub trait BorderStyle: Content<TuiOut> + Copy {
fn enabled (&self) -> bool; fn enabled (&self) -> bool;
fn enclose (self, w: impl Draw<TuiOut> + Layout<TuiOut>) -> impl Draw<TuiOut> + Layout<TuiOut> { fn enclose (self, w: impl Draw<TuiOut>) -> impl Draw<TuiOut> {
Bsp::b(Fill::xy(Border(self.enabled(), self)), w) Bsp::b(Fill::XY(Border(self.enabled(), self)), w)
} }
fn enclose2 (self, w: impl Draw<TuiOut> + Layout<TuiOut>) -> impl Draw<TuiOut> + Layout<TuiOut> { fn enclose2 (self, w: impl Draw<TuiOut>) -> impl Draw<TuiOut> {
Bsp::b(Margin::xy(1, 1, Fill::xy(Border(self.enabled(), self))), w) Bsp::b(Pad::XY(1, 1, Fill::XY(Border(self.enabled(), self))), w)
} }
fn enclose_bg (self, w: impl Draw<TuiOut> + Layout<TuiOut>) -> impl Draw<TuiOut> + Layout<TuiOut> { fn enclose_bg (self, w: impl Draw<TuiOut>) -> impl Draw<TuiOut> {
Tui::bg(self.style().unwrap().bg.unwrap_or(Color::Reset), Tui::bg(self.style().unwrap().bg.unwrap_or(Color::Reset),
Bsp::b(Fill::xy(Border(self.enabled(), self)), w)) Bsp::b(Fill::XY(Border(self.enabled(), self)), w))
} }
const NW: &'static str = ""; const NW: &'static str = "";
const N: &'static str = ""; const N: &'static str = "";
@ -57,14 +55,14 @@ pub trait BorderStyle: Draw<TuiOut> + Layout<TuiOut> + Copy {
const W0: &'static str = ""; const W0: &'static str = "";
const E0: &'static str = ""; const E0: &'static str = "";
fn n (&self) -> &str { Self::N } fn border_n (&self) -> &str { Self::N }
fn s (&self) -> &str { Self::S } fn border_s (&self) -> &str { Self::S }
fn e (&self) -> &str { Self::E } fn border_e (&self) -> &str { Self::E }
fn w (&self) -> &str { Self::W } fn border_w (&self) -> &str { Self::W }
fn nw (&self) -> &str { Self::NW } fn border_nw (&self) -> &str { Self::NW }
fn ne (&self) -> &str { Self::NE } fn border_ne (&self) -> &str { Self::NE }
fn sw (&self) -> &str { Self::SW } fn border_sw (&self) -> &str { Self::SW }
fn se (&self) -> &str { Self::SE } fn border_se (&self) -> &str { Self::SE }
#[inline] fn draw <'a> ( #[inline] fn draw <'a> (
&self, to: &mut TuiOut &self, to: &mut TuiOut
) -> Usually<()> { ) -> Usually<()> {
@ -143,7 +141,6 @@ macro_rules! border {
fn enabled (&self) -> bool { self.0 } fn enabled (&self) -> bool { self.0 }
} }
#[derive(Copy, Clone)] pub struct $T(pub bool, pub Style); #[derive(Copy, Clone)] pub struct $T(pub bool, pub Style);
impl Layout<TuiOut> for $T {}
impl Draw<TuiOut> for $T { impl Draw<TuiOut> for $T {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
if self.enabled() { let _ = BorderStyle::draw(self, to); } if self.enabled() { let _ = BorderStyle::draw(self, to); }

View file

@ -1,26 +1,26 @@
use crate::{*, Color::*}; use crate::{*, Color::*};
pub fn button_2 <'a> ( pub fn button_2 <'a> (
key: impl Draw<TuiOut> + Layout<TuiOut> + 'a, key: impl Draw<TuiOut> + 'a,
label: impl Draw<TuiOut> + Layout<TuiOut> + 'a, label: impl Draw<TuiOut> + 'a,
editing: bool, editing: bool,
) -> impl Draw<TuiOut> + Layout<TuiOut> + 'a { ) -> impl Draw<TuiOut> + 'a {
let key = Tui::fg_bg(Tui::orange(), Tui::g(0), Bsp::e( let key = Tui::fg_bg(Tui::orange(), Tui::g(0), Bsp::e(
Tui::fg(Tui::g(0), ""), Tui::fg(Tui::g(0), &""),
Bsp::e(key, Tui::fg(Tui::g(96), "")) Bsp::e(key, Tui::fg(Tui::g(96), &""))
)); ));
let label = When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label)); let label = When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label));
Tui::bold(true, Bsp::e(key, label)) Tui::bold(true, Bsp::e(key, label))
} }
pub fn button_3 <'a> ( pub fn button_3 <'a> (
key: impl Draw<TuiOut> + Layout<TuiOut> + 'a, key: impl Draw<TuiOut> + 'a,
label: impl Draw<TuiOut> + Layout<TuiOut> + 'a, label: impl Draw<TuiOut> + 'a,
value: impl Draw<TuiOut> + Layout<TuiOut> + 'a, value: impl Draw<TuiOut> + 'a,
editing: bool, editing: bool,
) -> impl Draw<TuiOut> + Layout<TuiOut> + 'a { ) -> impl Draw<TuiOut> + 'a {
let key = Tui::fg_bg(Tui::orange(), Tui::g(0), let key = Tui::fg_bg(Tui::orange(), Tui::g(0),
Bsp::e(Tui::fg(Tui::g(0), ""), Bsp::e(key, Tui::fg(if editing { Bsp::e(Tui::fg(Tui::g(0), &""), Bsp::e(key, Tui::fg(if editing {
Tui::g(128) Tui::g(128)
} else { } else {
Tui::g(96) Tui::g(96)
@ -28,11 +28,11 @@ pub fn button_3 <'a> (
let label = Bsp::e( let label = Bsp::e(
When::new(!editing, Bsp::e( When::new(!editing, Bsp::e(
Tui::fg_bg(Tui::g(255), Tui::g(96), label), Tui::fg_bg(Tui::g(255), Tui::g(96), label),
Tui::fg_bg(Tui::g(128), Tui::g(96), ""), Tui::fg_bg(Tui::g(128), Tui::g(96), &""),
)), )),
Bsp::e( Bsp::e(
Tui::fg_bg(Tui::g(224), Tui::g(128), value), Tui::fg_bg(Tui::g(224), Tui::g(128), value),
Tui::fg_bg(Tui::g(128), Reset, ""), Tui::fg_bg(Tui::g(128), Reset, &""),
)); ));
Tui::bold(true, Bsp::e(key, label)) Tui::bold(true, Bsp::e(key, label))
} }

View file

@ -1,37 +1,5 @@
use crate::*; use crate::*;
impl<
Label: Draw<TuiOut> + Layout<TuiOut>,
Value: Draw<TuiOut> + Layout<TuiOut>
> Content<TuiOut> for FieldH<ItemTheme, Label, Value> {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ {
let Self(ItemTheme { darkest, dark, lightest, .. }, title, value) = self;
row!(
Tui::fg_bg(dark.rgb, darkest.rgb, ""),
Tui::fg_bg(lightest.rgb, dark.rgb, title),
Tui::fg_bg(dark.rgb, darkest.rgb, ""),
Tui::fg_bg(lightest.rgb, darkest.rgb, Tui::bold(true, value)),
)
}
}
impl<
Label: Draw<TuiOut> + Layout<TuiOut>,
Value: Draw<TuiOut> + Layout<TuiOut>
> Content<TuiOut> for FieldV<ItemTheme, Label, Value> {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ {
let Self(ItemTheme { darkest, dark, lightest, .. }, title, value) = self;
Bsp::n(
Align::w(Tui::bg(darkest.rgb, Tui::fg(lightest.rgb, Tui::bold(true, value)))),
Fill::x(Align::w(row!(
Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "")),
Tui::bg(dark.rgb, Tui::fg(lightest.rgb, title)),
Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "")),
)))
)
}
}
// TODO: // TODO:
pub struct Field<T, U> { pub struct Field<T, U> {
pub direction: Direction, pub direction: Direction,
@ -44,8 +12,8 @@ pub struct Field<T, U> {
pub value_bg: Option<ItemColor>, pub value_bg: Option<ItemColor>,
pub value_align: Option<Direction>, pub value_align: Option<Direction>,
} }
impl<T: Draw<TuiOut>, U: Draw<TuiOut>> Content<TuiOut> for Field<T, U> { impl<T: Content<TuiOut>, U: Content<TuiOut>> HasContent<TuiOut> for Field<T, U> {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ { fn content (&self) -> impl Content<TuiOut> {
"TODO" "TODO"
} }
} }

View file

@ -13,21 +13,21 @@ impl<T> Phat<T> {
pub const LO: &'static str = ""; pub const LO: &'static str = "";
pub const HI: &'static str = ""; pub const HI: &'static str = "";
/// A phat line /// A phat line
pub fn lo (fg: Color, bg: Color) -> impl Draw<TuiOut> + Layout<TuiOut> { pub fn lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(Self::LO))) Fixed::Y(1, Tui::fg_bg(fg, bg, RepeatH(Self::LO)))
} }
/// A phat line /// A phat line
pub fn hi (fg: Color, bg: Color) -> impl Draw<TuiOut> + Layout<TuiOut> { pub fn hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(Self::HI))) Fixed::Y(1, Tui::fg_bg(fg, bg, RepeatH(Self::HI)))
} }
} }
impl<T: Layout<TuiOut> + Draw<TuiOut>> Content<TuiOut> for Phat<T> { impl<T: Content<TuiOut>> HasContent<TuiOut> for Phat<T> {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ { fn content (&self) -> impl Content<TuiOut> {
let [fg, bg, hi, lo] = self.colors; let [fg, bg, hi, lo] = self.colors;
let top = Fixed::y(1, Self::lo(bg, hi)); let top = Fixed::y(1, Self::lo(bg, hi));
let low = Fixed::y(1, Self::hi(bg, lo)); let low = Fixed::y(1, Self::hi(bg, lo));
let content = Tui::fg_bg(fg, bg, &self.content); let content = Tui::fg_bg(fg, bg, &self.content);
Min::xy(self.width, self.height, Bsp::s(top, Bsp::n(low, Fill::xy(content)))) Min::XY(self.width, self.height, Bsp::s(top, Bsp::n(low, Fill::XY(content))))
} }
} }

View file

@ -2,11 +2,6 @@ use crate::*;
use ratatui::prelude::Position; use ratatui::prelude::Position;
pub struct Repeat<'a>(pub &'a str); pub struct Repeat<'a>(pub &'a str);
impl Layout<TuiOut> for Repeat<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
to
}
}
impl Draw<TuiOut> for Repeat<'_> { impl Draw<TuiOut> for Repeat<'_> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
let [x, y, w, h] = to.area().xywh(); let [x, y, w, h] = to.area().xywh();
@ -23,11 +18,6 @@ impl Draw<TuiOut> for Repeat<'_> {
} }
pub struct RepeatV<'a>(pub &'a str); pub struct RepeatV<'a>(pub &'a str);
impl Layout<TuiOut> for RepeatV<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
to
}
}
impl Draw<TuiOut> for RepeatV<'_> { impl Draw<TuiOut> for RepeatV<'_> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
let [x, y, _w, h] = to.area().xywh(); let [x, y, _w, h] = to.area().xywh();
@ -40,11 +30,6 @@ impl Draw<TuiOut> for RepeatV<'_> {
} }
pub struct RepeatH<'a>(pub &'a str); pub struct RepeatH<'a>(pub &'a str);
impl Layout<TuiOut> for RepeatH<'_> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
to
}
}
impl Draw<TuiOut> for RepeatH<'_> { impl Draw<TuiOut> for RepeatH<'_> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) {
let [x, y, w, _h] = to.area().xywh(); let [x, y, w, _h] = to.area().xywh();

View file

@ -1,18 +1,10 @@
use crate::*; use crate::*;
use crate::ratatui::prelude::Position; use crate::ratatui::prelude::Position;
use unicode_width::{UnicodeWidthStr, UnicodeWidthChar}; use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
impl Layout<TuiOut> for &str { fn layout (&self, to: [u16;4]) -> [u16;4] { to.center_xy([width_chars_max(to.w(), self), 1]) } }
tui_layout!(|self: &str, to|to.center_xy([width_chars_max(to.w(), self), 1])); impl Draw<TuiOut> for &str { fn draw (&self, to: &mut TuiOut) { let [x, y, w, ..] = self.layout(to.area()); to.text(&self, x, y, w) } }
tui_draw!(|self: &str, to|{ impl Layout<TuiOut> for String { fn layout (&self, to: [u16;4]) -> [u16;4] { self.as_str().layout(to) } }
let [x, y, w, ..] = self.layout(to.area()); impl Draw<TuiOut> for String { fn draw (&self, to: &mut TuiOut) { self.as_str().draw(to) } }
to.text(&self, x, y, w)
});
tui_layout!(|self: Arc<str>, to|self.as_ref().layout(to));
tui_draw!(|self: Arc<str>, to|self.as_ref().draw(to));
tui_layout!(|self: String, to|self.as_str().layout(to));
tui_draw!(|self: String, to|self.as_str().draw(to));
fn width_chars_max (max: u16, text: impl AsRef<str>) -> u16 { fn width_chars_max (max: u16, text: impl AsRef<str>) -> u16 {
let mut width: u16 = 0; let mut width: u16 = 0;
@ -48,19 +40,13 @@ pub fn trim_string (max_width: usize, input: impl AsRef<str>) -> String {
pub struct TrimString<T: AsRef<str>>(pub u16, pub T); pub struct TrimString<T: AsRef<str>>(pub u16, pub T);
impl<'a, T: AsRef<str>> TrimString<T> { impl<'a, T: AsRef<str>> TrimString<T> {
fn as_ref (&self) -> TrimStringRef<'_, T> { fn as_ref (&self) -> TrimStringRef<'_, T> { TrimStringRef(self.0, &self.1) }
TrimStringRef(self.0, &self.1)
}
}
impl<'a, T: AsRef<str>> Layout<TuiOut> for TrimString<T> {
fn layout (&self, to: [u16; 4]) -> [u16;4] {
Layout::layout(&self.as_ref(), to)
}
} }
impl<'a, T: AsRef<str>> Draw<TuiOut> for TrimString<T> { impl<'a, T: AsRef<str>> Draw<TuiOut> for TrimString<T> {
fn draw (&self, to: &mut TuiOut) { fn draw (&self, to: &mut TuiOut) { Draw::draw(&self.as_ref(), to) }
Draw::draw(&self.as_ref(), to)
} }
impl<'a, T: AsRef<str>> Layout<TuiOut> for TrimString<T> {
fn layout (&self, to: [u16; 4]) -> [u16;4] { Layout::layout(&self.as_ref(), to) }
} }
/// Displays a borrowed [str]-like with fixed maximum width /// Displays a borrowed [str]-like with fixed maximum width
@ -68,7 +54,7 @@ impl<'a, T: AsRef<str>> Draw<TuiOut> for TrimString<T> {
/// Width is computed using [unicode_width]. /// Width is computed using [unicode_width].
pub struct TrimStringRef<'a, T: AsRef<str>>(pub u16, pub &'a T); pub struct TrimStringRef<'a, T: AsRef<str>>(pub u16, pub &'a T);
impl<T: AsRef<str>> Layout<TuiOut> for TrimStringRef<'_, T> { impl<'a, T: AsRef<str>> Layout<TuiOut> for TrimStringRef<'a, T> {
fn layout (&self, to: [u16; 4]) -> [u16;4] { fn layout (&self, to: [u16; 4]) -> [u16;4] {
[to.x(), to.y(), to.w().min(self.0).min(self.1.as_ref().width() as u16), to.h()] [to.x(), to.y(), to.w().min(self.0).min(self.1.as_ref().width() as u16), to.h()]
} }

View file

@ -1,11 +1,11 @@
use crate::*; use crate::*;
impl< impl<
A: Draw<TuiOut> + Layout<TuiOut>, A: Content<TuiOut>,
B: Draw<TuiOut> + Layout<TuiOut>, B: Content<TuiOut>,
C: Draw<TuiOut> + Layout<TuiOut>, C: Content<TuiOut>,
> Content<TuiOut> for Tryptich<A, B, C> { > HasContent<TuiOut> for Tryptich<A, B, C> {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ { fn content (&self) -> impl Content<TuiOut> {
let Self { top, h, left: (w_a, ref a), middle: (w_b, ref b), right: (w_c, ref c) } = *self; let Self { top, h, left: (w_a, ref a), middle: (w_b, ref b), right: (w_c, ref c) } = *self;
Fixed::y(h, if top { Fixed::y(h, if top {
Bsp::a( Bsp::a(
@ -17,13 +17,12 @@ impl<
) )
} else { } else {
Bsp::a( Bsp::a(
Fill::xy(Align::c(Fixed::x(w_b, Align::x(Tui::bg(Color::Reset, b))))), Fill::XY(Align::c(Fixed::x(w_b, Align::x(Tui::bg(Color::Reset, b))))),
Bsp::a( Bsp::a(
Fill::xy(Align::w(Fixed::x(w_a, Tui::bg(Color::Reset, a)))), Fill::XY(Align::w(Fixed::x(w_a, Tui::bg(Color::Reset, a)))),
Fill::xy(Align::e(Fixed::x(w_c, Tui::bg(Color::Reset, c)))), Fill::XY(Align::e(Fixed::x(w_c, Tui::bg(Color::Reset, c)))),
), ),
) )
}) })
} }
} }

View file

@ -27,9 +27,6 @@ impl Out for TuiOut {
} }
} }
impl Layout<TuiOut> for fn(&mut TuiOut) {}
impl TuiOut { impl TuiOut {
/// Spawn the output thread. /// Spawn the output thread.
pub fn run_output <T: Draw<TuiOut> + Send + Sync + 'static> ( pub fn run_output <T: Draw<TuiOut> + Send + Sync + 'static> (

View file

@ -3,7 +3,7 @@ use crate::*;
//use std::sync::{Arc, RwLock}; //use std::sync::{Arc, RwLock};
struct TestComponent(String); struct TestComponent(String);
impl Content<TuiOut> for TestComponent { impl Content<TuiOut> for TestComponent {
fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> { fn content (&self) -> impl Draw<TuiOut> {
Some(self.0.as_str()) Some(self.0.as_str())
} }
} }