1use crate::{
22 brush::Brush,
23 core::{
24 algebra::Vector2, color::Color, math::Rect, reflect::prelude::*, uuid_provider,
25 variable::InheritableVariable, visitor::prelude::*,
26 },
27 font::{Font, FontGlyph, FontHeight, FontResource},
28 style::StyledProperty,
29 HorizontalAlignment, VerticalAlignment,
30};
31use fyrox_core::log::Log;
32use fyrox_resource::state::{LoadError, ResourceState};
33pub use run::*;
34use std::{
35 ops::{Range, RangeBounds},
36 path::PathBuf,
37};
38use strum_macros::{AsRefStr, EnumString, VariantNames};
39use textwrapper::*;
40
41mod run;
42mod textwrapper;
43
44#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Visit, Reflect)]
46pub struct Position {
47 pub line: usize,
49
50 pub offset: usize,
52}
53
54#[derive(Debug, Clone, Default)]
55pub struct TextGlyph {
56 pub bounds: Rect<f32>,
57 pub tex_coords: [Vector2<f32>; 4],
58 pub atlas_page_index: usize,
59 pub source_char_index: usize,
60}
61
62#[derive(Copy, Clone, Debug, Default)]
63pub struct TextLine {
64 pub begin: usize,
66 pub end: usize,
68 pub width: f32,
70 pub height: f32,
72 pub x_offset: f32,
74 pub y_offset: f32,
76}
77
78impl TextLine {
79 fn new() -> TextLine {
80 TextLine {
81 begin: 0,
82 end: 0,
83 width: 0.0,
84 height: 0.0,
85 x_offset: 0.0,
86 y_offset: 0.0,
87 }
88 }
89
90 pub fn len(&self) -> usize {
91 self.end - self.begin
92 }
93
94 pub fn is_empty(&self) -> bool {
95 self.end == self.begin
96 }
97
98 pub fn y_distance(&self, y: f32) -> f32 {
99 (self.y_offset + self.height / 2.0 - y).abs()
100 }
101}
102
103#[derive(
105 Default,
106 Copy,
107 Clone,
108 PartialOrd,
109 PartialEq,
110 Hash,
111 Debug,
112 Eq,
113 Visit,
114 Reflect,
115 AsRefStr,
116 EnumString,
117 VariantNames,
118)]
119pub enum WrapMode {
120 #[default]
122 NoWrap,
123
124 Letter,
126
127 Word,
129}
130
131uuid_provider!(WrapMode = "f1290ceb-3fee-461f-a1e9-f9450bd06805");
132
133struct GlyphMetrics<'a> {
134 font: &'a mut Font,
135 size: f32,
136}
137
138impl GlyphMetrics<'_> {
139 fn ascender(&self) -> f32 {
140 self.font.ascender(self.size)
141 }
142
143 fn descender(&self) -> f32 {
144 self.font.descender(self.size)
145 }
146
147 fn newline_advance(&self) -> f32 {
148 self.size / 2.0
149 }
150
151 fn horizontal_kerning(&self, left: char, right: char) -> Option<f32> {
152 self.font.horizontal_kerning(self.size, left, right)
153 }
154
155 fn advance(&mut self, c: char) -> f32 {
156 match c {
157 '\n' => self.newline_advance(),
158 _ => self.font.glyph_advance(c, self.size),
159 }
160 }
161
162 fn glyph(&mut self, c: char, super_sampling_scale: f32) -> Option<&FontGlyph> {
163 self.font.glyph(c, self.size * super_sampling_scale)
164 }
165}
166
167fn build_glyph(
168 metrics: &mut GlyphMetrics,
169 mut x: f32,
170 mut y: f32,
171 source_char_index: usize,
172 character: char,
173 prev_character: Option<char>,
174 super_sampling_scale: f32,
175) -> (TextGlyph, f32) {
176 let ascender = metrics.ascender();
177 let font_size = metrics.size;
178
179 x = x.floor();
180 y = y.floor();
181
182 match metrics.glyph(character, super_sampling_scale) {
184 Some(glyph) => {
185 let k = 1.0 / super_sampling_scale;
188 let rect = Rect::new(
190 x + glyph.bitmap_left * k,
191 y + ascender.floor() - glyph.bitmap_top * k - (glyph.bitmap_height * k),
192 glyph.bitmap_width * k,
193 glyph.bitmap_height * k,
194 );
195 let text_glyph = TextGlyph {
196 bounds: rect,
197 tex_coords: glyph.tex_coords,
198 atlas_page_index: glyph.page_index,
199 source_char_index,
200 };
201 let advance = glyph.advance
202 + prev_character
203 .and_then(|prev| metrics.horizontal_kerning(prev, character))
204 .unwrap_or_default();
205 (text_glyph, advance * k)
206 }
207 None => {
208 let rect = Rect::new(x, y + ascender, font_size, font_size);
210 let text_glyph = TextGlyph {
211 bounds: rect,
212 tex_coords: [Vector2::default(); 4],
213 atlas_page_index: 0,
214 source_char_index,
215 };
216 (text_glyph, rect.w())
217 }
218 }
219}
220
221struct WrapSink<'a> {
222 lines: &'a mut Vec<TextLine>,
223 normal_width: f32,
224 first_width: f32,
225}
226
227impl LineSink for WrapSink<'_> {
228 fn push_line(&mut self, range: Range<usize>, width: f32) {
229 let mut line = TextLine::new();
230 line.begin = range.start;
231 line.end = range.end;
232 line.width = width;
233 self.lines.push(line);
234 }
235
236 fn max_width(&self) -> f32 {
237 if self.lines.is_empty() {
238 self.first_width
239 } else {
240 self.normal_width
241 }
242 }
243}
244
245#[derive(Default, Clone, Debug, Visit, Reflect)]
246pub struct FormattedText {
247 font: InheritableVariable<FontResource>,
248 text: InheritableVariable<Vec<char>>,
249 #[reflect(hidden)]
253 #[visit(skip)]
254 lines: Vec<TextLine>,
255 #[visit(skip)]
257 #[reflect(hidden)]
258 glyphs: Vec<TextGlyph>,
259 vertical_alignment: InheritableVariable<VerticalAlignment>,
260 horizontal_alignment: InheritableVariable<HorizontalAlignment>,
261 #[reflect(hidden)]
262 brush: InheritableVariable<Brush>,
263 #[visit(skip)]
264 #[reflect(hidden)]
265 constraint: Vector2<f32>,
266 wrap: InheritableVariable<WrapMode>,
267 mask_char: InheritableVariable<Option<char>>,
268 #[visit(skip)]
269 #[reflect(hidden)]
270 pub(crate) super_sampling_scale: f32,
271 #[visit(rename = "Height")]
272 font_size: InheritableVariable<StyledProperty<f32>>,
273 pub shadow: InheritableVariable<bool>,
274 pub shadow_brush: InheritableVariable<Brush>,
275 pub shadow_dilation: InheritableVariable<f32>,
276 pub shadow_offset: InheritableVariable<Vector2<f32>>,
277 #[visit(optional)]
278 pub runs: RunSet,
279 #[visit(optional)]
282 pub line_indent: InheritableVariable<f32>,
283 #[visit(optional)]
285 pub line_space: InheritableVariable<f32>,
286}
287
288impl FormattedText {
289 pub fn font_at(&self, index: usize) -> FontResource {
290 self.runs.font_at(index).unwrap_or_else(|| self.get_font())
291 }
292 pub fn font_size_at(&self, index: usize) -> f32 {
293 self.runs
294 .font_size_at(index)
295 .unwrap_or_else(|| self.font_size().property)
296 }
297 pub fn brush_at(&self, index: usize) -> Brush {
298 self.runs.brush_at(index).unwrap_or_else(|| self.brush())
299 }
300 pub fn shadow_at(&self, index: usize) -> bool {
301 self.runs.shadow_at(index).unwrap_or(*self.shadow)
302 }
303 pub fn shadow_brush_at(&self, index: usize) -> Brush {
304 self.runs
305 .shadow_brush_at(index)
306 .unwrap_or_else(|| self.shadow_brush.clone_inner())
307 }
308 pub fn shadow_dilation_at(&self, index: usize) -> f32 {
309 self.runs
310 .shadow_dilation_at(index)
311 .unwrap_or(*self.shadow_dilation)
312 }
313 pub fn shadow_offset_at(&self, index: usize) -> Vector2<f32> {
314 self.runs
315 .shadow_offset_at(index)
316 .unwrap_or(*self.shadow_offset)
317 }
318 pub fn nearest_valid_position(&self, start: Position) -> Position {
319 if self.lines.is_empty() {
320 return Position::default();
321 }
322 let mut pos = start;
323 pos.line = usize::min(pos.line, self.lines.len() - 1);
324 pos.offset = usize::min(pos.offset, self.lines[pos.line].len());
325 pos
326 }
327 pub fn get_relative_position_x(&self, start: Position, offset: isize) -> Position {
328 if self.lines.is_empty() {
329 return Position::default();
330 }
331 let mut pos = self.nearest_valid_position(start);
332 let distance = offset.abs();
333 for _ in 0..distance {
334 if offset < 0 {
335 if pos.offset > 0 {
336 pos.offset -= 1
337 } else if pos.line > 0 {
338 pos.line -= 1;
339 pos.offset = self.lines[pos.line].len().saturating_sub(1);
340 } else {
341 pos.offset = 0;
342 break;
343 }
344 } else {
345 let line = &self.lines[pos.line];
346 if pos.offset + 1 < line.len() {
347 pos.offset += 1;
348 } else if pos.line + 1 < self.lines.len() {
349 pos.line += 1;
350 pos.offset = 0;
351 } else {
352 pos.offset = line.len();
353 break;
354 }
355 }
356 }
357 pos
358 }
359
360 pub fn get_relative_position_y(&self, start: Position, offset: isize) -> Position {
361 let mut pos = self.nearest_valid_position(start);
362 pos.line = pos.line.saturating_add_signed(offset);
363 self.nearest_valid_position(pos)
364 }
365
366 pub fn get_line_range(&self, line: usize) -> Range<Position> {
367 let length = self.lines.get(line).map(TextLine::len).unwrap_or(0);
368 Range {
369 start: Position { line, offset: 0 },
370 end: Position {
371 line,
372 offset: length,
373 },
374 }
375 }
376
377 pub fn iter_line_ranges_within(
378 &self,
379 range: Range<Position>,
380 ) -> impl Iterator<Item = Range<Position>> + '_ {
381 (range.start.line..=range.end.line).map(move |i| {
382 let r = self.get_line_range(i);
383 Range {
384 start: Position::max(range.start, r.start),
385 end: Position::min(range.end, r.end),
386 }
387 })
388 }
389
390 pub fn end_position(&self) -> Position {
391 match self.lines.iter().enumerate().next_back() {
392 Some((i, line)) => Position {
393 line: i,
394 offset: line.len(),
395 },
396 None => Position::default(),
397 }
398 }
399
400 fn position_to_char_index_internal(&self, position: Position, clamp: bool) -> Option<usize> {
401 self.lines.get(position.line).map(|line| {
402 line.begin
403 + position.offset.min(if clamp {
404 line.len().saturating_sub(1)
405 } else {
406 line.len()
407 })
408 })
409 }
410
411 pub fn position_range_to_char_index_range(&self, range: Range<Position>) -> Range<usize> {
412 let start = self
413 .position_to_char_index_unclamped(range.start)
414 .unwrap_or(0);
415 let end = self
416 .position_to_char_index_unclamped(range.end)
417 .unwrap_or(self.text.len());
418 start..end
419 }
420 pub fn position_to_char_index_unclamped(&self, position: Position) -> Option<usize> {
425 self.position_to_char_index_internal(position, false)
426 }
427
428 pub fn position_to_char_index_clamped(&self, position: Position) -> Option<usize> {
435 self.position_to_char_index_internal(position, true)
436 }
437
438 pub fn char_index_to_position(&self, i: usize) -> Option<Position> {
440 self.lines
441 .iter()
442 .enumerate()
443 .find_map(|(line_index, line)| {
444 if (line.begin..line.end).contains(&i) {
445 Some(Position {
446 line: line_index,
447 offset: i - line.begin,
448 })
449 } else {
450 None
451 }
452 })
453 .or(Some(self.end_position()))
454 }
455
456 pub fn position_to_local(&self, position: Position) -> Vector2<f32> {
457 if self.font.state().data().is_none() {
458 return Default::default();
459 }
460 let position = self.nearest_valid_position(position);
461 let line = &self.lines[position.line];
462 let caret_pos = Vector2::new(line.x_offset, line.y_offset);
463 let range = line.begin..line.begin + position.offset;
464 caret_pos + Vector2::new(self.get_range_width(range), 0.0)
465 }
466
467 pub fn local_to_position(&self, point: Vector2<f32>) -> Position {
468 if self.get_font().state().data().is_none() {
469 return Position::default();
470 }
471 let y = point.y;
472
473 let Some(line_index) = self
474 .lines
475 .iter()
476 .enumerate()
477 .map(|(i, a)| (i, a.y_distance(y)))
478 .min_by(|a, b| f32::total_cmp(&a.1, &b.1))
479 .map(|(i, _)| i)
480 else {
481 return Position::default();
482 };
483 let line = self.lines[line_index];
484 let x = point.x - line.x_offset;
485 let mut glyph_x: f32 = 0.0;
486 let mut min_dist: f32 = x.abs();
487 let mut min_index: usize = 0;
488 for (offset, char_index) in (line.begin..line.end).enumerate() {
489 glyph_x += self.get_char_width(char_index).unwrap_or_default();
490 let dist = (x - glyph_x).abs();
491 if dist < min_dist {
492 min_dist = dist;
493 min_index = offset + 1;
494 }
495 }
496 Position {
497 line: line_index,
498 offset: min_index,
499 }
500 }
501
502 pub fn get_glyphs(&self) -> &[TextGlyph] {
503 &self.glyphs
504 }
505
506 pub fn get_glyph_draw_values(
507 &self,
508 layer: DrawValueLayer,
509 glyph: &TextGlyph,
510 ) -> GlyphDrawValues {
511 let atlas_page_index = glyph.atlas_page_index;
512 let i = glyph.source_char_index;
513 let font = self.font_at(i);
514 let height = FontHeight::from(self.font_size_at(i) * self.super_sampling_scale);
515 match layer {
516 DrawValueLayer::Main => GlyphDrawValues {
517 atlas_page_index,
518 font,
519 brush: self.brush_at(i),
520 height,
521 },
522 DrawValueLayer::Shadow => GlyphDrawValues {
523 atlas_page_index,
524 font,
525 brush: self.shadow_brush_at(i),
526 height,
527 },
528 }
529 }
530
531 pub fn get_font(&self) -> FontResource {
532 (*self.font).clone()
533 }
534
535 pub fn set_font(&mut self, font: FontResource) -> &mut Self {
536 self.font.set_value_and_mark_modified(font);
537 self
538 }
539
540 pub fn font_size(&self) -> &StyledProperty<f32> {
541 &self.font_size
542 }
543
544 pub fn super_sampled_font_size(&self) -> f32 {
545 **self.font_size * self.super_sampling_scale
546 }
547
548 pub fn set_font_size(&mut self, font_size: StyledProperty<f32>) -> &mut Self {
549 self.font_size.set_value_and_mark_modified(font_size);
550 self
551 }
552
553 pub fn get_lines(&self) -> &[TextLine] {
554 &self.lines
555 }
556
557 pub fn set_vertical_alignment(&mut self, vertical_alignment: VerticalAlignment) -> &mut Self {
558 self.vertical_alignment
559 .set_value_and_mark_modified(vertical_alignment);
560 self
561 }
562
563 pub fn vertical_alignment(&self) -> VerticalAlignment {
564 *self.vertical_alignment
565 }
566
567 pub fn set_horizontal_alignment(
568 &mut self,
569 horizontal_alignment: HorizontalAlignment,
570 ) -> &mut Self {
571 self.horizontal_alignment
572 .set_value_and_mark_modified(horizontal_alignment);
573 self
574 }
575
576 pub fn horizontal_alignment(&self) -> HorizontalAlignment {
577 *self.horizontal_alignment
578 }
579
580 pub fn set_brush(&mut self, brush: Brush) -> &mut Self {
581 self.brush.set_value_and_mark_modified(brush);
582 self
583 }
584
585 pub fn brush(&self) -> Brush {
586 (*self.brush).clone()
587 }
588
589 pub fn set_super_sampling_scale(&mut self, scale: f32) -> &mut Self {
590 self.super_sampling_scale = scale;
591 self
592 }
593
594 pub fn set_constraint(&mut self, constraint: Vector2<f32>) -> &mut Self {
595 self.constraint = constraint;
596 self
597 }
598
599 pub fn get_raw_text(&self) -> &[char] {
600 &self.text
601 }
602
603 pub fn text(&self) -> String {
604 self.text.iter().collect()
605 }
606
607 pub fn text_range(&self, range: Range<usize>) -> String {
608 self.text[range].iter().collect()
609 }
610
611 pub fn get_char_width(&self, index: usize) -> Option<f32> {
613 let glyph = self.text.get(index)?;
614 Some(
615 GlyphMetrics {
616 font: &mut self.font_at(index).data_ref(),
617 size: self.font_size_at(index),
618 }
619 .advance(*glyph),
620 )
621 }
622
623 pub fn get_range_width<T: IntoIterator<Item = usize>>(&self, range: T) -> f32 {
626 let mut width = 0.0;
627 for index in range {
628 width += self.get_char_width(index).unwrap_or_default();
629 }
630 width
631 }
632
633 pub fn text_rect<R: RangeBounds<usize>>(&self, line: usize, range: R) -> Option<Rect<f32>> {
641 let line = self.lines.get(line)?;
642 let x = line.x_offset;
643 let y = line.y_offset;
644 let h = line.height;
645 use std::ops::Bound;
646 let start = match range.start_bound() {
647 Bound::Included(&n) => n,
648 Bound::Excluded(&n) => n + 1,
649 Bound::Unbounded => 0,
650 };
651 let end = match range.end_bound() {
652 Bound::Included(&n) => n + 1,
653 Bound::Excluded(&n) => n,
654 Bound::Unbounded => line.len(),
655 };
656 let start = line.begin + start;
657 let end = line.begin + end;
658 let offset = self.get_range_width(line.begin..start);
659 let w = self.get_range_width(start..end);
660 Some(Rect::new(offset + x, y, w, h))
661 }
662
663 pub fn set_text<P: AsRef<str>>(&mut self, text: P) -> &mut Self {
664 self.text
665 .set_value_and_mark_modified(text.as_ref().chars().collect());
666 self
667 }
668
669 pub fn set_chars(&mut self, text: Vec<char>) -> &mut Self {
670 self.text.set_value_and_mark_modified(text);
671 self
672 }
673
674 pub fn set_wrap(&mut self, wrap: WrapMode) -> &mut Self {
675 self.wrap.set_value_and_mark_modified(wrap);
676 self
677 }
678
679 pub fn set_shadow(&mut self, shadow: bool) -> &mut Self {
681 self.shadow.set_value_and_mark_modified(shadow);
682 self
683 }
684
685 pub fn set_shadow_brush(&mut self, brush: Brush) -> &mut Self {
687 self.shadow_brush.set_value_and_mark_modified(brush);
688 self
689 }
690
691 pub fn set_shadow_dilation(&mut self, thickness: f32) -> &mut Self {
694 self.shadow_dilation.set_value_and_mark_modified(thickness);
695 self
696 }
697
698 pub fn set_shadow_offset(&mut self, offset: Vector2<f32>) -> &mut Self {
700 self.shadow_offset.set_value_and_mark_modified(offset);
701 self
702 }
703
704 pub fn runs(&self) -> &RunSet {
708 &self.runs
709 }
710
711 pub fn runs_mut(&mut self) -> &mut RunSet {
715 &mut self.runs
716 }
717
718 pub fn set_runs(&mut self, runs: RunSet) -> &mut Self {
722 self.runs = runs;
723 self
724 }
725
726 pub fn set_line_indent(&mut self, indent: f32) -> &mut Self {
731 self.line_indent.set_value_and_mark_modified(indent);
732 self
733 }
734
735 pub fn line_indent(&mut self) -> f32 {
740 *self.line_indent
741 }
742
743 pub fn set_line_space(&mut self, space: f32) -> &mut Self {
746 self.line_space.set_value_and_mark_modified(space);
747 self
748 }
749
750 pub fn line_space(&self) -> f32 {
753 *self.line_space
754 }
755
756 pub fn wrap_mode(&self) -> WrapMode {
757 *self.wrap
758 }
759
760 pub fn insert_char(&mut self, code: char, index: usize) -> &mut Self {
761 self.text.insert(index, code);
762 self
763 }
764
765 pub fn insert_str(&mut self, str: &str, position: usize) -> &mut Self {
766 for (i, code) in str.chars().enumerate() {
767 self.text.insert(position + i, code);
768 }
769
770 self
771 }
772
773 pub fn remove_range(&mut self, range: Range<usize>) -> &mut Self {
774 self.text.drain(range);
775 self
776 }
777
778 pub fn remove_at(&mut self, index: usize) -> &mut Self {
779 self.text.remove(index);
780 self
781 }
782
783 pub async fn wait_for_fonts(&mut self) -> Result<(), LoadError> {
785 (*self.font).clone().await?;
786 for run in self.runs.iter() {
787 if let Some(font) = run.font() {
788 font.clone().await?;
789 }
790 }
791 Ok(())
792 }
793
794 pub fn are_fonts_loaded(&self) -> bool {
797 if !self.font.is_ok() {
798 return false;
799 }
800 for run in self.runs.iter() {
801 if let Some(font) = run.font() {
802 if !font.is_ok() {
803 return false;
804 }
805 }
806 }
807 true
808 }
809
810 pub fn are_fonts_loading(&self) -> bool {
811 if !self.font.is_loading() {
812 return true;
813 }
814 for run in self.runs.iter() {
815 if let Some(font) = run.font() {
816 if !font.is_loading() {
817 return true;
818 }
819 }
820 }
821 false
822 }
823
824 pub fn font_load_error_list(&self) -> Vec<(PathBuf, LoadError)> {
825 let mut list = vec![];
826 if let ResourceState::LoadError { path, error } = &self.font.header().state {
827 list.push((path.clone(), error.clone()));
828 }
829 for run in self.runs.iter() {
830 if let Some(font) = run.font() {
831 if let ResourceState::LoadError { path, error } = &font.header().state {
832 list.push((path.clone(), error.clone()));
833 }
834 }
835 }
836 list
837 }
838
839 pub fn font_loading_summary(&self) -> String {
840 use std::fmt::Write;
841 let mut result = String::default();
842 write!(result, "Primary font: {}", self.font.header().state).unwrap();
843 for run in self.runs.iter() {
844 if let Some(font) = run.font() {
845 write!(result, "\nRun {:?}: {}", run.range, font.header().state).unwrap();
846 }
847 }
848 result
849 }
850
851 pub fn build(&mut self) -> Vector2<f32> {
852 let mut lines = std::mem::take(&mut self.lines);
853 lines.clear();
854 if !self.are_fonts_loaded() {
856 Log::err(format!(
857 "Text failed to build due to unloaded fonts. {:?}.\n{}",
858 self.text(),
859 self.font_loading_summary(),
860 ));
861 return Vector2::default();
862 }
863 let first_indent = self.line_indent.max(0.0);
864 let normal_indent = -self.line_indent.min(0.0);
865 let sink = WrapSink {
866 lines: &mut lines,
867 normal_width: self.constraint.x - normal_indent,
868 first_width: self.constraint.x - first_indent,
869 };
870 if let Some(mask) = *self.mask_char {
871 let advance = GlyphMetrics {
872 font: &mut self.font.data_ref(),
873 size: **self.font_size,
874 }
875 .advance(mask);
876 match *self.wrap {
877 WrapMode::NoWrap => wrap_mask(NoWrap::new(sink), self.text.len(), mask, advance),
878 WrapMode::Letter => wrap_mask(
879 LetterWrap::new(sink),
880 self.text.len(),
881 mask,
882 **self.font_size,
883 ),
884 WrapMode::Word => wrap_mask(WordWrap::new(sink), self.text.len(), mask, advance),
885 }
886 } else {
887 let source = self.text.iter().enumerate().map(|(i, c)| {
888 let a = GlyphMetrics {
889 font: &mut self.font_at(i).data_ref(),
890 size: self.font_size_at(i),
891 }
892 .advance(*c);
893 (*c, a)
894 });
895 match *self.wrap {
896 WrapMode::NoWrap => wrap(NoWrap::new(sink), source),
897 WrapMode::Letter => wrap(LetterWrap::new(sink), source),
898 WrapMode::Word => wrap(WordWrap::new(sink), source),
899 }
900 }
901
902 let mut total_height = 0.0;
903 for (i, line) in lines.iter_mut().enumerate() {
905 let indent = if i == 0 { first_indent } else { normal_indent };
906 match *self.horizontal_alignment {
907 HorizontalAlignment::Left => line.x_offset = indent,
908 HorizontalAlignment::Center => {
909 if self.constraint.x.is_infinite() {
910 line.x_offset = indent;
911 } else {
912 line.x_offset = 0.5 * (self.constraint.x - line.width).max(0.0);
913 }
914 }
915 HorizontalAlignment::Right => {
916 if self.constraint.x.is_infinite() {
917 line.x_offset = indent;
918 } else {
919 line.x_offset = (self.constraint.x - line.width - indent).max(0.0)
920 }
921 }
922 HorizontalAlignment::Stretch => line.x_offset = indent,
923 }
924 }
925 for line in lines.iter_mut() {
927 if self.mask_char.is_some() || self.runs.is_empty() {
928 line.height = GlyphMetrics {
929 font: &mut self.font.data_ref(),
930 size: **self.font_size,
931 }
932 .ascender();
933 } else {
934 for i in line.begin..line.end {
935 let h = GlyphMetrics {
936 font: &mut self.font_at(i).data_ref(),
937 size: self.font_size_at(i),
938 }
939 .ascender();
940 line.height = line.height.max(h);
941 }
942 }
943 total_height += line.height + self.line_space();
944 }
945 total_height -= self.line_space();
946
947 self.glyphs.clear();
949
950 let cursor_y_start = match *self.vertical_alignment {
951 VerticalAlignment::Top => 0.0,
952 VerticalAlignment::Center => {
953 if self.constraint.y.is_infinite() {
954 0.0
955 } else {
956 (self.constraint.y - total_height).max(0.0) * 0.5
957 }
958 }
959 VerticalAlignment::Bottom => {
960 if self.constraint.y.is_infinite() {
961 0.0
962 } else {
963 (self.constraint.y - total_height).max(0.0)
964 }
965 }
966 VerticalAlignment::Stretch => 0.0,
967 };
968 let mut y: f32 = cursor_y_start.floor();
969 for line in lines.iter_mut() {
970 let mut x = line.x_offset.floor();
971 if let Some(mask) = *self.mask_char {
972 let mut prev = None;
973 let mut metrics = GlyphMetrics {
974 font: &mut self.font.data_ref(),
975 size: **self.font_size,
976 };
977 for c in std::iter::repeat_n(mask, line.len()) {
978 let (glyph, advance) =
979 build_glyph(&mut metrics, x, y, 0, c, prev, self.super_sampling_scale);
980 self.glyphs.push(glyph);
981 x += advance;
982 prev = Some(c);
983 }
984 } else {
985 let mut prev = None;
986 for (i, &c) in self.text.iter().enumerate().take(line.end).skip(line.begin) {
987 let font = self.font_at(i);
988 let font = &mut font.data_ref();
989 let mut metrics = GlyphMetrics {
990 font,
991 size: self.font_size_at(i),
992 };
993 match c {
994 '\n' => {
995 x += metrics.newline_advance();
996 }
997 _ => {
998 let y1 = y + line.height - metrics.ascender();
999 let scale = self.super_sampling_scale;
1000 let (glyph, advance) =
1001 build_glyph(&mut metrics, x, y1, i, c, prev, scale);
1002 self.glyphs.push(glyph);
1003 x += advance;
1004 }
1005 }
1006 prev = Some(c);
1007 }
1008 }
1009 line.y_offset = y;
1010 y += line.height + self.line_space();
1011 }
1012
1013 let size_x = if self.constraint.x.is_finite() {
1014 self.constraint.x
1015 } else {
1016 lines
1017 .iter()
1018 .map(|line| line.width)
1019 .max_by(f32::total_cmp)
1020 .unwrap_or_default()
1021 };
1022 let size_y = if self.constraint.y.is_finite() {
1023 self.constraint.y
1024 } else {
1025 let descender = if self.mask_char.is_some() || self.runs.is_empty() {
1026 GlyphMetrics {
1027 font: &mut self.font.data_ref(),
1028 size: **self.font_size,
1029 }
1030 .descender()
1031 } else if let Some(line) = self.lines.last() {
1032 (line.begin..line.end)
1033 .map(|i| {
1034 GlyphMetrics {
1035 font: &mut self.font_at(i).data_ref(),
1036 size: self.font_size_at(i),
1037 }
1038 .descender()
1039 })
1040 .min_by(f32::total_cmp)
1041 .unwrap_or_default()
1042 } else {
1043 0.0
1044 };
1045 total_height - descender
1047 };
1048 self.lines = lines;
1049 Vector2::new(size_x, size_y)
1050 }
1051}
1052
1053fn wrap<W, I>(mut wrapper: W, source: I)
1054where
1055 W: TextWrapper,
1056 I: Iterator<Item = (char, f32)>,
1057{
1058 for (character, advance) in source {
1059 wrapper.push(character, advance);
1060 }
1061 wrapper.finish();
1062}
1063
1064fn wrap_mask<W: TextWrapper>(mut wrapper: W, length: usize, mask_char: char, advance: f32) {
1065 for _ in 0..length {
1066 wrapper.push(mask_char, advance);
1067 }
1068 wrapper.finish();
1069}
1070
1071pub struct FormattedTextBuilder {
1072 font: FontResource,
1073 brush: Brush,
1074 constraint: Vector2<f32>,
1075 text: Vec<char>,
1076 vertical_alignment: VerticalAlignment,
1077 horizontal_alignment: HorizontalAlignment,
1078 wrap: WrapMode,
1079 mask_char: Option<char>,
1080 shadow: bool,
1081 shadow_brush: Brush,
1082 shadow_dilation: f32,
1083 shadow_offset: Vector2<f32>,
1084 font_size: StyledProperty<f32>,
1085 super_sampling_scaling: f32,
1086 runs: Vec<Run>,
1087 line_indent: f32,
1089 line_space: f32,
1091}
1092
1093impl FormattedTextBuilder {
1094 pub fn new(font: FontResource) -> FormattedTextBuilder {
1096 FormattedTextBuilder {
1097 font,
1098 text: Vec::default(),
1099 horizontal_alignment: HorizontalAlignment::Left,
1100 vertical_alignment: VerticalAlignment::Top,
1101 brush: Brush::Solid(Color::WHITE),
1102 constraint: Vector2::new(128.0, 128.0),
1103 wrap: WrapMode::NoWrap,
1104 mask_char: None,
1105 shadow: false,
1106 shadow_brush: Brush::Solid(Color::BLACK),
1107 shadow_dilation: 1.0,
1108 shadow_offset: Vector2::new(1.0, 1.0),
1109 font_size: 14.0f32.into(),
1110 super_sampling_scaling: 1.0,
1111 runs: Vec::default(),
1112 line_indent: 0.0,
1113 line_space: 0.0,
1114 }
1115 }
1116
1117 pub fn with_vertical_alignment(mut self, vertical_alignment: VerticalAlignment) -> Self {
1118 self.vertical_alignment = vertical_alignment;
1119 self
1120 }
1121
1122 pub fn with_wrap(mut self, wrap: WrapMode) -> Self {
1123 self.wrap = wrap;
1124 self
1125 }
1126
1127 pub fn with_horizontal_alignment(mut self, horizontal_alignment: HorizontalAlignment) -> Self {
1128 self.horizontal_alignment = horizontal_alignment;
1129 self
1130 }
1131
1132 pub fn with_text(mut self, text: String) -> Self {
1133 self.text = text.chars().collect();
1134 self
1135 }
1136
1137 pub fn with_chars(mut self, text: Vec<char>) -> Self {
1138 self.text = text;
1139 self
1140 }
1141
1142 pub fn with_font_size(mut self, font_size: StyledProperty<f32>) -> Self {
1143 self.font_size = font_size;
1144 self
1145 }
1146
1147 pub fn with_constraint(mut self, constraint: Vector2<f32>) -> Self {
1148 self.constraint = constraint;
1149 self
1150 }
1151
1152 pub fn with_brush(mut self, brush: Brush) -> Self {
1153 self.brush = brush;
1154 self
1155 }
1156
1157 pub fn with_mask_char(mut self, mask_char: Option<char>) -> Self {
1158 self.mask_char = mask_char;
1159 self
1160 }
1161
1162 pub fn with_shadow(mut self, shadow: bool) -> Self {
1164 self.shadow = shadow;
1165 self
1166 }
1167
1168 pub fn with_shadow_brush(mut self, brush: Brush) -> Self {
1170 self.shadow_brush = brush;
1171 self
1172 }
1173
1174 pub fn with_shadow_dilation(mut self, thickness: f32) -> Self {
1177 self.shadow_dilation = thickness;
1178 self
1179 }
1180
1181 pub fn with_shadow_offset(mut self, offset: Vector2<f32>) -> Self {
1183 self.shadow_offset = offset;
1184 self
1185 }
1186
1187 pub fn with_super_sampling_scaling(mut self, scaling: f32) -> Self {
1189 self.super_sampling_scaling = scaling;
1190 self
1191 }
1192
1193 pub fn with_run(mut self, run: Run) -> Self {
1197 self.runs.push(run);
1198 self
1199 }
1200
1201 pub fn with_runs<I: IntoIterator<Item = Run>>(mut self, runs: I) -> Self {
1205 self.runs.extend(runs);
1206 self
1207 }
1208
1209 pub fn with_line_indent(mut self, indent: f32) -> Self {
1214 self.line_indent = indent;
1215 self
1216 }
1217
1218 pub fn with_line_space(mut self, space: f32) -> Self {
1221 self.line_space = space;
1222 self
1223 }
1224
1225 pub fn build(self) -> FormattedText {
1226 FormattedText {
1227 text: self.text.into(),
1228 lines: Vec::new(),
1229 glyphs: Vec::new(),
1230 vertical_alignment: self.vertical_alignment.into(),
1231 horizontal_alignment: self.horizontal_alignment.into(),
1232 brush: self.brush.into(),
1233 constraint: self.constraint,
1234 wrap: self.wrap.into(),
1235 mask_char: self.mask_char.into(),
1236 super_sampling_scale: self.super_sampling_scaling,
1237 font_size: self.font_size.into(),
1238 shadow: self.shadow.into(),
1239 shadow_brush: self.shadow_brush.into(),
1240 font: self.font.into(),
1241 shadow_dilation: self.shadow_dilation.into(),
1242 shadow_offset: self.shadow_offset.into(),
1243 runs: self.runs.into(),
1244 line_indent: self.line_indent.into(),
1245 line_space: self.line_space.into(),
1246 }
1247 }
1248}