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)
    }
}