1use sequoia_core::Size;
4use sequoia_text::{
5 ElideMode, FontStyle, FontWeight, LetterSpacing, LineHeight, RichAlign, TextSpan, TextSystem,
6 WrapMode,
7};
8
9pub struct LayoutCtx<'a> {
14 text: &'a mut TextSystem,
15 default_font_size: f32,
16 available_width: f32,
17}
18
19impl<'a> LayoutCtx<'a> {
20 pub fn new(text: &'a mut TextSystem, default_font_size: f32) -> Self {
23 Self {
24 text,
25 default_font_size,
26 available_width: f32::INFINITY,
27 }
28 }
29
30 pub fn default_font_size(&self) -> f32 {
32 self.default_font_size
33 }
34
35 pub fn set_available_width(&mut self, width: f32) {
37 self.available_width = if width.is_finite() {
38 width.max(0.0)
39 } else {
40 f32::INFINITY
41 };
42 }
43
44 pub fn available_width(&self) -> f32 {
46 self.available_width
47 }
48
49 pub fn text_width(&mut self, text: &str, size: f32) -> f32 {
51 self.text.text_width(text, size)
52 }
53
54 pub fn text_width_weighted(&mut self, text: &str, size: f32, weight: FontWeight) -> f32 {
56 self.text.text_width_weighted(text, size, weight)
57 }
58
59 pub fn text_width_spaced(&mut self, text: &str, size: f32, spacing: LetterSpacing) -> f32 {
61 self.text.text_width_spaced(text, size, spacing)
62 }
63
64 pub fn text_width_weighted_spaced(
66 &mut self,
67 text: &str,
68 size: f32,
69 weight: FontWeight,
70 spacing: LetterSpacing,
71 ) -> f32 {
72 self.text
73 .text_width_weighted_spaced(text, size, weight, spacing)
74 }
75
76 pub fn text_width_styled_spaced(
79 &mut self,
80 text: &str,
81 size: f32,
82 weight: FontWeight,
83 spacing: LetterSpacing,
84 family: Option<&str>,
85 style: FontStyle,
86 ) -> f32 {
87 self.text
88 .text_width_styled_spaced(text, size, weight, spacing, family, style)
89 }
90
91 pub fn caret_positions(&mut self, text: &str, size: f32, weight: FontWeight) -> Vec<f32> {
93 self.text.caret_positions(text, size, weight)
94 }
95
96 pub fn caret_positions_spaced(
98 &mut self,
99 text: &str,
100 size: f32,
101 weight: FontWeight,
102 spacing: LetterSpacing,
103 ) -> Vec<f32> {
104 self.text
105 .caret_positions_spaced(text, size, weight, spacing)
106 }
107
108 pub fn text_wrapped_size(
110 &mut self,
111 text: &str,
112 size: f32,
113 weight: FontWeight,
114 width: f32,
115 mode: WrapMode,
116 ) -> Size {
117 self.text_wrapped_size_spaced(text, size, weight, width, mode, 0.0)
118 }
119
120 pub fn text_wrapped_size_spaced(
122 &mut self,
123 text: &str,
124 size: f32,
125 weight: FontWeight,
126 width: f32,
127 mode: WrapMode,
128 spacing: LetterSpacing,
129 ) -> Size {
130 let shaped = self
131 .text
132 .shape_wrapped_spaced(text, size, weight, width, mode, spacing);
133 Size::new(shaped.width(), shaped.height())
134 }
135
136 pub fn text_wrapped_size_styled_spaced(
138 &mut self,
139 text: &str,
140 size: f32,
141 weight: FontWeight,
142 width: f32,
143 mode: WrapMode,
144 spacing: LetterSpacing,
145 family: Option<&str>,
146 style: FontStyle,
147 ) -> Size {
148 let shaped = self
149 .text
150 .shape_wrapped_styled_spaced(text, size, weight, width, mode, spacing, family, style);
151 Size::new(shaped.width(), shaped.height())
152 }
153
154 #[allow(clippy::too_many_arguments)]
156 pub fn text_wrapped_size_styled_spaced_lh(
157 &mut self,
158 text: &str,
159 size: f32,
160 weight: FontWeight,
161 width: f32,
162 mode: WrapMode,
163 spacing: LetterSpacing,
164 family: Option<&str>,
165 style: FontStyle,
166 line_height: LineHeight,
167 ) -> Size {
168 let shaped = self.text.shape_wrapped_styled_spaced_lh(
169 text,
170 size,
171 weight,
172 width,
173 mode,
174 spacing,
175 family,
176 style,
177 line_height,
178 );
179 Size::new(shaped.width(), shaped.height())
180 }
181
182 #[allow(clippy::too_many_arguments)]
184 pub fn text_min_content_width_styled_spaced(
185 &mut self,
186 text: &str,
187 size: f32,
188 weight: FontWeight,
189 spacing: LetterSpacing,
190 family: Option<&str>,
191 style: FontStyle,
192 mode: WrapMode,
193 ) -> f32 {
194 self.text
195 .min_content_width_styled_spaced(text, size, weight, spacing, family, style, mode)
196 }
197
198 #[allow(clippy::too_many_arguments)]
200 pub fn text_elide_lines_styled_spaced(
201 &mut self,
202 text: &str,
203 size: f32,
204 weight: FontWeight,
205 width: f32,
206 mode: WrapMode,
207 spacing: LetterSpacing,
208 family: Option<&str>,
209 style: FontStyle,
210 line_height: LineHeight,
211 max_lines: usize,
212 ) -> String {
213 self.text.elide_lines_styled_spaced(
214 text,
215 size,
216 weight,
217 width,
218 mode,
219 spacing,
220 family,
221 style,
222 line_height,
223 max_lines,
224 )
225 }
226
227 pub fn text_elided_size(
229 &mut self,
230 text: &str,
231 size: f32,
232 weight: FontWeight,
233 max_width: f32,
234 mode: ElideMode,
235 ) -> Size {
236 self.text_elided_size_spaced(text, size, weight, max_width, mode, 0.0)
237 }
238
239 pub fn text_elided_size_spaced(
241 &mut self,
242 text: &str,
243 size: f32,
244 weight: FontWeight,
245 max_width: f32,
246 mode: ElideMode,
247 spacing: LetterSpacing,
248 ) -> Size {
249 let shown = self
250 .text
251 .elide_spaced(text, size, weight, max_width, mode, spacing);
252 let w = self
253 .text
254 .text_width_weighted_spaced(&shown, size, weight, spacing)
255 .min(max_width.max(0.0));
256 Size::new(w, Self::text_line_height(size))
257 }
258
259 pub fn text_elided_size_styled_spaced(
261 &mut self,
262 text: &str,
263 size: f32,
264 weight: FontWeight,
265 max_width: f32,
266 mode: ElideMode,
267 spacing: LetterSpacing,
268 family: Option<&str>,
269 style: FontStyle,
270 ) -> Size {
271 let shown = self
272 .text
273 .elide_styled_spaced(text, size, weight, max_width, mode, spacing, family, style);
274 let w = self
275 .text
276 .text_width_styled_spaced(&shown, size, weight, spacing, family, style)
277 .min(max_width.max(0.0));
278 Size::new(w, Self::text_line_height(size))
279 }
280
281 #[allow(clippy::too_many_arguments)]
283 pub fn text_elided_size_styled_spaced_lh(
284 &mut self,
285 text: &str,
286 size: f32,
287 weight: FontWeight,
288 max_width: f32,
289 mode: ElideMode,
290 spacing: LetterSpacing,
291 family: Option<&str>,
292 style: FontStyle,
293 line_height: LineHeight,
294 ) -> Size {
295 let shown = self
296 .text
297 .elide_styled_spaced(text, size, weight, max_width, mode, spacing, family, style);
298 let w = self
299 .text
300 .text_width_styled_spaced(&shown, size, weight, spacing, family, style)
301 .min(max_width.max(0.0));
302 Size::new(w, Self::text_line_height_with(size, line_height))
303 }
304
305 pub fn text_line_height(size: f32) -> f32 {
307 Self::text_line_height_with(size, LineHeight::default())
308 }
309
310 pub fn text_line_height_with(size: f32, line_height: LineHeight) -> f32 {
312 line_height.resolve(size).max(1.0)
313 }
314
315 #[allow(clippy::too_many_arguments)]
317 pub fn text_first_baseline_styled_spaced_lh(
318 &mut self,
319 text: &str,
320 size: f32,
321 weight: FontWeight,
322 width: f32,
323 mode: WrapMode,
324 spacing: LetterSpacing,
325 family: Option<&str>,
326 style: FontStyle,
327 line_height: LineHeight,
328 ) -> f32 {
329 self.text
330 .shape_wrapped_styled_spaced_lh(
331 text,
332 size,
333 weight,
334 width,
335 mode,
336 spacing,
337 family,
338 style,
339 line_height,
340 )
341 .first_baseline()
342 }
343
344 pub fn rich_size(
346 &mut self,
347 spans: &[TextSpan],
348 size: f32,
349 width: f32,
350 mode: WrapMode,
351 spacing: LetterSpacing,
352 align: RichAlign,
353 ) -> Size {
354 self.rich_size_lh(
355 spans,
356 size,
357 width,
358 mode,
359 spacing,
360 align,
361 LineHeight::default(),
362 )
363 }
364
365 #[allow(clippy::too_many_arguments)]
367 pub fn rich_size_lh(
368 &mut self,
369 spans: &[TextSpan],
370 size: f32,
371 width: f32,
372 mode: WrapMode,
373 spacing: LetterSpacing,
374 align: RichAlign,
375 line_height: LineHeight,
376 ) -> Size {
377 self.text
378 .shape_rich_full_lh(spans, size, width, mode, spacing, align, line_height)
379 .size()
380 }
381
382 #[allow(clippy::too_many_arguments)]
384 pub fn rich_elide_lines(
385 &mut self,
386 spans: &[TextSpan],
387 size: f32,
388 width: f32,
389 mode: WrapMode,
390 spacing: LetterSpacing,
391 align: RichAlign,
392 line_height: LineHeight,
393 max_lines: usize,
394 ) -> Vec<TextSpan> {
395 self.text.elide_rich_lines(
396 spans,
397 size,
398 width,
399 mode,
400 spacing,
401 align,
402 line_height,
403 max_lines,
404 )
405 }
406
407 #[allow(clippy::too_many_arguments)]
409 pub fn rich_first_baseline(
410 &mut self,
411 spans: &[TextSpan],
412 size: f32,
413 width: f32,
414 mode: WrapMode,
415 spacing: LetterSpacing,
416 align: RichAlign,
417 line_height: LineHeight,
418 ) -> f32 {
419 self.text
420 .shape_rich_full_lh(spans, size, width, mode, spacing, align, line_height)
421 .line(0)
422 .map(|line| line.baseline)
423 .unwrap_or_else(|| Self::text_line_height_with(size, line_height) * 0.5)
424 }
425}