From 90fc869e14ef8a3b557ed9e2ff763fd1b0dd1651 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 9 Sep 2025 01:07:19 +0300 Subject: [PATCH] uuugh --- .editorconfig | 3 + core/src/core_macros.rs | 32 ++++--- core/src/lib.rs | 8 ++ output/src/content.rs | 141 +++++++++++++++++++++------- output/src/draw.rs | 107 ++++----------------- output/src/layout.rs | 104 ++------------------ output/src/layout/layout_align.rs | 60 +++++------- output/src/layout/layout_bsp.rs | 81 ++++++++++++---- output/src/layout/layout_cond.rs | 33 +++---- output/src/layout/layout_expand.rs | 39 -------- output/src/layout/layout_fill.rs | 55 ----------- output/src/layout/layout_fixed.rs | 47 ---------- output/src/layout/layout_map.rs | 32 +++---- output/src/layout/layout_margin.rs | 50 ---------- output/src/layout/layout_max.rs | 47 ---------- output/src/layout/layout_min.rs | 47 ---------- output/src/layout/layout_move.rs | 33 +++++++ output/src/layout/layout_pad.rs | 27 ++++++ output/src/layout/layout_padding.rs | 50 ---------- output/src/layout/layout_pull.rs | 48 ---------- output/src/layout/layout_push.rs | 43 --------- output/src/layout/layout_shrink.rs | 43 --------- output/src/layout/layout_size.rs | 121 ++++++++++++++++++++++++ output/src/output.rs | 5 +- output/src/output_test.rs | 7 +- output/src/space/space_measure.rs | 2 +- output/src/thunk.rs | 50 +++------- output/src/view.rs | 66 +++++++------ output/src/widget/widget_field.rs | 22 +---- proc/src/lib.rs | 6 +- tui/examples/tui_00.rs | 25 +++-- tui/examples/tui_01.rs | 14 +-- tui/src/tui_content.rs | 118 ++++++----------------- tui/src/tui_content/tui_border.rs | 58 ++++++------ tui/src/tui_content/tui_button.rs | 42 +++------ tui/src/tui_content/tui_field.rs | 36 +------ tui/src/tui_content/tui_phat.rs | 18 ++-- tui/src/tui_content/tui_repeat.rs | 17 +--- tui/src/tui_content/tui_string.rs | 36 +++---- tui/src/tui_content/tui_tryptich.rs | 25 +++-- tui/src/tui_engine/tui_output.rs | 3 - tui/src/tui_test.rs | 2 +- 42 files changed, 645 insertions(+), 1158 deletions(-) create mode 100644 .editorconfig delete mode 100644 output/src/layout/layout_expand.rs delete mode 100644 output/src/layout/layout_fill.rs delete mode 100644 output/src/layout/layout_fixed.rs delete mode 100644 output/src/layout/layout_margin.rs delete mode 100644 output/src/layout/layout_max.rs delete mode 100644 output/src/layout/layout_min.rs create mode 100644 output/src/layout/layout_move.rs create mode 100644 output/src/layout/layout_pad.rs delete mode 100644 output/src/layout/layout_padding.rs delete mode 100644 output/src/layout/layout_pull.rs delete mode 100644 output/src/layout/layout_push.rs delete mode 100644 output/src/layout/layout_shrink.rs create mode 100644 output/src/layout/layout_size.rs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7b08ef3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +root = true +[*] +max_line_length = 132 diff --git a/core/src/core_macros.rs b/core/src/core_macros.rs index a8fdda4..ef56421 100644 --- a/core/src/core_macros.rs +++ b/core/src/core_macros.rs @@ -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 ( ($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>)?)*)? { - $(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_ { - $(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_ { - $(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_> { - $(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)?> { + $(fn $fn $(<$($fl),*>)? (& $($fl2)* $self $(,$arg:$ty)*) $(-> $ret)? { (**$self).$fn($($arg),*) })* } //impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { //$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { @@ -40,21 +43,24 @@ //} }); /// 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>)?)*)? { - $(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 { - $(fn $fn (&$self $(,$arg:$ty)*) -> $ret $body)* + pub trait $Trait $(<$($A: $T),+>)? : $($dep $(<$dtt>+)? $($dep2 $(<$dtt2>)?)*+)? Sized { + $(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? $body)* } 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_ { - $(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_> { - $(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)?> { + $(fn $fn (&$self $(,$arg:$ty)*) $(-> $ret)? { (**$self).$fn($($arg),*) })* } //impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { //$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { diff --git a/core/src/lib.rs b/core/src/lib.rs index 3a51258..7bf320e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -35,3 +35,11 @@ pub trait Eval { } }; } + +pub fn wrap_inc (index: usize, count: usize) -> usize { + if count > 0 { (index + 1) % count } else { 0 } +} + +pub fn wrap_dec (index: usize, count: usize) -> usize { + if count > 0 { index.overflowing_sub(1).0.min(count.saturating_sub(1)) } else { 0 } +} diff --git a/output/src/content.rs b/output/src/content.rs index f797f98..f63e98b 100644 --- a/output/src/content.rs +++ b/output/src/content.rs @@ -1,40 +1,111 @@ use crate::*; - -/// Composable renderable with static dispatch. -pub trait Content: Sized { - /// Return opaque [Draw]able. - fn content (&self) -> impl Draw + Layout + '_ { () } -} - -/// The platonic ideal unit of [Content]: -/// total emptiness at dead center (e=1vg^sqrt(-1)) -impl Content for () {} - -impl + Layout> Content for fn()->T { - fn content (&self) -> impl Draw + Layout + '_ { - self() +pub trait HasContent { fn content (&self) -> impl Content; } +pub trait Content: Draw + Layout {} +impl + Layout> Content for T {} +impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a { fn as_ref (&self) -> &(dyn Draw + 'a) { self } } +impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a { fn as_ref (&self) -> &(dyn Layout + 'a) { self } } +/// Drawable with dynamic dispatch. +pub trait Draw { fn draw (&self, to: &mut O); } +impl Draw for () { fn draw (&self, to: &mut O) {} } +impl Draw for fn(&mut O) { fn draw (&self, to: &mut O) { (*self)(to) } } +impl Draw for Box> { fn draw (&self, to: &mut O) { (**self).draw(to) } } +impl> Draw for &D { fn draw (&self, to: &mut O) { (*self).draw(to) } } +impl> Draw for &mut D { fn draw (&self, to: &mut O) { (**self).draw(to) } } +impl> Draw for Option { fn draw (&self, to: &mut O) { if let Some(draw) = self { draw.draw(to) } } } +/// Drawable area of display. +pub trait Layout { + 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() } + fn max_h (&self, to: O::Area) -> O::Unit { to.h() } + fn h (&self, to: O::Area) -> O::Unit { + to.h().max(self.min_h(to)).min(self.max_h(to)) + } + fn layout (&self, to: O::Area) -> O::Area { + [self.x(to), self.y(to), self.w(to), self.h(to)].into() } } -/// Implement composable content for a struct. -#[macro_export] macro_rules! content { - - // Implement for all [Out]s. - (|$self:ident:$Struct:ty| $content:expr) => { - impl Content for $Struct { - fn content (&$self) -> impl Draw + Layout + '_ { Some($content) } - } - }; - - // Implement for specific [Out]. - ($Out:ty:| - $self:ident: - $Struct:ident$(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)? - |$content:expr) => { - impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Out> - for $Struct $(<$($($L)? $($T)?),+>)? { - fn content (&$self) -> impl Draw<$Out> + Layout<$Out> + '_ { $content } - } - }; - +impl Layout for () { + fn x (&self, a: O::Area) -> O::Unit { a.x() } + fn y (&self, a: O::Area) -> O::Unit { a.y() } + fn w (&self, _: O::Area) -> O::Unit { 0.into() } + fn min_w (&self, _: O::Area) -> O::Unit { 0.into() } + fn max_w (&self, _: O::Area) -> O::Unit { 0.into() } + 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() } +} + +impl> Layout for &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> Layout 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 Layout for Box> { + 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> Layout for Option { + 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()) + } } diff --git a/output/src/draw.rs b/output/src/draw.rs index f78574d..9826267 100644 --- a/output/src/draw.rs +++ b/output/src/draw.rs @@ -1,94 +1,27 @@ use crate::*; -/// Drawable with dynamic dispatch. -pub trait Draw { - /// Write data to display. - fn draw (&self, to: &mut O); +pub struct Bound(pub O::Area, pub D); + +impl> HasContent for Bound { + fn content (&self) -> &impl Content { &self.1 } } -impl Draw for fn(&mut O) { +impl Layout for Bound { + 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> Draw for Bound { fn draw (&self, to: &mut O) { - self(to) - } -} - -impl Draw for () { fn draw (&self, _: &mut O) {} } - -impl> Draw for &T { - fn draw (&self, to: &mut O) { (*self).draw(to) } -} - -impl<'x, O: Out> Draw for &(dyn Draw + 'x) { - fn draw (&self, to: &mut O) { - (*self).draw(to) - } -} - -impl<'x, O: Out> Draw for &mut (dyn Draw + 'x) { - fn draw (&self, to: &mut O) { - (**self).draw(to) - } -} - -impl> Draw for RwLock { - fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) } -} - -impl> Draw for [T] { - fn draw (&self, to: &mut O) { - for draw in self.iter() { - draw.draw(to) - } - } -} - -//impl> Draw for &mut T { - //fn draw (&self, to: &mut O) { - //(**self).draw(to) - //} -//} - -//impl, U: Draw> Draw 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 - 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>, to|(**self).draw(to)); -draw!(|self: Box>, to|(**self).draw(to)); -//draw!(|self: Option>, to|if let Some(draw) = self { draw.draw(to) }); - -impl> Draw for Option { - fn draw (&self, to: &mut O) { - if let Some(draw) = self { - draw.draw(to) - } + let area = to.area(); + *to.area_mut() = self.0; + self.1.draw(to); + *to.area_mut() = area; } } diff --git a/output/src/layout.rs b/output/src/layout.rs index ec42644..85ca20a 100644 --- a/output/src/layout.rs +++ b/output/src/layout.rs @@ -1,98 +1,10 @@ use crate::*; -pub trait Layout { - 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 - 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 Layout for () {} - -impl> Layout for &L { /*FIXME*/ } - -impl> Layout for RwLock { /*FIXME*/ } - -impl> Layout for Option { /*FIXME*/ } - -//impl Layout for fn(&mut O) {} - -impl> Layout for Arc { - fn layout (&self, to: O::Area) -> O::Area { - (**self).layout(to) - } -} - -impl<'x, O: Out> Layout for &(dyn Draw + 'x) { - fn layout (&self, to: O::Area) -> O::Area { - Fill::xy(self).layout(to) - } -} - -mod layout_align; pub use self::layout_align::*; -mod layout_bsp; pub use self::layout_bsp::*; -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_margin; pub use self::layout_margin::*; -mod layout_max; pub use self::layout_max::*; -mod layout_min; pub use self::layout_min::*; -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_align; pub use self::layout_align::*; +mod layout_bsp; pub use self::layout_bsp::*; +mod layout_cond; pub use self::layout_cond::*; +mod layout_map; pub use self::layout_map::*; +mod layout_pad; pub use self::layout_pad::*; +mod layout_move; pub use self::layout_move::*; +mod layout_size; pub use self::layout_size::*; +mod layout_stack; //pub use self::layout_stack::*; diff --git a/output/src/layout/layout_align.rs b/output/src/layout/layout_align.rs index c8f0922..6fab1b7 100644 --- a/output/src/layout/layout_align.rs +++ b/output/src/layout/layout_align.rs @@ -6,7 +6,7 @@ //! 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::n(four()), [18, 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::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::n(two_by_four()), [18, 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]); //! ``` use crate::*; +use Alignment::*; /// 9th of area to place. #[derive(Debug, Copy, Clone, Default)] pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } - pub struct Align(Alignment, T); - impl Align { #[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) } #[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) } @@ -47,39 +46,24 @@ impl Align { #[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) } #[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) } } - -impl> Layout for Align { - fn layout (&self, on: E::Area) -> E::Area { - self.0.align(on, &self.1) - } -} -impl + Layout> Draw for Align { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.1) - } -} - -impl Alignment { - fn align (&self, on: E::Area, content: &impl Layout) -> 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() +impl> Draw for Align { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), &self.1).draw(to) } +} +impl> Layout for Align { + 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!(), + } + } + fn y (&self, to: O::Area) -> O::Unit { + match self.0 { + 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!(), + } } } diff --git a/output/src/layout/layout_bsp.rs b/output/src/layout/layout_bsp.rs index ff3e4aa..3de4cfc 100644 --- a/output/src/layout/layout_bsp.rs +++ b/output/src/layout/layout_bsp.rs @@ -1,7 +1,6 @@ use crate::*; -use Direction::*; -/// A split or layer. +/// A binary split or layer. pub struct Bsp( pub(crate) Direction, /// First element. @@ -19,31 +18,79 @@ impl Bsp { #[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) } } -impl< - O: Out, - Head: Draw + Layout, - Tail: Draw + Layout -> Draw for Bsp { +impl, Tail: Content> Draw for Bsp { fn draw (&self, to: &mut O) { - let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2); - 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); + match self.0 { + South => { + panic!("{}", self.1.h(to.area())); + let area_1 = self.1.layout(to.area()); + let area_2 = self.2.layout([ + to.area().x(), + 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, Tail: Layout> Layout for Bsp { + 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 { bsp_areas(area, self.0, &self.1, &self.2)[2] } } -fn bsp_areas ( - area: O::Area, direction: Direction, a: &impl Layout, b: &impl Layout, +fn bsp_areas , B: Layout> ( + area: O::Area, direction: Direction, a: &A, b: &B, ) -> [O::Area;3] { let [x, y, w, h] = area.xywh(); let [aw, ah] = a.layout(area).wh(); diff --git a/output/src/layout/layout_cond.rs b/output/src/layout/layout_cond.rs index aceb535..65ebc5b 100644 --- a/output/src/layout/layout_cond.rs +++ b/output/src/layout/layout_cond.rs @@ -2,54 +2,45 @@ use crate::*; /// Show an item only when a condition is true. pub struct When(bool, T, PhantomData); -impl When { +impl> When { /// Create a binary condition. pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) } } impl> Layout for When { fn layout (&self, to: O::Area) -> O::Area { let Self(cond, item, ..) = self; - let mut area = O::Area::zero(); - 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() + if *cond { item.layout(to) } else { O::Area::zero().into() } } } -impl> Draw for When { +impl> Draw for When { fn draw (&self, to: &mut O) { 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 -pub struct Either + Layout, B: Draw + Layout>(pub bool, pub A, pub B, pub PhantomData); -impl + Layout, B: Draw + Layout> Either { +pub struct Either(pub bool, pub A, pub B, pub PhantomData); +impl, B: Content> Either { /// Create a ternary view condition. pub const fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b, PhantomData) } } -impl + Layout, B: Draw + Layout> Layout for Either { +impl, B: Layout> Layout for Either { fn layout (&self, to: E::Area) -> E::Area { let Self(cond, a, b, ..) = self; if *cond { a.layout(to) } else { b.layout(to) } } } -impl + Layout, B: Draw + Layout> Draw for Either { +impl, B: Content> Draw for Either { fn draw (&self, to: &mut E) { 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 + Layout, B: Draw + Layout> Draw for Either< //return Ok(Some(match words.next() { //Some(Token{value: Key($x),..}) => Self::x(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!() //})) //} else { @@ -134,7 +125,7 @@ impl + Layout, B: Draw + Layout> Draw for Either< //state.give_or_fail(words, ||"y: no unit")?, //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 y")?, //state.give_or_fail(words, ||"xy: no content")? diff --git a/output/src/layout/layout_expand.rs b/output/src/layout/layout_expand.rs deleted file mode 100644 index 8194fe2..0000000 --- a/output/src/layout/layout_expand.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::*; - -pub enum Expand { X(U, A), Y(U, A), XY(U, U, A), } - -impl Expand { - #[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 + Layout> Content for Expand { - fn content (&self) -> impl Draw + Layout + '_ { - use Expand::*; - match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, } - } -} - -impl + Layout> Draw for Expand { - fn draw (&self, to: &mut O) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Expand { - #[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> Layout for Expand { - fn layout (&self, to: O::Area) -> O::Area { - [to.x(), to.y(), to.w().plus(self.dx()), to.h().plus(self.dy())].into() - } -} diff --git a/output/src/layout/layout_fill.rs b/output/src/layout/layout_fill.rs deleted file mode 100644 index 6287714..0000000 --- a/output/src/layout/layout_fill.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::*; - -pub enum Fill { - /// Use maximum width of area. - X(A), - /// Use maximum height of area. - Y(A), - /// Use maximum width and height of area. - XY(A) -} - -impl Fill { - #[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> Draw for Fill { - fn draw (&self, to: &mut O) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl> Layout for Fill { - 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() - } - } -} diff --git a/output/src/layout/layout_fixed.rs b/output/src/layout/layout_fixed.rs deleted file mode 100644 index 1d6eb1d..0000000 --- a/output/src/layout/layout_fixed.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::*; - -pub enum Fixed { X(U, A), Y(U, A), XY(U, U, A), } - -impl Fixed { - #[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 Fixed { - #[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> Draw for Fixed { - fn draw (&self, to: &mut O) { - let area = Layout::::layout(&self, to.area()); - to.place_at(area, &self.content()) - } -} - -impl Layout for Fixed { - 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() - } -} diff --git a/output/src/layout/layout_map.rs b/output/src/layout/layout_map.rs index f509dcc..ffd7005 100644 --- a/output/src/layout/layout_map.rs +++ b/output/src/layout/layout_map.rs @@ -31,7 +31,7 @@ macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{ O, A, Push>>>, I, F, fn(A, usize)->B > where O: Out, - B: Draw + Layout, + B: Draw, I: Iterator + 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!(south, y, n); -impl_map_direction!(west, x, e); -impl_map_direction!(north, y, s); +impl_map_direction!(east, X, w); +impl_map_direction!(south, Y, n); +impl_map_direction!(west, X, e); +impl_map_direction!(north, Y, s); impl<'a, O, A, B, I, F, G> Layout for Map where O: Out, - B: Draw + Layout, + B: Layout, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync @@ -94,7 +94,7 @@ impl<'a, O, A, B, I, F, G> Layout for Map where } impl<'a, O, A, B, I, F, G> Draw for Map where O: Out, - B: Draw + Layout, + B: Content, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync @@ -115,25 +115,25 @@ impl<'a, O, A, B, I, F, G> Draw for Map where #[inline] pub fn map_south( item_offset: O::Unit, item_height: O::Unit, - item: impl Draw + Layout -) -> impl Draw + Layout { - Push::y(item_offset, Fixed::y(item_height, Fill::x(item))) + item: impl Content +) -> impl Content { + Push::Y(item_offset, Fixed::Y(item_height, Fill::X(item))) } #[inline] pub fn map_south_west( item_offset: O::Unit, item_height: O::Unit, - item: impl Draw + Layout -) -> impl Draw + Layout { - Push::y(item_offset, Align::nw(Fixed::y(item_height, Fill::x(item)))) + item: impl Content +) -> impl Content { + Push::Y(item_offset, Align::nw(Fixed::Y(item_height, Fill::X(item)))) } #[inline] pub fn map_east( item_offset: O::Unit, item_width: O::Unit, - item: impl Draw + Layout -) -> impl Draw + Layout { - Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item)))) + item: impl Content +) -> impl Content { + Push::X(item_offset, Align::w(Fixed::X(item_width, Fill::Y(item)))) } diff --git a/output/src/layout/layout_margin.rs b/output/src/layout/layout_margin.rs deleted file mode 100644 index cee3800..0000000 --- a/output/src/layout/layout_margin.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::*; - -pub enum Margin { X(U, A), Y(U, A), XY(U, U, A), } - -impl Margin { - #[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 + Layout> Draw for Margin { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Margin { - #[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> Layout for Margin { - 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() - } -} diff --git a/output/src/layout/layout_max.rs b/output/src/layout/layout_max.rs deleted file mode 100644 index 81467ae..0000000 --- a/output/src/layout/layout_max.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::*; - -pub enum Max { X(U, A), Y(U, A), XY(U, U, A), } - -impl Max { - #[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 + Layout> Draw for Max { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Max { - #[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> Layout for Max { - 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() - } -} diff --git a/output/src/layout/layout_min.rs b/output/src/layout/layout_min.rs deleted file mode 100644 index 73f8209..0000000 --- a/output/src/layout/layout_min.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::*; - -pub enum Min { X(U, A), Y(U, A), XY(U, U, A), } - -impl Min { - #[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 + Layout> Draw for Min { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Min { - #[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> Layout for Min { - 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() - } -} diff --git a/output/src/layout/layout_move.rs b/output/src/layout/layout_move.rs new file mode 100644 index 0000000..163d2e3 --- /dev/null +++ b/output/src/layout/layout_move.rs @@ -0,0 +1,33 @@ +use crate::*; +/// Increment X and/or Y coordinate. +pub enum Push { X(U, A), Y(U, A), XY(U, U, A), } +impl Push { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } } +} +impl Push { + #[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> Draw for Push { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Push { + 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 { X(U, A), Y(U, A), XY(U, U, A), } +impl Pull { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } } +} +impl Pull { + #[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> Draw for Pull { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Pull { + 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()) } +} diff --git a/output/src/layout/layout_pad.rs b/output/src/layout/layout_pad.rs new file mode 100644 index 0000000..0570c23 --- /dev/null +++ b/output/src/layout/layout_pad.rs @@ -0,0 +1,27 @@ +use crate::*; +use Pad::*; +pub enum Pad { X(U, A), Y(U, A), XY(U, U, A), } +impl Pad { + #[inline] pub const fn inner (&self) -> &A { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } } +} +impl Pad { + #[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> Draw for Pad { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Pad { + 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()) + } +} diff --git a/output/src/layout/layout_padding.rs b/output/src/layout/layout_padding.rs deleted file mode 100644 index 5295fdf..0000000 --- a/output/src/layout/layout_padding.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::*; - -pub enum Padding { X(U, A), Y(U, A), XY(U, U, A), } - -impl Padding { - #[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 + Layout> Draw for Padding { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Padding { - #[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> Layout for Padding { - 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() - } -} diff --git a/output/src/layout/layout_pull.rs b/output/src/layout/layout_pull.rs deleted file mode 100644 index 9fdda7f..0000000 --- a/output/src/layout/layout_pull.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::*; - -pub enum Pull { X(U, A), Y(U, A), XY(U, U, A), } - -impl Pull { - #[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 + Layout> Draw for Pull { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Pull { - #[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> Layout for Pull { - 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() - } -} diff --git a/output/src/layout/layout_push.rs b/output/src/layout/layout_push.rs deleted file mode 100644 index 4c507b3..0000000 --- a/output/src/layout/layout_push.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::*; - -pub enum Push { X(U, A), Y(U, A), XY(U, U, A), } - -impl Push { - #[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 + Layout> Draw for Push { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Push { - #[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> Layout for Push { - 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() - } -} diff --git a/output/src/layout/layout_shrink.rs b/output/src/layout/layout_shrink.rs deleted file mode 100644 index 6a64425..0000000 --- a/output/src/layout/layout_shrink.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::*; - -pub enum Shrink { X(U, A), Y(U, A), XY(U, U, A), } - -impl Shrink { - #[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 + Layout> Draw for Shrink { - fn draw (&self, to: &mut E) { - to.place_at(self.layout(to.area()), &self.content()) - } -} - -impl Shrink { - #[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> Layout for Shrink { - 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() - } -} diff --git a/output/src/layout/layout_size.rs b/output/src/layout/layout_size.rs new file mode 100644 index 0000000..a9d4932 --- /dev/null +++ b/output/src/layout/layout_size.rs @@ -0,0 +1,121 @@ +use crate::*; + +pub enum Fill { X(A), Y(A), XY(A) } +impl Fill { + #[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> Draw for Fill { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Fill { + 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 { X(U, A), Y(U, A), XY(U, U, A), } +impl Fixed { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } } +} +impl Fixed { + #[inline] pub const fn dx (&self) -> Option { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } } + #[inline] pub const fn dy (&self) -> Option { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } } +} +impl> Draw for Fixed { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Fixed { + 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 { X(U, A), Y(U, A), XY(U, U, A), } +impl Max { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } } +} +impl Max { + #[inline] pub const fn dx (&self) -> Option { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } } + #[inline] pub const fn dy (&self) -> Option { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } } +} +impl> Draw for Max { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Max { + 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 { X(U, A), Y(U, A), XY(U, U, A), } +impl Min { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } } +} +impl Min { + #[inline] pub const fn dx (&self) -> Option { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } } + #[inline] pub const fn dy (&self) -> Option { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } } +} +impl> Draw for Min { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Min { + 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 { X(U, A), Y(U, A), XY(U, U, A), } +impl Expand { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } } +} +impl Expand { + #[inline] pub const fn dx (&self) -> Option { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } } + #[inline] pub const fn dy (&self) -> Option { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } } +} +impl> Draw for Expand { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Expand { + 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 { X(U, A), Y(U, A), XY(U, U, A), } +impl Shrink { + #[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } } +} +impl Shrink { + #[inline] pub const fn dx (&self) -> Option { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } } + #[inline] pub const fn dy (&self) -> Option { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } } +} +impl> Draw for Shrink { + fn draw (&self, to: &mut O) { Bound(self.layout(to.area()), self.inner()).draw(to) } +} +impl> Layout for Shrink { + 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() + } +} diff --git a/output/src/output.rs b/output/src/output.rs index 00c7bb9..6a32109 100644 --- a/output/src/output.rs +++ b/output/src/output.rs @@ -4,6 +4,9 @@ #![feature(const_precise_live_drops)] #![feature(type_changing_struct_update)] #![feature(anonymous_lifetime_in_impl_trait)] +#![feature(const_option_ops)] +#![feature(const_trait_impl)] +#![feature(const_default)] //#![feature(non_lifetime_binders)] pub(crate) use self::Direction::*; @@ -25,7 +28,7 @@ pub trait Out: Send + Sync + Sized { type Area: Area; /// Render drawable in area specified by `T::layout(self.area())` - #[inline] fn place <'t, T: Draw + Layout + ?Sized> ( + #[inline] fn place <'t, T: Content + ?Sized> ( &mut self, content: &'t T ) { self.place_at(content.layout(self.area()), content) diff --git a/output/src/output_test.rs b/output/src/output_test.rs index 958f485..932e87a 100644 --- a/output/src/output_test.rs +++ b/output/src/output_test.rs @@ -84,8 +84,8 @@ macro_rules! test_op_transform { h in u16::MIN..u16::MAX, ) { if let Some(op) = match (op_x, op_y) { - (Some(x), Some(y)) => Some($Op::xy(x, y, content)), - (Some(x), None) => Some($Op::x(x, content)), + (Some(x), Some(y)) => Some($Op::XY(x, y, content)), + (Some(x), None) => Some($Op::X(x, content)), (None, Some(y)) => Some($Op::y(y, content)), _ => None } { @@ -104,8 +104,7 @@ test_op_transform!(proptest_op_push, Push); test_op_transform!(proptest_op_pull, Pull); test_op_transform!(proptest_op_shrink, Shrink); test_op_transform!(proptest_op_expand, Expand); -test_op_transform!(proptest_op_margin, Margin); -test_op_transform!(proptest_op_padding, Padding); +test_op_transform!(proptest_op_padding, Pad); proptest! { #[test] fn proptest_op_bsp ( diff --git a/output/src/space/space_measure.rs b/output/src/space/space_measure.rs index d1bdb30..f508554 100644 --- a/output/src/space/space_measure.rs +++ b/output/src/space/space_measure.rs @@ -76,6 +76,6 @@ impl Measure { format!("{}x{}", self.w(), self.h()).into() } pub fn of > (&self, item: T) -> Bsp, T> { - Bsp::b(Fill::xy(self), item) + Bsp::b(Fill::XY(self), item) } } diff --git a/output/src/thunk.rs b/output/src/thunk.rs index da2d84e..29b7321 100644 --- a/output/src/thunk.rs +++ b/output/src/thunk.rs @@ -1,43 +1,19 @@ use crate::*; -/// Lazily-evaluated [Draw]able. -pub struct Lazy(PhantomData<(E, T)>, F); -impl + Layout, F: Fn()->T> Lazy { - pub const fn new (thunk: F) -> Self { - Self(PhantomData, thunk) - } -} -impl + Layout, F: Fn()->T> Content for Lazy { - fn content (&self) -> impl Draw + Layout + '_ { - (self.1)() - } -} - -pub struct Thunk(PhantomData, F); -impl Thunk { - pub const fn new (draw: F) -> Self { Self(PhantomData, draw) } -} -impl Draw for Thunk { - fn draw (&self, to: &mut E) { (self.1)(to) } -} -impl Layout for Thunk { - fn layout (&self, to: E::Area) -> E::Area { to } -} - -#[derive(Debug, Default)] pub struct Memo { - pub value: T, - pub view: Arc> +pub struct Lazy(F, PhantomData<(O, T)>); +impl, F: Fn()->T> Lazy { pub const fn new (thunk: F) -> Self { Self(thunk, PhantomData) } } + +pub struct Thunk(PhantomData, F); +impl Thunk { pub const fn new (draw: F) -> Self { Self(PhantomData, draw) } } +impl Layout for Thunk {} +impl Draw for Thunk { + fn draw (&self, to: &mut O) { (self.1)(to) } } +#[derive(Debug, Default)] pub struct Memo { pub value: T, pub view: Arc> } impl Memo { - pub fn new (value: T, view: U) -> Self { - Self { value, view: Arc::new(view.into()) } - } - pub fn update ( - &mut self, - newval: T, - draw: impl Fn(&mut U, &T, &T)->R - ) -> Option { + pub fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } } + pub fn update (&mut self, newval: T, draw: impl Fn(&mut U, &T, &T)->R) -> Option { if newval != self.value { let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value); self.value = newval; @@ -48,6 +24,4 @@ impl Memo { } /// Clear a pre-allocated buffer, then write into it. -#[macro_export] macro_rules! rewrite { - ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } } -} +#[macro_export] macro_rules! rewrite { ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } } } diff --git a/output/src/view.rs b/output/src/view.rs index bd1cc51..f8a182f 100644 --- a/output/src/view.rs +++ b/output/src/view.rs @@ -67,7 +67,7 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( } }), - Some("align") => output.place(&{ + Some("align") => output.place(&{ let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap()); match frags.next() { Some("n") => Align::n(a), @@ -81,55 +81,65 @@ 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()); match frags.next() { - Some("x") => Fill::X(a), - Some("y") => Fill::Y(a), - Some("xy") => Fill::XY(a), + Some("xy") | None => Fill::XY(a), + Some("x") => Fill::X(a), + Some("y") => Fill::Y(a), frag => unimplemented!("fill/{frag:?}") } }), - Some("fixed") => output.place(&{ + Some("fixed") => output.place(&{ 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()); match axis { - Some("x") => Fixed::X(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), + Some("xy") | None => Fixed::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), + Some("x") => Fixed::X(state.from(arg0?)?.unwrap(), cb), + Some("y") => Fixed::Y(state.from(arg0?)?.unwrap(), cb), frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})", head.src()?.unwrap_or_default().split("/").next()) } }), - Some("min") => output.place(&{ - let c = match frags.next() { - Some("x") | Some("y") => arg1, Some("xy") => arg2, _ => panic!() - }; - let cb = Thunk::new(move|output: &mut O|state.view(output, &c).unwrap()); - match frags.next() { - Some("x") => Min::X(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), + Some("min") => 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 => Min::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), + Some("x") => Min::X(state.from(arg0?)?.unwrap(), cb), + Some("y") => Min::Y(state.from(arg0?)?.unwrap(), cb), frag => unimplemented!("min/{frag:?}") } }), - Some("max") => output.place(&{ - let c = match frags.next() { - Some("x") | Some("y") => arg1, Some("xy") => arg2, _ => panic!() - }; - let cb = Thunk::new(move|output: &mut O|state.view(output, &c).unwrap()); - match frags.next() { - Some("x") => Max::X(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), + Some("max") => 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 => Max::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), + Some("x") => Max::X(state.from(arg0?)?.unwrap(), cb), + Some("y") => Max::Y(state.from(arg0?)?.unwrap(), cb), 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) }; diff --git a/output/src/widget/widget_field.rs b/output/src/widget/widget_field.rs index 8de2515..6bedc02 100644 --- a/output/src/widget/widget_field.rs +++ b/output/src/widget/widget_field.rs @@ -1,25 +1,11 @@ use crate::*; pub struct FieldH(pub Theme, pub Label, pub Value); -impl, V: Draw> Layout for FieldH where Self: Content { - fn layout (&self, to: O::Area) -> O::Area { - self.content().layout(to) - } -} -impl, V: Draw> Draw for FieldH where Self: Content { - fn draw (&self, to: &mut O) { - self.content().draw(to) - } +impl, V: Content> HasContent for FieldH { + fn content (&self) -> impl Content { Bsp::e(&self.1, &self.2) } } pub struct FieldV(pub Theme, pub Label, pub Value); -impl, V: Draw> Layout for FieldV where Self: Content { - fn layout (&self, to: O::Area) -> O::Area { - self.content().layout(to) - } -} -impl, V: Draw> Draw for FieldV where Self: Content { - fn draw (&self, to: &mut O) { - self.content().draw(to) - } +impl, V: Content> HasContent for FieldV { + fn content (&self) -> impl Content { Bsp::s(&self.1, &self.2) } } diff --git a/proc/src/lib.rs b/proc/src/lib.rs index fa33152..7ae7699 100644 --- a/proc/src/lib.rs +++ b/proc/src/lib.rs @@ -106,7 +106,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) { //#[tengri_proc::view(SomeOut)] //impl SomeView { //#[tengri::view(":view-1")] - //fn view_1 (&self) -> impl Draw + use<'_> { + //fn view_1 (&self) -> impl Content + use<'_> { //"view-1" //} //} @@ -114,13 +114,13 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) { //let written = quote! { #parsed }; //assert_eq!(format!("{written}"), format!("{}", quote! { //impl SomeView { - //fn view_1 (&self) -> impl Draw + use<'_> { + //fn view_1 (&self) -> impl Content + use<'_> { //"view-1" //} //} ///// Generated by [tengri_proc]. //impl ::tengri::output::Content for SomeView { - //fn content (&self) -> impl Draw { + //fn content (&self) -> impl Content { //self.size.of(::tengri::output::View(self, self.config.view)) //} //} diff --git a/tui/examples/tui_00.rs b/tui/examples/tui_00.rs index a4aa475..f13049e 100644 --- a/tui/examples/tui_00.rs +++ b/tui/examples/tui_00.rs @@ -28,19 +28,18 @@ impl ExampleCommand { } } -tui_draw!(|self: Example, to|{ - to.place(&self.content()); -}); -content!(TuiOut: |self: Example|{ - let index = self.0 + 1; - let wh = self.1.wh(); - let src = Self::VIEWS.get(self.0).unwrap_or(&""); - let heading = format!("Example {}/{} in {:?}", index, Self::VIEWS.len(), &wh); - let title = Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(heading))); - 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))); - self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content))) -}); +impl Draw for Example { + fn content (&self) -> impl Draw { + let index = self.0 + 1; + let wh = self.1.wh(); + let src = Self::VIEWS.get(self.0).unwrap_or(&""); + let heading = format!("Example {}/{} in {:?}", index, Self::VIEWS.len(), &wh); + let title = Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(heading))); + 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))); + self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content))) + } +} impl View for Example { fn view_expr <'a> (&'a self, to: &mut TuiOut, expr: &'a impl DslExpr) -> Usually<()> { if evaluate_output_expression(self, to, expr)? diff --git a/tui/examples/tui_01.rs b/tui/examples/tui_01.rs index 58d505e..9d62bdf 100644 --- a/tui/examples/tui_01.rs +++ b/tui/examples/tui_01.rs @@ -12,25 +12,25 @@ fn main () {} //#[tengri_proc::view(TuiOut)] //impl Example { - //pub fn title (&self) -> impl Draw + use<'_> { + //pub fn title (&self) -> impl Content + use<'_> { //Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, VIEWS.len())))).boxed() //} - //pub fn code (&self) -> impl Draw + use<'_> { + //pub fn code (&self) -> impl Content + use<'_> { //Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", VIEWS[self.0])))).boxed() //} - //pub fn hello (&self) -> impl Draw + use<'_> { + //pub fn hello (&self) -> impl Content + use<'_> { //Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed() //} - //pub fn world (&self) -> impl Draw + use<'_> { + //pub fn world (&self) -> impl Content + use<'_> { //Tui::bg(Color::Rgb(100, 10, 10), "world").boxed() //} - //pub fn hello_world (&self) -> impl Draw + use<'_> { + //pub fn hello_world (&self) -> impl Content + use<'_> { //"Hello world!".boxed() //} - //pub fn map_e (&self) -> impl Draw + use<'_> { + //pub fn map_e (&self) -> impl Content + use<'_> { //Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() //} - //pub fn map_s (&self) -> impl Draw + use<'_> { + //pub fn map_s (&self) -> impl Content + use<'_> { //Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() //} //} diff --git a/tui/src/tui_content.rs b/tui/src/tui_content.rs index 90e6f3a..7c4285d 100644 --- a/tui/src/tui_content.rs +++ b/tui/src/tui_content.rs @@ -1,50 +1,12 @@ #[allow(unused)] use crate::*; - impl Tui { - pub const fn fg (color: Color, w: T) -> TuiForeground { - TuiForeground(Foreground(color, w)) - } - pub const fn bg (color: Color, w: T) -> TuiBackground { - TuiBackground(Background(color, w)) - } - pub const fn fg_bg (fg: Color, bg: Color, w: T) -> TuiBackground> { - TuiBackground(Background(bg, TuiForeground(Foreground(fg, w)))) - } - pub const fn modify (enable: bool, modifier: Modifier, w: T) -> Modify { - Modify(enable, modifier, w) - } - pub const fn bold (enable: bool, w: T) -> Modify { - Self::modify(enable, Modifier::BOLD, w) - } - pub const fn border (enable: bool, style: S, w: T) -> Bordered { - Bordered(enable, style, w) - } + pub const fn fg (color: Color, w: T) -> Foreground { Foreground(color, w) } + pub const fn bg (color: Color, w: T) -> Background { Background(color, w) } + pub const fn fg_bg (fg: Color, bg: Color, w: T) -> Background> { Background(bg, Foreground(fg, w)) } + pub const fn modify (enable: bool, modifier: Modifier, w: T) -> Modify { Modify(enable, modifier, w) } + pub const fn bold (enable: bool, w: T) -> Modify { Self::modify(enable, Modifier::BOLD, w) } + pub const fn border (enable: bool, style: S, w: T) -> Bordered { Bordered(enable, style, w) } } - -#[macro_export] macro_rules! tui_layout ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{ - impl Layout 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 for $Self { - fn draw (&$self, $to: &mut TuiOut) { - $expr - } - } -}); - -#[macro_export] macro_rules! tui_content ((|$self:ident:$Self:ty|$sexpr:expr)=>{ - impl Content for $Self { - fn content (&$self) -> impl Draw + Layout + '_ { - $expr - } - } -}); - mod tui_border; pub use self::tui_border::*; mod tui_button; pub use self::tui_button::*; 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_scroll; pub use self::tui_scroll::*; mod tui_string; pub use self::tui_string::*; - mod tui_number; //pub use self::tui_number::*; mod tui_tryptich; //pub use self::tui_tryptich::*; - -pub struct TuiForeground(pub(crate) Foreground); -pub struct TuiBackground(pub(crate) Background); +impl> Draw for Foreground { + fn draw (&self, to: &mut TuiOut) { + let area = self.layout(to.area()); + to.fill_fg(area, self.0); + to.place_at(area, &self.1); + } +} +impl> Draw for Background { + fn draw (&self, to: &mut TuiOut) { + let area = self.layout(to.area()); + to.fill_bg(area, self.0); + to.place_at(area, &self.1); + } +} pub struct Modify(pub bool, pub Modifier, pub T); -pub struct Styled(pub Option