Skip to main content

ctl_layout/
record.rs

1//! A record: key and value rows.
2
3use ctl_text::{Context, Line, Measurement, Renderable, Text};
4
5use crate::align::Align;
6use crate::column::Column;
7use crate::frame::{Frame, RecordStyle};
8use crate::table::Table;
9
10/// Labelled values, one pair to a row.
11///
12/// Two rows draw as:
13///
14/// ```text
15/// version  1.4.0
16/// channel  stable
17/// ```
18///
19/// A record is a two-column [`Table`] with no header. It shares the table's
20/// column widths, so a long value wraps under its own column and a long word
21/// keeps its line. A record with no rows draws nothing.
22#[derive(Clone, Debug)]
23pub struct Record {
24    table: Table,
25}
26
27impl Record {
28    /// A record with no rows, drawn in the default [`RecordStyle`]: keys
29    /// right-aligned and no frame.
30    #[must_use]
31    pub fn new() -> Self {
32        Self::default()
33    }
34
35    /// Sets how the record is drawn, replacing the default
36    /// [`RecordStyle::KeysRight`].
37    #[must_use]
38    pub fn style(self, style: RecordStyle) -> Self {
39        Self {
40            table: Self::table(style).rows(self.table.into_rows()),
41        }
42    }
43
44    /// Adds `key` and its `value` as the last row. Either may span several
45    /// lines, and the row is as tall as the taller of the two.
46    #[must_use]
47    pub fn row(self, key: impl Into<Text>, value: impl Into<Text>) -> Self {
48        self.push(key.into(), value.into())
49    }
50
51    fn push(mut self, key: Text, value: Text) -> Self {
52        self.table = self.table.row([key, value]);
53        self
54    }
55
56    fn table(style: RecordStyle) -> Table {
57        let (frame, keys) = match style {
58            RecordStyle::KeysRight => (Frame::Plain, Align::Right),
59            RecordStyle::KeysLeft => (Frame::Plain, Align::Left),
60            RecordStyle::Boxed => (Frame::Grid, Align::Left),
61        };
62        Table::new([Column::untitled().align(keys), Column::untitled()]).frame(frame)
63    }
64}
65
66impl Default for Record {
67    fn default() -> Self {
68        Self {
69            table: Self::table(RecordStyle::default()),
70        }
71    }
72}
73
74impl Renderable for Record {
75    fn measure(&self, context: &Context) -> Measurement {
76        self.table.measure(context)
77    }
78
79    fn render(&self, context: &Context) -> Vec<Line> {
80        self.table.render(context)
81    }
82}