From 38f8c0ed66d75e5a4d28381351bd99293835f7cb Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 21 Jul 2022 17:20:35 +0200 Subject: [PATCH] Add Float widget --- src/ui/widgets.rs | 1 + src/ui/widgets/float.rs | 65 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/ui/widgets/float.rs diff --git a/src/ui/widgets.rs b/src/ui/widgets.rs index 65376d0..addb443 100644 --- a/src/ui/widgets.rs +++ b/src/ui/widgets.rs @@ -5,6 +5,7 @@ pub mod background; pub mod border; pub mod empty; +pub mod float; pub mod join; pub mod layer; pub mod list; diff --git a/src/ui/widgets/float.rs b/src/ui/widgets/float.rs new file mode 100644 index 0000000..a70c854 --- /dev/null +++ b/src/ui/widgets/float.rs @@ -0,0 +1,65 @@ +use async_trait::async_trait; +use toss::frame::{Frame, Pos, Size}; + +use super::{BoxedWidget, Widget}; + +pub struct Float { + inner: BoxedWidget, + horizontal: Option, + vertical: Option, +} + +impl Float { + pub fn new>(inner: W) -> Self { + Self { + inner: inner.into(), + horizontal: None, + vertical: None, + } + } + + pub fn horizontal(mut self, position: f32) -> Self { + self.horizontal = Some(position); + self + } + + pub fn vertical(mut self, position: f32) -> Self { + self.vertical = Some(position); + self + } +} + +#[async_trait] +impl Widget for Float { + fn size(&self, frame: &mut Frame, max_width: Option, max_height: Option) -> Size { + self.inner.size(frame, max_width, max_height) + } + + async fn render(self: Box, frame: &mut Frame) { + let size = frame.size(); + + let mut inner_size = self.inner.size(frame, Some(size.width), Some(size.height)); + inner_size.width = inner_size.width.min(size.width); + inner_size.height = inner_size.height.min(size.height); + + let mut inner_pos = Pos::ZERO; + + if let Some(horizontal) = self.horizontal { + let available = (size.width - inner_size.width) as f32; + // Biased towards the left if horizontal lands exactly on the + // boundary between two cells + inner_pos.x = (horizontal * available as f32).floor().min(available) as i32; + } + + if let Some(vertical) = self.vertical { + let available = (size.height - inner_size.height) as f32; + // Biased towards the top if vertical lands exactly on the boundary + // between two cells + inner_pos.y = (vertical * available as f32).floor().min(available) as i32; + } + + frame.push(inner_pos, inner_size); + self.inner.render(frame).await; + frame.pop(); + } +}