tuigui 0.23.0

An easy-to-use, highly extensible, and speedy TUI library.
Documentation
use crate::preludes::widget_creation::*;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// Column anchor
pub enum ColAnchor {
    Left,
    Center,
    Right,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// Row anchor
pub enum RowAnchor {
    Top,
    Center,
    Bottom,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// Terminal anchor
pub struct Anchor {
    pub col: ColAnchor,
    pub row: RowAnchor,
}

impl Anchor {
    /// Create new anchor
    pub fn new(col: ColAnchor, row: RowAnchor) -> Self {
        Self {
            col,
            row,
        }
    }

    /// Calculate the position of an area based on the parent (usually a canvas) size and the child (usually a widget) size
    pub fn get_position(&self, parent_size: Size, child_size: Size) -> Position {
        let mut col = match self.col {
            ColAnchor::Left => 0,
            ColAnchor::Center => parent_size.cols.saturating_sub(child_size.cols) >> 1,
            ColAnchor::Right => parent_size.cols.saturating_sub(child_size.cols),
        };

        let mut row = match self.row {
            RowAnchor::Top => 0,
            RowAnchor::Center => parent_size.rows.saturating_sub(child_size.rows) >> 1,
            RowAnchor::Bottom => parent_size.rows.saturating_sub(child_size.rows),
        };

        if child_size.cols > parent_size.cols {
            col = 0;
        }

        if child_size.rows > parent_size.rows {
            row = 0;
        }

        Position::new(col as i16, row as i16)
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// How to size the child widget of the anchor container widget
pub enum AnchorContainerWidgetSize {
    /// Consistent size that doesn't change when the terminal is resized
    Fixed(Size),
    /// Relative, changes when the terminal is resized
    Ratio(Size),
    /// Use the minimum size configured by the widget
    Min,
    /// Use the maximum size configured by the widget
    Max,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// Anchor container, anchor a widget
/// to a certain edge or center of the parent widget
pub struct AnchorContainer<W: Widget> {
    pub anchor: Anchor,
    pub widget: W,
    pub widget_size: AnchorContainerWidgetSize,
    widget_data: WidgetData,
}

impl<W: Widget> AnchorContainer<W> {
    pub fn new(
        anchor: Anchor,
        widget_size: AnchorContainerWidgetSize,
        widget: W,
    ) -> Self {
        Self {
            anchor,
            widget,
            widget_size,
            widget_data: WidgetData::new(),
        }
    }
}

impl<W: Widget> Widget for AnchorContainer<W> {
    fn draw(&mut self, canvas: &mut Canvas, state_frame: Option<&EventStateFrame>) {
        if canvas.is_visible() == false {
            return;
        }

        let child_info = self.widget.widget_info();

        let size = match self.widget_size {
            AnchorContainerWidgetSize::Fixed(size) => size,
            AnchorContainerWidgetSize::Ratio(ratio) => canvas.transform.size / ratio,
            AnchorContainerWidgetSize::Min => child_info.size_info.get_min(),
            AnchorContainerWidgetSize::Max => child_info.size_info.get_max(),
        };

        let mut inner = canvas.new_child(Transform::new(
            self.anchor.get_position(canvas.transform.size, size),
            size,
        ));

        self.widget.draw(&mut inner, state_frame);
    }

    fn widget_info(&self) -> WidgetInfo {
        let child_info = self.widget.widget_info();

        WidgetInfo {
            size_info: match child_info.size_info {
                WidgetSizeInfo::Dynamic { min, .. } => {
                    WidgetSizeInfo::Dynamic {
                        min,
                        max: None,
                    }
                },
                WidgetSizeInfo::Fixed(size) => {
                    WidgetSizeInfo::Dynamic {
                        min: Some(size),
                        max: None,
                    }
                },
            },
        }
    }

    fn widget_data(&mut self) -> &mut WidgetData {
        return &mut self.widget_data;
    }
}