Add Float widget
This commit is contained in:
parent
bcc07dc9ba
commit
575faf9bbf
4 changed files with 137 additions and 12 deletions
|
|
@ -6,17 +6,20 @@ use toss::widgets::{BorderLook, Text};
|
|||
use toss::{Styled, Terminal, Widget, WidgetExt};
|
||||
|
||||
fn widget() -> impl Widget<Infallible> {
|
||||
Text::new(
|
||||
Styled::new("Hello world!", ContentStyle::default().green())
|
||||
.then_plain("\n")
|
||||
.then(
|
||||
"Press any key to exit",
|
||||
ContentStyle::default().on_dark_blue(),
|
||||
),
|
||||
)
|
||||
.border()
|
||||
.look(BorderLook::LINE_DOUBLE)
|
||||
.style(ContentStyle::default().dark_red())
|
||||
let styled = Styled::new("Hello world!", ContentStyle::default().green())
|
||||
.then_plain("\n")
|
||||
.then(
|
||||
"Press any key to exit",
|
||||
ContentStyle::default().on_dark_blue(),
|
||||
);
|
||||
Text::new(styled)
|
||||
.padding()
|
||||
.horizontal(1)
|
||||
.border()
|
||||
.look(BorderLook::LINE_DOUBLE)
|
||||
.style(ContentStyle::default().dark_red())
|
||||
.float()
|
||||
.all(0.5)
|
||||
}
|
||||
|
||||
fn render_frame(term: &mut Terminal) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::widgets::{Border, Padding};
|
||||
use crate::widgets::{Border, Float, Padding};
|
||||
use crate::{Frame, Size};
|
||||
|
||||
// TODO Feature-gate these traits
|
||||
|
|
@ -33,6 +33,10 @@ pub trait WidgetExt: Sized {
|
|||
Border::new(self)
|
||||
}
|
||||
|
||||
fn float(self) -> Float<Self> {
|
||||
Float::new(self)
|
||||
}
|
||||
|
||||
fn padding(self) -> Padding<Self> {
|
||||
Padding::new(self)
|
||||
}
|
||||
|
|
@ -45,6 +49,10 @@ pub trait AsyncWidgetExt: Sized {
|
|||
Border::new(self)
|
||||
}
|
||||
|
||||
fn float(self) -> Float<Self> {
|
||||
Float::new(self)
|
||||
}
|
||||
|
||||
fn padding(self) -> Padding<Self> {
|
||||
Padding::new(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
mod border;
|
||||
mod float;
|
||||
mod padding;
|
||||
mod text;
|
||||
|
||||
pub use border::*;
|
||||
pub use float::*;
|
||||
pub use padding::*;
|
||||
pub use text::*;
|
||||
|
|
|
|||
112
src/widgets/float.rs
Normal file
112
src/widgets/float.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{AsyncWidget, Frame, Pos, Size, Widget};
|
||||
|
||||
pub struct Float<I> {
|
||||
inner: I,
|
||||
horizontal: Option<f32>,
|
||||
vertical: Option<f32>,
|
||||
}
|
||||
|
||||
impl<I> Float<I> {
|
||||
pub fn new(inner: I) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
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
|
||||
}
|
||||
|
||||
pub fn all(self, position: f32) -> Self {
|
||||
self.horizontal(position).vertical(position)
|
||||
}
|
||||
|
||||
fn push_inner(&self, frame: &mut Frame, size: Size, mut inner_size: Size) {
|
||||
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).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).floor().min(available) as i32;
|
||||
}
|
||||
|
||||
frame.push(inner_pos, inner_size);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, I> Widget<E> for Float<I>
|
||||
where
|
||||
I: Widget<E>,
|
||||
{
|
||||
fn size(
|
||||
&self,
|
||||
frame: &mut Frame,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Result<Size, E> {
|
||||
self.inner.size(frame, max_width, max_height)
|
||||
}
|
||||
|
||||
fn draw(self, frame: &mut Frame) -> Result<(), E> {
|
||||
let size = frame.size();
|
||||
let inner_size = self
|
||||
.inner
|
||||
.size(frame, Some(size.width), Some(size.height))?;
|
||||
|
||||
self.push_inner(frame, size, inner_size);
|
||||
self.inner.draw(frame)?;
|
||||
frame.pop();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<E, I> AsyncWidget<E> for Float<I>
|
||||
where
|
||||
I: AsyncWidget<E> + Send + Sync,
|
||||
{
|
||||
async fn size(
|
||||
&self,
|
||||
frame: &mut Frame,
|
||||
max_width: Option<u16>,
|
||||
max_height: Option<u16>,
|
||||
) -> Result<Size, E> {
|
||||
self.inner.size(frame, max_width, max_height).await
|
||||
}
|
||||
|
||||
async fn draw(self, frame: &mut Frame) -> Result<(), E> {
|
||||
let size = frame.size();
|
||||
let inner_size = self
|
||||
.inner
|
||||
.size(frame, Some(size.width), Some(size.height))
|
||||
.await?;
|
||||
|
||||
self.push_inner(frame, size, inner_size);
|
||||
self.inner.draw(frame).await?;
|
||||
frame.pop();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue