Skip to main content

ctl_layout/
indent.rs

1//! A widget moved right.
2
3use std::fmt;
4
5use ctl_text::{Context, Line, Measurement, Renderable};
6
7use crate::lines::indent_lines;
8
9/// A widget moved right by a number of cells.
10///
11/// The child gets the width that is left, but never less than 1 cell. So a
12/// child still draws when the indent is as wide as the context. A blank line
13/// stays blank.
14///
15/// The child may be borrowed, as in `Indent::new(2, &widget)`.
16pub struct Indent<'a> {
17    columns: u16,
18    child: Box<dyn Renderable + 'a>,
19}
20
21impl<'a> Indent<'a> {
22    /// `child` moved right by `cells` cells.
23    #[must_use]
24    pub fn new(cells: u16, child: impl Renderable + 'a) -> Self {
25        Self {
26            columns: cells,
27            child: Box::new(child),
28        }
29    }
30
31    fn inner(&self, context: &Context) -> Context {
32        context.at_width(context.width().saturating_sub(self.columns).max(1))
33    }
34}
35
36impl fmt::Debug for Indent<'_> {
37    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
38        formatter
39            .debug_struct("Indent")
40            .field("columns", &self.columns)
41            .finish_non_exhaustive()
42    }
43}
44
45impl Renderable for Indent<'_> {
46    fn measure(&self, context: &Context) -> Measurement {
47        let measured = self.child.measure(&self.inner(context));
48        Measurement::new(
49            measured.minimum().saturating_add(self.columns),
50            measured.maximum().saturating_add(self.columns),
51        )
52    }
53
54    fn render(&self, context: &Context) -> Vec<Line> {
55        indent_lines(self.child.render(&self.inner(context)), self.columns)
56    }
57}