1use crate::alignment;
3use crate::layout;
4use crate::renderer;
5use crate::text;
6use crate::widget::Tree;
7use crate::{Element, Layout, Length, Pixels, Point, Rectangle, Size, Widget};
8
9use std::borrow::Cow;
10
11pub use iced_style::text::{Appearance, StyleSheet};
12
13#[allow(missing_debug_implementations)]
29pub struct Text<'a, Renderer>
30where
31 Renderer: text::Renderer,
32 Renderer::Theme: StyleSheet,
33{
34 content: Cow<'a, str>,
35 size: Option<f32>,
36 width: Length,
37 height: Length,
38 horizontal_alignment: alignment::Horizontal,
39 vertical_alignment: alignment::Vertical,
40 font: Renderer::Font,
41 style: <Renderer::Theme as StyleSheet>::Style,
42}
43
44impl<'a, Renderer> Text<'a, Renderer>
45where
46 Renderer: text::Renderer,
47 Renderer::Theme: StyleSheet,
48{
49 pub fn new(content: impl Into<Cow<'a, str>>) -> Self {
51 Text {
52 content: content.into(),
53 size: None,
54 font: Default::default(),
55 width: Length::Shrink,
56 height: Length::Shrink,
57 horizontal_alignment: alignment::Horizontal::Left,
58 vertical_alignment: alignment::Vertical::Top,
59 style: Default::default(),
60 }
61 }
62
63 pub fn size(mut self, size: impl Into<Pixels>) -> Self {
65 self.size = Some(size.into().0);
66 self
67 }
68
69 pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
73 self.font = font.into();
74 self
75 }
76
77 pub fn style(
79 mut self,
80 style: impl Into<<Renderer::Theme as StyleSheet>::Style>,
81 ) -> Self {
82 self.style = style.into();
83 self
84 }
85
86 pub fn width(mut self, width: impl Into<Length>) -> Self {
88 self.width = width.into();
89 self
90 }
91
92 pub fn height(mut self, height: impl Into<Length>) -> Self {
94 self.height = height.into();
95 self
96 }
97
98 pub fn horizontal_alignment(
100 mut self,
101 alignment: alignment::Horizontal,
102 ) -> Self {
103 self.horizontal_alignment = alignment;
104 self
105 }
106
107 pub fn vertical_alignment(
109 mut self,
110 alignment: alignment::Vertical,
111 ) -> Self {
112 self.vertical_alignment = alignment;
113 self
114 }
115}
116
117impl<'a, Message, Renderer> Widget<Message, Renderer> for Text<'a, Renderer>
118where
119 Renderer: text::Renderer,
120 Renderer::Theme: StyleSheet,
121{
122 fn width(&self) -> Length {
123 self.width
124 }
125
126 fn height(&self) -> Length {
127 self.height
128 }
129
130 fn layout(
131 &self,
132 renderer: &Renderer,
133 limits: &layout::Limits,
134 ) -> layout::Node {
135 let limits = limits.width(self.width).height(self.height);
136
137 let size = self.size.unwrap_or_else(|| renderer.default_size());
138
139 let bounds = limits.max();
140
141 let (width, height) =
142 renderer.measure(&self.content, size, self.font.clone(), bounds);
143
144 let size = limits.resolve(Size::new(width, height));
145
146 layout::Node::new(size)
147 }
148
149 fn draw(
150 &self,
151 _state: &Tree,
152 renderer: &mut Renderer,
153 theme: &Renderer::Theme,
154 style: &renderer::Style,
155 layout: Layout<'_>,
156 _cursor_position: Point,
157 _viewport: &Rectangle,
158 ) {
159 draw(
160 renderer,
161 style,
162 layout,
163 &self.content,
164 self.size,
165 self.font.clone(),
166 theme.appearance(self.style),
167 self.horizontal_alignment,
168 self.vertical_alignment,
169 );
170 }
171}
172
173pub fn draw<Renderer>(
184 renderer: &mut Renderer,
185 style: &renderer::Style,
186 layout: Layout<'_>,
187 content: &str,
188 size: Option<f32>,
189 font: Renderer::Font,
190 appearance: Appearance,
191 horizontal_alignment: alignment::Horizontal,
192 vertical_alignment: alignment::Vertical,
193) where
194 Renderer: text::Renderer,
195{
196 let bounds = layout.bounds();
197
198 let x = match horizontal_alignment {
199 alignment::Horizontal::Left => bounds.x,
200 alignment::Horizontal::Center => bounds.center_x(),
201 alignment::Horizontal::Right => bounds.x + bounds.width,
202 };
203
204 let y = match vertical_alignment {
205 alignment::Vertical::Top => bounds.y,
206 alignment::Vertical::Center => bounds.center_y(),
207 alignment::Vertical::Bottom => bounds.y + bounds.height,
208 };
209
210 renderer.fill_text(crate::text::Text {
211 content,
212 size: size.unwrap_or_else(|| renderer.default_size()),
213 bounds: Rectangle { x, y, ..bounds },
214 color: appearance.color.unwrap_or(style.text_color),
215 font,
216 horizontal_alignment,
217 vertical_alignment,
218 });
219}
220
221impl<'a, Message, Renderer> From<Text<'a, Renderer>>
222 for Element<'a, Message, Renderer>
223where
224 Renderer: text::Renderer + 'a,
225 Renderer::Theme: StyleSheet,
226{
227 fn from(text: Text<'a, Renderer>) -> Element<'a, Message, Renderer> {
228 Element::new(text)
229 }
230}
231
232impl<'a, Renderer> Clone for Text<'a, Renderer>
233where
234 Renderer: text::Renderer,
235 Renderer::Theme: StyleSheet,
236{
237 fn clone(&self) -> Self {
238 Self {
239 content: self.content.clone(),
240 size: self.size,
241 width: self.width,
242 height: self.height,
243 horizontal_alignment: self.horizontal_alignment,
244 vertical_alignment: self.vertical_alignment,
245 font: self.font.clone(),
246 style: self.style,
247 }
248 }
249}
250
251impl<'a, Message, Renderer> From<&'a str> for Element<'a, Message, Renderer>
252where
253 Renderer: text::Renderer + 'a,
254 Renderer::Theme: StyleSheet,
255{
256 fn from(contents: &'a str) -> Self {
257 Text::new(contents).into()
258 }
259}