1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::prelude::Terminal;
use crate::prelude::TerminalConst;
use crate::prelude::Widget;
use crate::style::Style;
use crate::terminal::{Rectangle, UpdateInfo, UpdateResult};
use crate::widgets::BoundingBox;
use crate::Error;
/// Text at the top-left of the terminal.
pub struct Text<'a> {
/// The text to display.
pub text: &'a str,
/// The style with which to display it.
pub style: Style,
}
impl<'a> Text<'a> {
/// Create a new [`Text`] with the default style.
///
/// ## Create a new [`Text`]
///
/// ```
/// use tuit::style::Style;
/// use tuit::widgets::builtins::Text;
///
/// let text_widget = Text::new("Hello!");
///
/// assert_eq!(text_widget.text, "Hello!");
/// assert_eq!(text_widget.style, Style::new());
/// ```
///
/// ## Using [`Text`]
///
/// ```
/// use tuit::prelude::*;
/// use tuit::widgets::builtins::Text;
/// use tuit::terminal::ConstantSize;
///
/// // 20x20 cells terminal. Okay... maybe not tremendous, but... you get it, right?
/// let mut tremendous_terminal: ConstantSize<20, 20> = ConstantSize::new();
/// // 1x3 cells terminal
/// let mut tiny_terminal: ConstantSize<1, 3> = ConstantSize::new();
///
/// let text_widget = Text::new("Hello!");
///
/// text_widget.drawn(&mut tremendous_terminal).expect("There is enough space");
/// text_widget.drawn(&mut tiny_terminal).expect_err("There is not enough space, so we get an `Err`.");
/// ```
#[must_use]
pub const fn new(text: &'a str) -> Self {
Self {
text,
style: Style::new(),
}
}
/// Apply a [`Style`] to the [`Text`].
///
/// ```
/// use tuit::style::{Ansi4, Style};
/// use tuit::widgets::builtins::Text;
///
/// let style = Style::new().bg_ansi4(Ansi4::BrightCyan);
/// let text_widget = Text::new("Hello!").styled(style);
///
/// assert_eq!(text_widget.text, "Hello!");
/// assert_eq!(text_widget.style, style);
/// ```
#[must_use]
pub const fn styled(mut self, style: Style) -> Self {
self.style = style;
self
}
}
impl Widget for Text<'_> {
fn update(
&mut self,
_update_info: UpdateInfo,
_terminal: impl TerminalConst,
) -> crate::Result<UpdateResult> {
Ok(UpdateResult::NoEvent)
}
fn draw(
&self,
_update_info: UpdateInfo,
mut terminal: impl Terminal,
) -> crate::Result<UpdateResult> {
let mut cells = terminal.cells_mut();
for (idx, character) in self.text.chars().enumerate() {
let current_cell = cells.next().ok_or(Error::OutOfBoundsIndex(idx))?;
current_cell.character = character;
current_cell.style = self.style.inherits(current_cell.style);
}
Ok(UpdateResult::NoEvent)
}
}
impl BoundingBox for Text<'_> {
fn bounding_box(&self, rect: Rectangle) -> crate::Result<Rectangle> {
let height = self.text.len().div_ceil(rect.width()).min(rect.height());
let width = self.text.len().min(rect.width());
Ok(Rectangle::of_size((width, height)))
}
fn completely_covers(&self, rectangle: Rectangle) -> bool {
self.text.len() >= rectangle.area()
}
}