mod command;
mod label;
mod list;
mod text;
pub use command::*;
pub use label::*;
pub use list::*;
pub use text::*;
use tui::{
backend::Backend,
layout::Rect,
widgets::{StatefulWidget, Widget},
Frame,
};
use crate::theme::Theme;
#[derive(Default, Clone, Copy)]
#[cfg_attr(debug_assertions, derive(Debug))]
pub struct Offset {
pub x: u16,
pub y: u16,
}
impl Offset {
pub fn new(x: u16, y: u16) -> Self {
Self { x, y }
}
}
#[derive(Clone, Copy)]
#[cfg_attr(debug_assertions, derive(Debug))]
pub struct Area {
pub width: u16,
pub height: u16,
}
impl Default for Area {
fn default() -> Self {
Self { width: 1, height: 1 }
}
}
impl Area {
pub fn default_visible() -> Self {
Self { width: 25, height: 2 }
}
pub fn new(width: u16, height: u16) -> Self {
Self { width, height }
}
pub fn min_width(mut self, width: u16) -> Self {
self.width = width.max(self.width);
self
}
}
pub trait CustomWidget<'s> {
type Inner: Widget;
fn min_size(&self) -> Area;
fn is_focused(&self) -> bool;
fn prepare(&'s self, area: Rect, theme: Theme) -> (Option<Offset>, Self::Inner);
fn render_in<B: Backend>(&'s self, frame: &mut Frame<B>, area: Rect, theme: Theme)
where
Self: Sized,
{
let (offset, widget) = self.prepare(area, theme);
frame.render_widget(widget, area);
if self.is_focused() {
if let Some(offset) = offset {
frame.set_cursor(area.x + offset.x, area.y + offset.y);
}
}
}
}
pub trait CustomStatefulWidget<'s> {
type Inner: StatefulWidget;
fn min_size(&self) -> Area;
fn prepare(&'s mut self, area: Rect, theme: Theme)
-> (Self::Inner, &'s mut <Self::Inner as StatefulWidget>::State);
fn render_in<B: Backend>(&'s mut self, frame: &mut Frame<B>, area: Rect, theme: Theme)
where
Self: Sized,
{
let (widget, state) = self.prepare(area, theme);
frame.render_stateful_widget(widget, area, state);
}
}
pub trait IntoWidget<W> {
fn into_widget(self, theme: Theme) -> W;
}
impl<W, T> IntoWidget<W> for T
where
T: Into<W>,
{
fn into_widget(self, _theme: Theme) -> W {
self.into()
}
}
pub trait IntoCursorWidget<W> {
fn into_widget_and_cursor(self, theme: Theme) -> (W, Option<(Offset, Area)>);
}
impl<W, T> IntoCursorWidget<W> for T
where
T: Into<W>,
{
fn into_widget_and_cursor(self, _theme: Theme) -> (W, Option<(Offset, Area)>) {
(self.into(), None)
}
}