⎇ da888af8336c498edd4fcff6d86d68dd685921ec
examples/custom_tree_owned_partial.rs
Historia
Quién tocó qué
crudo
1mod common {
2 pub mod image;
3 pub mod text;
4}
5use common::image::{image_measure_function, ImageContext};
6use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, LOREM_IPSUM};
7use taffy::{
8 compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout,
9 prelude::*, Cache, Layout, Style,
10};
11
12#[derive(Debug, Copy, Clone)]
13#[allow(dead_code)]
14enum NodeKind {
15 Flexbox,
16 Grid,
17 Text,
18 Image,
19}
20
21struct Node {
22 kind: NodeKind,
23 style: Style,
24 text_data: Option<TextContext>,
25 image_data: Option<ImageContext>,
26 cache: Cache,
27 layout: Layout,
28 children: Vec<Node>,
29}
30
31impl Default for Node {
32 fn default() -> Self {
33 Node {
34 kind: NodeKind::Flexbox,
35 style: Style::default(),
36 text_data: None,
37 image_data: None,
38 cache: Cache::new(),
39 layout: Layout::with_order(0),
40 children: Vec::new(),
41 }
42 }
43}
44
45#[allow(dead_code)]
46impl Node {
47 pub fn new_row(style: Style) -> Node {
48 Node {
49 kind: NodeKind::Flexbox,
50 style: Style { display: Display::Flex, flex_direction: FlexDirection::Row, ..style },
51 ..Node::default()
52 }
53 }
54 pub fn new_column(style: Style) -> Node {
55 Node {
56 kind: NodeKind::Flexbox,
57 style: Style { display: Display::Flex, flex_direction: FlexDirection::Column, ..style },
58 ..Node::default()
59 }
60 }
61 pub fn new_grid(style: Style) -> Node {
62 Node { kind: NodeKind::Grid, style: Style { display: Display::Grid, ..style }, ..Node::default() }
63 }
64 pub fn new_text(style: Style, text_data: TextContext) -> Node {
65 Node { kind: NodeKind::Text, style, text_data: Some(text_data), ..Node::default() }
66 }
67 pub fn new_image(style: Style, image_data: ImageContext) -> Node {
68 Node { kind: NodeKind::Image, style, image_data: Some(image_data), ..Node::default() }
69 }
70 pub fn append_child(&mut self, node: Node) {
71 self.children.push(node);
72 }
73
74 pub fn compute_layout(&mut self, available_space: Size<AvailableSpace>) {
75 compute_root_layout(self, NodeId::from(usize::MAX), available_space);
76 }
77
78 /// The methods on LayoutPartialTree need to be able to access:
79 ///
80 /// - The node being laid out
81 /// - Direct children of the node being laid out
82 ///
83 /// Each must have an ID. For children we simply use it's index. For the node itself
84 /// we use usize::MAX on the assumption that there will never be that many children.
85 fn node_from_id(&self, node_id: NodeId) -> &Node {
86 let idx = usize::from(node_id);
87 if idx == usize::MAX {
88 self
89 } else {
90 &self.children[idx]
91 }
92 }
93
94 fn node_from_id_mut(&mut self, node_id: NodeId) -> &mut Node {
95 let idx = usize::from(node_id);
96 if idx == usize::MAX {
97 self
98 } else {
99 &mut self.children[idx]
100 }
101 }
102}
103
104struct ChildIter(std::ops::Range<usize>);
105impl Iterator for ChildIter {
106 type Item = NodeId;
107 fn next(&mut self) -> Option<Self::Item> {
108 self.0.next().map(NodeId::from)
109 }
110}
111
112impl taffy::TraversePartialTree for Node {
113 type ChildIter<'a> = ChildIter;
114
115 fn child_ids(&self, _node_id: NodeId) -> Self::ChildIter<'_> {
116 ChildIter(0..self.children.len())
117 }
118
119 fn child_count(&self, _node_id: NodeId) -> usize {
120 self.children.len()
121 }
122
123 fn get_child_id(&self, _node_id: NodeId, index: usize) -> NodeId {
124 NodeId::from(index)
125 }
126}
127
128impl taffy::LayoutPartialTree for Node {
129 type CoreContainerStyle<'a> = &'a Style where
130 Self: 'a;
131
132 type CacheMut<'b> = &'b mut Cache where Self: 'b;
133
134 fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
135 &self.node_from_id(node_id).style
136 }
137
138 fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
139 self.node_from_id_mut(node_id).layout = *layout
140 }
141
142 fn get_cache_mut(&mut self, node_id: NodeId) -> &mut Cache {
143 &mut self.node_from_id_mut(node_id).cache
144 }
145
146 fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
147 compute_cached_layout(self, node_id, inputs, |parent, node_id, inputs| {
148 let node = parent.node_from_id_mut(node_id);
149 let font_metrics = FontMetrics { char_width: 10.0, char_height: 10.0 };
150
151 match node.kind {
152 NodeKind::Flexbox => compute_flexbox_layout(node, node_id, inputs),
153 NodeKind::Grid => compute_grid_layout(node, node_id, inputs),
154 NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
155 text_measure_function(
156 known_dimensions,
157 available_space,
158 node.text_data.as_ref().unwrap(),
159 &font_metrics,
160 )
161 }),
162 NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
163 image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
164 }),
165 }
166 })
167 }
168}
169
170impl taffy::LayoutFlexboxContainer for Node {
171 type FlexboxContainerStyle<'a> = &'a Style where
172 Self: 'a;
173
174 type FlexboxItemStyle<'a> = &'a Style where
175 Self: 'a;
176
177 fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
178 &self.node_from_id(node_id).style
179 }
180
181 fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
182 &self.node_from_id(child_node_id).style
183 }
184}
185
186impl taffy::LayoutGridContainer for Node {
187 type GridContainerStyle<'a> = &'a Style where
188 Self: 'a;
189
190 type GridItemStyle<'a> = &'a Style where
191 Self: 'a;
192
193 fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
194 &self.node_from_id(node_id).style
195 }
196
197 fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
198 &self.node_from_id(child_node_id).style
199 }
200}
201
202fn main() -> Result<(), taffy::TaffyError> {
203 let mut root = Node::new_column(Style::DEFAULT);
204
205 let text_node = Node::new_text(
206 Style::default(),
207 TextContext { text_content: LOREM_IPSUM.into(), writing_mode: WritingMode::Horizontal },
208 );
209 root.append_child(text_node);
210
211 let image_node = Node::new_image(Style::default(), ImageContext { width: 400.0, height: 300.0 });
212 root.append_child(image_node);
213
214 // Compute layout
215 root.compute_layout(Size::MAX_CONTENT);
216
217 Ok(())
218}