1use std::error::Error;
5use std::rc::Rc;
6
7use ferroui_pretext::{
8 DelegateTextMeasurerFactory, PrepareOptions, PretextLayout, RichInlineBreakMode, RichInlineItem,
9};
10use ferroui_pretext_layout::{CircleObstacle, ColumnFlowLayout, PreparedTextMetrics, RectObstacle};
11
12fn main() -> Result<(), Box<dyn Error>> {
13 let engine = PretextLayout::new(Rc::new(DelegateTextMeasurerFactory::new(
14 |text: &str, _: &str| text.chars().count() as f64 * 8.0,
15 )));
16 let prepared = engine.prepare_with_segments(
17 "Prepare this paragraph once. Reflow it through columns as the exclusion \
18 shape moves. Width changes reuse the prepared measurements, and only \
19 the visible line ranges need their text materialized. This is useful \
20 for editorial pages, canvas labels and virtualized cards.",
21 "16px Monospace",
22 PrepareOptions::default(),
23 )?;
24 let columns = [
25 RectObstacle {
26 x: 0.0,
27 y: 0.0,
28 width: 240.0,
29 height: 220.0,
30 },
31 RectObstacle {
32 x: 264.0,
33 y: 0.0,
34 width: 240.0,
35 height: 220.0,
36 },
37 ];
38 let rectangles = [RectObstacle {
39 x: 0.0,
40 y: 0.0,
41 width: 80.0,
42 height: 40.0,
43 }];
44
45 println!("Illustrative monospace geometry (8 units per Unicode scalar)");
46 println!("Prepared segments: {}", prepared.segments().len());
47 for width in [120.0, 180.0, 240.0] {
48 let metrics = PreparedTextMetrics::collect_wrap_metrics(&prepared, width, 20.0);
49 println!(
50 "Width {width:>3.0}: {} lines, height {:.0}, widest {:.0}",
51 metrics.line_count, metrics.height, metrics.max_line_width,
52 );
53 }
54
55 for circle_y in [70.0, 150.0] {
56 let circles = [CircleObstacle {
57 x: 150.0,
58 y: circle_y,
59 radius: 45.0,
60 }];
61 let lines = ColumnFlowLayout::layout_into_columns(
62 &prepared,
63 &columns,
64 &rectangles,
65 &circles,
66 20.0,
67 48.0,
68 )?;
69 println!(
70 "\nCircle centered at (150, {circle_y:.0}); {} positioned lines:",
71 lines.len()
72 );
73 for line in lines {
74 println!(
75 " x={:>3.0} y={:>3.0} w={:>3.0} {}",
76 line.x, line.y, line.width, line.text
77 );
78 }
79 }
80
81 let inline = engine.prepare_rich_inline(&[
82 RichInlineItem::new("Assigned to ", "16px Monospace"),
83 RichInlineItem::new("@maya", "16px Monospace")
84 .with_break_mode(RichInlineBreakMode::Never)
85 .with_extra_width(16.0),
86 RichInlineItem::new(" for the next editorial review.", "16px Monospace"),
87 ])?;
88 println!("\nRich inline flow with an atomic badge:");
89 PretextLayout::walk_rich_inline_line_ranges(&inline, 160.0, |range| {
90 let line = PretextLayout::materialize_rich_inline_line_range(&inline, &range);
91 print!(" width={:>3.0}", line.width);
92 for fragment in line.fragments {
93 print!(
94 " [item {} gap {:.0}: {}]",
95 fragment.item_index, fragment.gap_before, fragment.text
96 );
97 }
98 println!();
99 });
100 Ok(())
101}