diff --git a/src/widget.rs b/src/widget.rs index 1ac044a..65f95f8 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -1,7 +1,8 @@ use async_trait::async_trait; use crate::widgets::{ - Background, Border, Either2, Either3, Float, JoinSegment, Layer2, Padding, Resize, + Background, Border, Boxed, BoxedAsync, Either2, Either3, Float, JoinSegment, Layer2, Padding, + Resize, }; use crate::{Frame, Size, WidthDb}; @@ -39,6 +40,20 @@ pub trait WidgetExt: Sized { Border::new(self) } + fn boxed<'a, E>(self) -> Boxed<'a, E> + where + Self: Widget + 'a, + { + Boxed::new(self) + } + + fn boxed_async<'a, E>(self) -> BoxedAsync<'a, E> + where + Self: AsyncWidget + Send + Sync + 'a, + { + BoxedAsync::new(self) + } + fn first2(self) -> Either2 { Either2::First(self) } diff --git a/src/widgets.rs b/src/widgets.rs index 49c65a5..4991618 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,5 +1,6 @@ pub mod background; pub mod border; +pub mod boxed; pub mod cursor; pub mod editor; pub mod either; @@ -14,6 +15,7 @@ pub mod text; pub use background::*; pub use border::*; +pub use boxed::*; pub use cursor::*; pub use editor::*; pub use either::*; diff --git a/src/widgets/boxed.rs b/src/widgets/boxed.rs new file mode 100644 index 0000000..050514c --- /dev/null +++ b/src/widgets/boxed.rs @@ -0,0 +1,116 @@ +use async_trait::async_trait; + +use crate::{AsyncWidget, Frame, Size, Widget, WidthDb}; + +pub struct Boxed<'a, E>(Box + 'a>); + +impl<'a, E> Boxed<'a, E> { + pub fn new(inner: I) -> Self + where + I: Widget + 'a, + { + Self(Box::new(inner)) + } +} + +trait WidgetWrapper { + fn wrap_size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result; + + fn wrap_draw(self: Box, frame: &mut Frame) -> Result<(), E>; +} + +impl WidgetWrapper for W +where + W: Widget, +{ + fn wrap_size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result { + self.size(widthdb, max_width, max_height) + } + + fn wrap_draw(self: Box, frame: &mut Frame) -> Result<(), E> { + (*self).draw(frame) + } +} + +impl Widget for Boxed<'_, E> { + fn size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result { + self.0.wrap_size(widthdb, max_width, max_height) + } + + fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.0.wrap_draw(frame) + } +} + +pub struct BoxedAsync<'a, E>(Box + Send + Sync + 'a>); + +impl<'a, E> BoxedAsync<'a, E> { + pub fn new(inner: I) -> Self + where + I: AsyncWidget + Send + Sync + 'a, + { + Self(Box::new(inner)) + } +} + +#[async_trait] +trait AsyncWidgetWrapper { + async fn wrap_size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result; + + async fn wrap_draw(self: Box, frame: &mut Frame) -> Result<(), E>; +} + +#[async_trait] +impl AsyncWidgetWrapper for W +where + W: AsyncWidget + Send + Sync, +{ + async fn wrap_size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result { + self.size(widthdb, max_width, max_height).await + } + + async fn wrap_draw(self: Box, frame: &mut Frame) -> Result<(), E> { + (*self).draw(frame).await + } +} + +#[async_trait] +impl AsyncWidget for BoxedAsync<'_, E> { + async fn size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result { + self.0.wrap_size(widthdb, max_width, max_height).await + } + + async fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.0.wrap_draw(frame).await + } +}