ctl-layout 0.7.1

Terminal widgets built on ctl-text: tables, records, rules, stacks, and indents
Documentation
//! A widget moved right.

use std::fmt;

use ctl_text::{Context, Line, Measurement, Renderable};

use crate::lines::indent_lines;

/// A widget moved right by a number of cells.
///
/// The child gets the width that is left, but never less than 1 cell. So a
/// child still draws when the indent is as wide as the context. A blank line
/// stays blank.
///
/// The child may be borrowed, as in `Indent::new(2, &widget)`.
pub struct Indent<'a> {
    columns: u16,
    child: Box<dyn Renderable + 'a>,
}

impl<'a> Indent<'a> {
    /// `child` moved right by `cells` cells.
    #[must_use]
    pub fn new(cells: u16, child: impl Renderable + 'a) -> Self {
        Self {
            columns: cells,
            child: Box::new(child),
        }
    }

    fn inner(&self, context: &Context) -> Context {
        context.at_width(context.width().saturating_sub(self.columns).max(1))
    }
}

impl fmt::Debug for Indent<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter
            .debug_struct("Indent")
            .field("columns", &self.columns)
            .finish_non_exhaustive()
    }
}

impl Renderable for Indent<'_> {
    fn measure(&self, context: &Context) -> Measurement {
        let measured = self.child.measure(&self.inner(context));
        Measurement::new(
            measured.minimum().saturating_add(self.columns),
            measured.maximum().saturating_add(self.columns),
        )
    }

    fn render(&self, context: &Context) -> Vec<Line> {
        indent_lines(self.child.render(&self.inner(context)), self.columns)
    }
}