diff --git a/src/ui.rs b/src/ui.rs index 208a8cd..b5e8873 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -32,6 +32,13 @@ use self::widgets::BoxedWidget; /// Time to spend batch processing events before redrawing the screen. const EVENT_PROCESSING_TIME: Duration = Duration::from_millis(1000 / 15); // 15 fps +/// Error for anything that can go wrong while rendering. +#[derive(Debug, thiserror::Error)] +pub enum UiError { + #[error("{0}")] + Io(#[from] io::Error), +} + pub enum UiEvent { GraphemeWidthsChanged, LogChanged, @@ -51,8 +58,6 @@ enum Mode { Log, } -// TODO Add Error for anything that can go wrong while rendering - pub struct Ui { event_tx: UnboundedSender, diff --git a/src/ui/widgets.rs b/src/ui/widgets.rs index 20fb6d3..6f137b8 100644 --- a/src/ui/widgets.rs +++ b/src/ui/widgets.rs @@ -19,7 +19,9 @@ pub mod rules; pub mod text; use async_trait::async_trait; -use toss::{Frame, Size, WidthDb}; +use toss::{AsyncWidget, Frame, Size, WidthDb}; + +use super::UiError; // TODO Add Error type and return Result-s (at least in Widget::render) @@ -42,3 +44,66 @@ impl From for BoxedWidget { Box::new(widget) } } + +/// Wrapper that implements [`Widget`] for an [`AsyncWidget`]. +pub struct AsyncWidgetWrapper { + inner: I, +} + +impl AsyncWidgetWrapper { + pub fn new(inner: I) -> Self { + Self { inner } + } +} + +#[async_trait] +impl Widget for AsyncWidgetWrapper +where + I: AsyncWidget + Send + Sync, +{ + async fn size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Size { + self.inner + .size(widthdb, max_width, max_height) + .await + .unwrap() + } + + async fn render(self: Box, frame: &mut Frame) { + self.inner.draw(frame).await.unwrap(); + } +} + +/// Wrapper that implements [`AsyncWidget`] for a [`Widget`]. +pub struct WidgetWrapper { + inner: BoxedWidget, +} + +impl WidgetWrapper { + pub fn new>(inner: W) -> Self { + Self { + inner: inner.into(), + } + } +} + +#[async_trait] +impl AsyncWidget for WidgetWrapper { + async fn size( + &self, + widthdb: &mut WidthDb, + max_width: Option, + max_height: Option, + ) -> Result { + Ok(self.inner.size(widthdb, max_width, max_height).await) + } + + async fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.inner.render(frame).await; + Ok(()) + } +}