embedded_text/alignment/
mod.rs

1//! Text alignment options.
2use crate::{
3    rendering::{cursor::Cursor, space_config::SpaceConfig},
4    style::LineMeasurement,
5    utils::str_width,
6};
7use embedded_graphics::text::renderer::TextRenderer;
8
9#[cfg(test)]
10mod test;
11
12/// Horizontal text alignment options.
13#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
14pub enum HorizontalAlignment {
15    /// Left aligned.
16    Left,
17
18    /// Center aligned.
19    Center,
20
21    /// Right aligned.
22    Right,
23
24    /// Fully justified.
25    Justified,
26}
27
28impl HorizontalAlignment {
29    /// Calculate offset from the left side and whitespace information.
30    pub(crate) fn place_line(
31        self,
32        renderer: &impl TextRenderer,
33        measurement: LineMeasurement,
34    ) -> (i32, SpaceConfig) {
35        let space_width = str_width(renderer, " ");
36        let space_config = SpaceConfig::new(space_width, None);
37        let remaining_space = measurement.max_line_width - measurement.width;
38        match self {
39            HorizontalAlignment::Left => (0, space_config),
40            HorizontalAlignment::Center => ((remaining_space as i32 + 1) / 2, space_config),
41            HorizontalAlignment::Right => (remaining_space as i32, space_config),
42            HorizontalAlignment::Justified => {
43                let space_count = measurement.space_count;
44                let space_info = if !measurement.last_line() && space_count != 0 {
45                    let space = remaining_space + space_count * space_width;
46                    let space_width = space / space_count;
47                    let extra_pixels = space % space_count;
48                    SpaceConfig::new(space_width, Some(extra_pixels))
49                } else {
50                    space_config
51                };
52                (0, space_info)
53            }
54        }
55    }
56
57    pub(crate) const fn leading_spaces(self) -> bool {
58        match self {
59            HorizontalAlignment::Left => true,
60            HorizontalAlignment::Center => false,
61            HorizontalAlignment::Right => false,
62            HorizontalAlignment::Justified => false,
63        }
64    }
65
66    pub(crate) const fn trailing_spaces(self) -> bool {
67        false
68    }
69}
70
71/// Vertical text alignment options.
72#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
73pub enum VerticalAlignment {
74    /// Top aligned text.
75    ///
76    /// The first line of the text will be rendered at the top of the text box.
77    Top,
78
79    /// Middle aligned text.
80    ///
81    /// The text will be vertically centered within the text box.
82    Middle,
83
84    /// Bottom aligned text.
85    ///
86    /// The last line of the text will be aligned to the bottom of the text box.
87    Bottom,
88}
89
90impl VerticalAlignment {
91    /// Set the cursor's initial vertical position
92    pub(crate) fn apply_vertical_alignment(
93        self,
94        cursor: &mut Cursor,
95        text_height: i32,
96        box_height: i32,
97    ) {
98        match self {
99            VerticalAlignment::Top => {
100                // nothing to do here
101            }
102
103            VerticalAlignment::Middle => {
104                let offset = (box_height - text_height) / 2;
105
106                cursor.y += offset;
107            }
108
109            VerticalAlignment::Bottom => {
110                let offset = box_height - text_height;
111
112                cursor.y += offset;
113            }
114        }
115    }
116}