gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1111HTML 1039Markdown 12TOML 94524 Sutichaykuna

⎇ 1ad9fc1134ff7eb5d35a0d497fab74ce3e1616cb examples/cosmic_text/src/main.rs Rust · 117 siq'ikuna · 4.4 KB Ñawpa willay Pi imata llamkarqan ch'uya

Move cosmic-text example to it's own crate (#754) 1ad9fc113 · Nico Burns ·

1mod image;
2use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping};
3use image::{image_measure_function, ImageContext};
4use taffy::prelude::*;
5
6pub const LOREM_IPSUM : &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
7
8struct CosmicTextContext {
9    buffer: cosmic_text::Buffer,
10}
11
12impl CosmicTextContext {
13    fn new(metrics: Metrics, text: &str, attrs: Attrs, font_system: &mut FontSystem) -> Self {
14        let mut buffer = Buffer::new_empty(metrics);
15        buffer.set_size(font_system, None, None);
16        buffer.set_text(font_system, text, attrs, Shaping::Advanced);
17        Self { buffer }
18    }
19
20    fn measure(
21        &mut self,
22        known_dimensions: taffy::Size<Option<f32>>,
23        available_space: taffy::Size<taffy::AvailableSpace>,
24        font_system: &mut FontSystem,
25    ) -> taffy::Size<f32> {
26        // Set width constraint
27        let width_constraint = known_dimensions.width.or(match available_space.width {
28            AvailableSpace::MinContent => Some(0.0),
29            AvailableSpace::MaxContent => None,
30            AvailableSpace::Definite(width) => Some(width),
31        });
32        self.buffer.set_size(font_system, width_constraint, None);
33
34        // Compute layout
35        self.buffer.shape_until_scroll(font_system, false);
36
37        // Determine measured size of text
38        let (width, total_lines) = self
39            .buffer
40            .layout_runs()
41            .fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
42        let height = total_lines as f32 * self.buffer.metrics().line_height;
43
44        taffy::Size { width, height }
45    }
46}
47
48enum NodeContext {
49    Text(CosmicTextContext),
50    Image(ImageContext),
51}
52
53impl NodeContext {
54    /// Constructor for a text node context
55    fn text(metrics: Metrics, text: &str, attrs: Attrs, font_system: &mut FontSystem) -> Self {
56        NodeContext::Text(CosmicTextContext::new(metrics, text, attrs, font_system))
57    }
58
59    /// Constructor for an image node context
60    fn image(width: f32, height: f32) -> Self {
61        NodeContext::Image(ImageContext { width, height })
62    }
63}
64
65fn measure_function(
66    known_dimensions: taffy::Size<Option<f32>>,
67    available_space: taffy::Size<taffy::AvailableSpace>,
68    node_context: Option<&mut NodeContext>,
69    font_system: &mut FontSystem,
70) -> Size<f32> {
71    if let Size { width: Some(width), height: Some(height) } = known_dimensions {
72        return Size { width, height };
73    }
74
75    match node_context {
76        None => Size::ZERO,
77        Some(NodeContext::Text(text_context)) => text_context.measure(known_dimensions, available_space, font_system),
78        Some(NodeContext::Image(image_context)) => image_measure_function(known_dimensions, image_context),
79    }
80}
81
82fn main() -> Result<(), taffy::TaffyError> {
83    let metrics = Metrics { font_size: 14.0, line_height: 16.0 };
84    let mut font_system = FontSystem::new();
85    let mut taffy: TaffyTree<NodeContext> = TaffyTree::new();
86
87    let text_node = taffy.new_leaf_with_context(
88        Style::default(),
89        NodeContext::text(metrics, LOREM_IPSUM, Attrs::new(), &mut font_system),
90    )?;
91
92    let image_node = taffy.new_leaf_with_context(Style::default(), NodeContext::image(400.0, 300.0))?;
93
94    let root = taffy.new_with_children(
95        Style {
96            display: Display::Flex,
97            flex_direction: FlexDirection::Column,
98            size: Size { width: length(200.0), height: auto() },
99            ..Default::default()
100        },
101        &[text_node, image_node],
102    )?;
103
104    // Compute layout and print result
105    taffy.compute_layout_with_measure(
106        root,
107        Size::MAX_CONTENT,
108        // Note: this closure is a FnMut closure and can be used to borrow external context for the duration of layout
109        // For example, you may wish to borrow a global font registry and pass it into your text measuring function
110        |known_dimensions, available_space, _node_id, node_context, _style| {
111            measure_function(known_dimensions, available_space, node_context, &mut font_system)
112        },
113    )?;
114    taffy.print_tree(root);
115
116    Ok(())
117}