Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

34
vendor/taffy/examples/basic.rs vendored Normal file
View File

@@ -0,0 +1,34 @@
use taffy::prelude::*;
fn main() -> Result<(), taffy::TaffyError> {
let mut taffy: TaffyTree<()> = TaffyTree::new();
let child = taffy.new_leaf(Style {
size: Size { width: Dimension::Percent(0.5), height: Dimension::Auto },
..Default::default()
})?;
let node = taffy.new_with_children(
Style {
size: Size { width: Dimension::Length(100.0), height: Dimension::Length(100.0) },
justify_content: Some(JustifyContent::Center),
..Default::default()
},
&[child],
)?;
println!("Compute layout with 100x100 viewport:");
taffy.compute_layout(
node,
Size { height: AvailableSpace::Definite(100.0), width: AvailableSpace::Definite(100.0) },
)?;
println!("node: {:#?}", taffy.layout(node)?);
println!("child: {:#?}", taffy.layout(child)?);
println!("Compute layout with undefined (infinite) viewport:");
taffy.compute_layout(node, Size::MAX_CONTENT)?;
println!("node: {:#?}", taffy.layout(node)?);
println!("child: {:#?}", taffy.layout(child)?);
Ok(())
}

18
vendor/taffy/examples/common/image.rs vendored Normal file
View File

@@ -0,0 +1,18 @@
use taffy::geometry::Size;
pub struct ImageContext {
pub width: f32,
pub height: f32,
}
pub fn image_measure_function(
known_dimensions: taffy::geometry::Size<Option<f32>>,
image_context: &ImageContext,
) -> taffy::geometry::Size<f32> {
match (known_dimensions.width, known_dimensions.height) {
(Some(width), Some(height)) => Size { width, height },
(Some(width), None) => Size { width, height: (width / image_context.width) * image_context.height },
(None, Some(height)) => Size { width: (height / image_context.height) * image_context.width, height },
(None, None) => Size { width: image_context.width, height: image_context.height },
}
}

75
vendor/taffy/examples/common/text.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
pub 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.";
pub struct FontMetrics {
pub char_width: f32,
pub char_height: f32,
}
#[allow(dead_code)]
pub enum WritingMode {
Horizontal,
Vertical,
}
pub struct TextContext {
pub text_content: String,
pub writing_mode: WritingMode,
}
pub fn text_measure_function(
known_dimensions: taffy::geometry::Size<Option<f32>>,
available_space: taffy::geometry::Size<taffy::style::AvailableSpace>,
text_context: &TextContext,
font_metrics: &FontMetrics,
) -> taffy::geometry::Size<f32> {
use taffy::geometry::AbsoluteAxis;
use taffy::prelude::*;
let inline_axis = match text_context.writing_mode {
WritingMode::Horizontal => AbsoluteAxis::Horizontal,
WritingMode::Vertical => AbsoluteAxis::Vertical,
};
let block_axis = inline_axis.other_axis();
let words: Vec<&str> = text_context.text_content.split_whitespace().collect();
if words.is_empty() {
return Size::ZERO;
}
let min_line_length: usize = words.iter().map(|line| line.len()).max().unwrap_or(0);
let max_line_length: usize = words.iter().map(|line| line.len()).sum();
let inline_size =
known_dimensions.get_abs(inline_axis).unwrap_or_else(|| match available_space.get_abs(inline_axis) {
AvailableSpace::MinContent => min_line_length as f32 * font_metrics.char_width,
AvailableSpace::MaxContent => max_line_length as f32 * font_metrics.char_width,
AvailableSpace::Definite(inline_size) => inline_size
.min(max_line_length as f32 * font_metrics.char_width)
.max(min_line_length as f32 * font_metrics.char_width),
});
let block_size = known_dimensions.get_abs(block_axis).unwrap_or_else(|| {
let inline_line_length = (inline_size / font_metrics.char_width).floor() as usize;
let mut line_count = 1;
let mut current_line_length = 0;
for word in &words {
if current_line_length == 0 {
// first word
current_line_length = word.len();
} else if current_line_length + word.len() + 1 > inline_line_length {
// every word past the first needs to check for line length including the space between words
// note: a real implementation of this should handle whitespace characters other than ' '
// and do something more sophisticated for long words
line_count += 1;
current_line_length = word.len();
} else {
// add the word and a space
current_line_length += word.len() + 1;
};
}
(line_count as f32) * font_metrics.char_height
});
match text_context.writing_mode {
WritingMode::Horizontal => Size { width: inline_size, height: block_size },
WritingMode::Vertical => Size { width: block_size, height: inline_size },
}
}

View File

@@ -0,0 +1,256 @@
//! ## Example: Partial Tree with Directly Owned Children
//!
//! The following example demonstrate an implementation of Taffy's Partial trait and usage of the low-level compute APIs.
//! This example uses directly owned children with NodeId's being index's into vec on parent node.
//! Since an iterator created from a node can't access grandchildren, we are limited to only implement `TraversePartialTree`.
//! See the [`crate::tree::traits`] module for more details about the low-level traits.
mod common {
pub mod image;
pub mod text;
}
use common::image::{image_measure_function, ImageContext};
use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, LOREM_IPSUM};
use taffy::{
compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout,
prelude::*, Cache, CacheTree, Layout, Style,
};
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
enum NodeKind {
Flexbox,
Grid,
Text,
Image,
}
struct Node {
kind: NodeKind,
style: Style,
text_data: Option<TextContext>,
image_data: Option<ImageContext>,
cache: Cache,
layout: Layout,
children: Vec<Node>,
}
impl Default for Node {
fn default() -> Self {
Node {
kind: NodeKind::Flexbox,
style: Style::default(),
text_data: None,
image_data: None,
cache: Cache::new(),
layout: Layout::with_order(0),
children: Vec::new(),
}
}
}
#[allow(dead_code)]
impl Node {
pub fn new_row(style: Style) -> Node {
Node {
kind: NodeKind::Flexbox,
style: Style { display: Display::Flex, flex_direction: FlexDirection::Row, ..style },
..Node::default()
}
}
pub fn new_column(style: Style) -> Node {
Node {
kind: NodeKind::Flexbox,
style: Style { display: Display::Flex, flex_direction: FlexDirection::Column, ..style },
..Node::default()
}
}
pub fn new_grid(style: Style) -> Node {
Node { kind: NodeKind::Grid, style: Style { display: Display::Grid, ..style }, ..Node::default() }
}
pub fn new_text(style: Style, text_data: TextContext) -> Node {
Node { kind: NodeKind::Text, style, text_data: Some(text_data), ..Node::default() }
}
pub fn new_image(style: Style, image_data: ImageContext) -> Node {
Node { kind: NodeKind::Image, style, image_data: Some(image_data), ..Node::default() }
}
pub fn append_child(&mut self, node: Node) {
self.children.push(node);
}
pub fn compute_layout(&mut self, available_space: Size<AvailableSpace>) {
compute_root_layout(self, NodeId::from(usize::MAX), available_space);
}
/// The methods on LayoutPartialTree need to be able to access:
///
/// - The node being laid out
/// - Direct children of the node being laid out
///
/// Each must have an ID. For children we simply use it's index. For the node itself
/// we use usize::MAX on the assumption that there will never be that many children.
fn node_from_id(&self, node_id: NodeId) -> &Node {
let idx = usize::from(node_id);
if idx == usize::MAX {
self
} else {
&self.children[idx]
}
}
fn node_from_id_mut(&mut self, node_id: NodeId) -> &mut Node {
let idx = usize::from(node_id);
if idx == usize::MAX {
self
} else {
&mut self.children[idx]
}
}
}
struct ChildIter(std::ops::Range<usize>);
impl Iterator for ChildIter {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(NodeId::from)
}
}
impl taffy::TraversePartialTree for Node {
type ChildIter<'a> = ChildIter;
fn child_ids(&self, _node_id: NodeId) -> Self::ChildIter<'_> {
ChildIter(0..self.children.len())
}
fn child_count(&self, _node_id: NodeId) -> usize {
self.children.len()
}
fn get_child_id(&self, _node_id: NodeId, index: usize) -> NodeId {
NodeId::from(index)
}
}
impl taffy::LayoutPartialTree for Node {
type CoreContainerStyle<'a>
= &'a Style
where
Self: 'a;
fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
&self.node_from_id(node_id).style
}
fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
self.node_from_id_mut(node_id).layout = *layout
}
fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
compute_cached_layout(self, node_id, inputs, |parent, node_id, inputs| {
let node = parent.node_from_id_mut(node_id);
let font_metrics = FontMetrics { char_width: 10.0, char_height: 10.0 };
match node.kind {
NodeKind::Flexbox => compute_flexbox_layout(node, node_id, inputs),
NodeKind::Grid => compute_grid_layout(node, node_id, inputs),
NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
text_measure_function(
known_dimensions,
available_space,
node.text_data.as_ref().unwrap(),
&font_metrics,
)
}),
NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
}),
}
})
}
}
impl CacheTree for Node {
fn cache_get(
&self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
run_mode: taffy::RunMode,
) -> Option<taffy::LayoutOutput> {
self.node_from_id(node_id).cache.get(known_dimensions, available_space, run_mode)
}
fn cache_store(
&mut self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
run_mode: taffy::RunMode,
layout_output: taffy::LayoutOutput,
) {
self.node_from_id_mut(node_id).cache.store(known_dimensions, available_space, run_mode, layout_output)
}
fn cache_clear(&mut self, node_id: NodeId) {
self.node_from_id_mut(node_id).cache.clear()
}
}
impl taffy::LayoutFlexboxContainer for Node {
type FlexboxContainerStyle<'a>
= &'a Style
where
Self: 'a;
type FlexboxItemStyle<'a>
= &'a Style
where
Self: 'a;
fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
&self.node_from_id(node_id).style
}
fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
&self.node_from_id(child_node_id).style
}
}
impl taffy::LayoutGridContainer for Node {
type GridContainerStyle<'a>
= &'a Style
where
Self: 'a;
type GridItemStyle<'a>
= &'a Style
where
Self: 'a;
fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
&self.node_from_id(node_id).style
}
fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
&self.node_from_id(child_node_id).style
}
}
fn main() -> Result<(), taffy::TaffyError> {
let mut root = Node::new_column(Style::DEFAULT);
let text_node = Node::new_text(
Style::default(),
TextContext { text_content: LOREM_IPSUM.into(), writing_mode: WritingMode::Horizontal },
);
root.append_child(text_node);
let image_node = Node::new_image(Style::default(), ImageContext { width: 400.0, height: 300.0 });
root.append_child(image_node);
// Compute layout
root.compute_layout(Size::MAX_CONTENT);
Ok(())
}

View File

@@ -0,0 +1,279 @@
mod common {
pub mod image;
pub mod text;
}
use common::image::{image_measure_function, ImageContext};
use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, LOREM_IPSUM};
use taffy::tree::Cache;
use taffy::util::print_tree;
use taffy::{
compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout,
prelude::*, round_layout, CacheTree,
};
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
enum NodeKind {
Flexbox,
Grid,
Text,
Image,
}
struct Node {
kind: NodeKind,
style: Style,
text_data: Option<TextContext>,
image_data: Option<ImageContext>,
cache: Cache,
unrounded_layout: Layout,
final_layout: Layout,
children: Vec<Node>,
}
impl Default for Node {
fn default() -> Self {
Node {
kind: NodeKind::Flexbox,
style: Style::default(),
text_data: None,
image_data: None,
cache: Cache::new(),
unrounded_layout: Layout::with_order(0),
final_layout: Layout::with_order(0),
children: Vec::new(),
}
}
}
#[allow(dead_code)]
impl Node {
pub fn new_row(style: Style) -> Node {
Node {
kind: NodeKind::Flexbox,
style: Style { display: Display::Flex, flex_direction: FlexDirection::Row, ..style },
..Node::default()
}
}
pub fn new_column(style: Style) -> Node {
Node {
kind: NodeKind::Flexbox,
style: Style { display: Display::Flex, flex_direction: FlexDirection::Column, ..style },
..Node::default()
}
}
pub fn new_grid(style: Style) -> Node {
Node { kind: NodeKind::Grid, style: Style { display: Display::Grid, ..style }, ..Node::default() }
}
pub fn new_text(style: Style, text_data: TextContext) -> Node {
Node { kind: NodeKind::Text, style, text_data: Some(text_data), ..Node::default() }
}
pub fn new_image(style: Style, image_data: ImageContext) -> Node {
Node { kind: NodeKind::Image, style, image_data: Some(image_data), ..Node::default() }
}
pub fn append_child(&mut self, node: Node) {
self.children.push(node);
}
unsafe fn as_id(&self) -> NodeId {
NodeId::from(self as *const Node as usize)
}
pub fn compute_layout(&mut self, available_space: Size<AvailableSpace>, use_rounding: bool) {
let root_node_id = unsafe { self.as_id() };
compute_root_layout(&mut StatelessLayoutTree, root_node_id, available_space);
if use_rounding {
round_layout(&mut StatelessLayoutTree, root_node_id)
}
}
pub fn print_tree(&mut self) {
print_tree(&StatelessLayoutTree, unsafe { self.as_id() });
}
}
struct ChildIter<'a>(std::slice::Iter<'a, Node>);
impl Iterator for ChildIter<'_> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|c| NodeId::from(c as *const Node as usize))
}
}
#[inline(always)]
unsafe fn node_from_id<'a>(node_id: NodeId) -> &'a Node {
&*(usize::from(node_id) as *const Node)
}
#[inline(always)]
unsafe fn node_from_id_mut<'a>(node_id: NodeId) -> &'a mut Node {
&mut *(usize::from(node_id) as *mut Node)
}
struct StatelessLayoutTree;
impl TraversePartialTree for StatelessLayoutTree {
type ChildIter<'a> = ChildIter<'a>;
fn child_ids(&self, node_id: NodeId) -> Self::ChildIter<'_> {
unsafe { ChildIter(node_from_id(node_id).children.iter()) }
}
fn child_count(&self, node_id: NodeId) -> usize {
unsafe { node_from_id(node_id).children.len() }
}
fn get_child_id(&self, node_id: NodeId, index: usize) -> NodeId {
unsafe { node_from_id(node_id).children[index].as_id() }
}
}
impl TraverseTree for StatelessLayoutTree {}
impl LayoutPartialTree for StatelessLayoutTree {
type CoreContainerStyle<'a>
= &'a Style
where
Self: 'a;
fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
unsafe { &node_from_id(node_id).style }
}
fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
unsafe { node_from_id_mut(node_id).unrounded_layout = *layout };
}
fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
let node = unsafe { node_from_id_mut(node_id) };
let font_metrics = FontMetrics { char_width: 10.0, char_height: 10.0 };
match node.kind {
NodeKind::Flexbox => compute_flexbox_layout(tree, node_id, inputs),
NodeKind::Grid => compute_grid_layout(tree, node_id, inputs),
NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
text_measure_function(
known_dimensions,
available_space,
node.text_data.as_ref().unwrap(),
&font_metrics,
)
}),
NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
}),
}
})
}
}
impl CacheTree for StatelessLayoutTree {
fn cache_get(
&self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
run_mode: taffy::RunMode,
) -> Option<taffy::LayoutOutput> {
unsafe { node_from_id(node_id) }.cache.get(known_dimensions, available_space, run_mode)
}
fn cache_store(
&mut self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
run_mode: taffy::RunMode,
layout_output: taffy::LayoutOutput,
) {
unsafe { node_from_id_mut(node_id) }.cache.store(known_dimensions, available_space, run_mode, layout_output)
}
fn cache_clear(&mut self, node_id: NodeId) {
unsafe { node_from_id_mut(node_id) }.cache.clear()
}
}
impl taffy::LayoutFlexboxContainer for StatelessLayoutTree {
type FlexboxContainerStyle<'a>
= &'a Style
where
Self: 'a;
type FlexboxItemStyle<'a>
= &'a Style
where
Self: 'a;
fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
unsafe { &node_from_id(node_id).style }
}
fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
unsafe { &node_from_id(child_node_id).style }
}
}
impl taffy::LayoutGridContainer for StatelessLayoutTree {
type GridContainerStyle<'a>
= &'a Style
where
Self: 'a;
type GridItemStyle<'a>
= &'a Style
where
Self: 'a;
fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
unsafe { &node_from_id(node_id).style }
}
fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
unsafe { &node_from_id(child_node_id).style }
}
}
impl RoundTree for StatelessLayoutTree {
fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout {
unsafe { &node_from_id_mut(node_id).unrounded_layout }
}
fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout) {
unsafe { node_from_id_mut(node_id).final_layout = *layout }
}
}
impl PrintTree for StatelessLayoutTree {
fn get_debug_label(&self, node_id: NodeId) -> &'static str {
match unsafe { node_from_id(node_id).kind } {
NodeKind::Flexbox => "FLEX",
NodeKind::Grid => "GRID",
NodeKind::Text => "TEXT",
NodeKind::Image => "IMAGE",
}
}
fn get_final_layout(&self, node_id: NodeId) -> &Layout {
unsafe { &node_from_id(node_id).final_layout }
}
}
fn main() -> Result<(), taffy::TaffyError> {
let mut root = Node::new_column(Style::DEFAULT);
let text_node = Node::new_text(
Style::default(),
TextContext { text_content: LOREM_IPSUM.into(), writing_mode: WritingMode::Horizontal },
);
root.append_child(text_node);
let image_node = Node::new_image(Style::default(), ImageContext { width: 400.0, height: 300.0 });
root.append_child(image_node);
// Compute layout and print result
root.compute_layout(Size::MAX_CONTENT, true);
root.print_tree();
Ok(())
}

293
vendor/taffy/examples/custom_tree_vec.rs vendored Normal file
View File

@@ -0,0 +1,293 @@
mod common {
pub mod image;
pub mod text;
}
use common::image::{image_measure_function, ImageContext};
use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, LOREM_IPSUM};
use taffy::util::print_tree;
use taffy::{
compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout,
prelude::*, round_layout, Cache, CacheTree,
};
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
enum NodeKind {
Flexbox,
Grid,
Text,
Image,
}
struct Node {
kind: NodeKind,
style: Style,
text_data: Option<TextContext>,
image_data: Option<ImageContext>,
cache: Cache,
unrounded_layout: Layout,
final_layout: Layout,
children: Vec<usize>,
}
impl Default for Node {
fn default() -> Self {
Node {
kind: NodeKind::Flexbox,
style: Style::default(),
text_data: None,
image_data: None,
cache: Cache::new(),
unrounded_layout: Layout::with_order(0),
final_layout: Layout::with_order(0),
children: Vec::new(),
}
}
}
#[allow(dead_code)]
impl Node {
pub fn new_row(style: Style) -> Node {
Node {
kind: NodeKind::Flexbox,
style: Style { display: Display::Flex, flex_direction: FlexDirection::Row, ..style },
..Node::default()
}
}
pub fn new_column(style: Style) -> Node {
Node {
kind: NodeKind::Flexbox,
style: Style { display: Display::Flex, flex_direction: FlexDirection::Column, ..style },
..Node::default()
}
}
pub fn new_grid(style: Style) -> Node {
Node { kind: NodeKind::Grid, style: Style { display: Display::Grid, ..style }, ..Node::default() }
}
pub fn new_text(style: Style, text_data: TextContext) -> Node {
Node { kind: NodeKind::Text, style, text_data: Some(text_data), ..Node::default() }
}
pub fn new_image(style: Style, image_data: ImageContext) -> Node {
Node { kind: NodeKind::Image, style, image_data: Some(image_data), ..Node::default() }
}
}
struct Tree {
nodes: Vec<Node>,
}
impl Tree {
pub fn new() -> Tree {
Tree { nodes: Vec::new() }
}
pub fn add_node(&mut self, node: Node) -> usize {
self.nodes.push(node);
self.nodes.len() - 1
}
pub fn append_child(&mut self, parent: usize, child: usize) {
self.nodes[parent].children.push(child);
}
#[inline(always)]
fn node_from_id(&self, node_id: NodeId) -> &Node {
&self.nodes[usize::from(node_id)]
}
#[inline(always)]
fn node_from_id_mut(&mut self, node_id: NodeId) -> &mut Node {
&mut self.nodes[usize::from(node_id)]
}
pub fn compute_layout(&mut self, root: usize, available_space: Size<AvailableSpace>, use_rounding: bool) {
compute_root_layout(self, NodeId::from(root), available_space);
if use_rounding {
round_layout(self, NodeId::from(root))
}
}
pub fn print_tree(&mut self, root: usize) {
print_tree(self, NodeId::from(root));
}
}
struct ChildIter<'a>(std::slice::Iter<'a, usize>);
impl Iterator for ChildIter<'_> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().copied().map(NodeId::from)
}
}
impl taffy::TraversePartialTree for Tree {
type ChildIter<'a> = ChildIter<'a>;
fn child_ids(&self, node_id: NodeId) -> Self::ChildIter<'_> {
ChildIter(self.node_from_id(node_id).children.iter())
}
fn child_count(&self, node_id: NodeId) -> usize {
self.node_from_id(node_id).children.len()
}
fn get_child_id(&self, node_id: NodeId, index: usize) -> NodeId {
NodeId::from(self.node_from_id(node_id).children[index])
}
}
impl taffy::TraverseTree for Tree {}
impl taffy::LayoutPartialTree for Tree {
type CoreContainerStyle<'a>
= &'a Style
where
Self: 'a;
fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
&self.node_from_id(node_id).style
}
fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
self.node_from_id_mut(node_id).unrounded_layout = *layout;
}
fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
let node = tree.node_from_id_mut(node_id);
let font_metrics = FontMetrics { char_width: 10.0, char_height: 10.0 };
match node.kind {
NodeKind::Flexbox => compute_flexbox_layout(tree, node_id, inputs),
NodeKind::Grid => compute_grid_layout(tree, node_id, inputs),
NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
text_measure_function(
known_dimensions,
available_space,
node.text_data.as_ref().unwrap(),
&font_metrics,
)
}),
NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
}),
}
})
}
}
impl CacheTree for Tree {
fn cache_get(
&self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
run_mode: taffy::RunMode,
) -> Option<taffy::LayoutOutput> {
self.node_from_id(node_id).cache.get(known_dimensions, available_space, run_mode)
}
fn cache_store(
&mut self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
run_mode: taffy::RunMode,
layout_output: taffy::LayoutOutput,
) {
self.node_from_id_mut(node_id).cache.store(known_dimensions, available_space, run_mode, layout_output)
}
fn cache_clear(&mut self, node_id: NodeId) {
self.node_from_id_mut(node_id).cache.clear()
}
}
impl taffy::LayoutFlexboxContainer for Tree {
type FlexboxContainerStyle<'a>
= &'a Style
where
Self: 'a;
type FlexboxItemStyle<'a>
= &'a Style
where
Self: 'a;
fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
&self.node_from_id(node_id).style
}
fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
&self.node_from_id(child_node_id).style
}
}
impl taffy::LayoutGridContainer for Tree {
type GridContainerStyle<'a>
= &'a Style
where
Self: 'a;
type GridItemStyle<'a>
= &'a Style
where
Self: 'a;
fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
&self.node_from_id(node_id).style
}
fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
&self.node_from_id(child_node_id).style
}
}
impl taffy::RoundTree for Tree {
fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout {
&self.node_from_id(node_id).unrounded_layout
}
fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout) {
self.node_from_id_mut(node_id).final_layout = *layout;
}
}
impl taffy::PrintTree for Tree {
fn get_debug_label(&self, node_id: NodeId) -> &'static str {
match self.node_from_id(node_id).kind {
NodeKind::Flexbox => "FLEX",
NodeKind::Grid => "GRID",
NodeKind::Text => "TEXT",
NodeKind::Image => "IMAGE",
}
}
fn get_final_layout(&self, node_id: NodeId) -> &Layout {
&self.node_from_id(node_id).final_layout
}
}
fn main() -> Result<(), taffy::TaffyError> {
let mut tree = Tree::new();
let root = Node::new_column(Style::DEFAULT);
let root_id = tree.add_node(root);
let text_node = Node::new_text(
Style::default(),
TextContext { text_content: LOREM_IPSUM.into(), writing_mode: WritingMode::Horizontal },
);
let text_node_id = tree.add_node(text_node);
tree.append_child(root_id, text_node_id);
let image_node = Node::new_image(Style::default(), ImageContext { width: 400.0, height: 300.0 });
let image_node_id = tree.add_node(image_node);
tree.append_child(root_id, image_node_id);
// Compute layout and print result
tree.compute_layout(root_id, Size::MAX_CONTENT, true);
tree.print_tree(root_id);
Ok(())
}

24
vendor/taffy/examples/flexbox_gap.rs vendored Normal file
View File

@@ -0,0 +1,24 @@
use taffy::prelude::*;
// Creates three 20px x 20px children, evenly spaced 10px apart from each other
// Thus the container is 80px x 20px.
fn main() -> Result<(), taffy::TaffyError> {
let mut taffy: TaffyTree<()> = TaffyTree::new();
let child_style = Style { size: Size { width: length(20.0), height: length(20.0) }, ..Default::default() };
let child0 = taffy.new_leaf(child_style.clone())?;
let child1 = taffy.new_leaf(child_style.clone())?;
let child2 = taffy.new_leaf(child_style.clone())?;
let root = taffy.new_with_children(
Style { gap: Size { width: length(10.0), height: zero() }, ..Default::default() },
&[child0, child1, child2],
)?;
// Compute layout and print result
taffy.compute_layout(root, Size::MAX_CONTENT)?;
taffy.print_tree(root);
Ok(())
}

View File

@@ -0,0 +1,48 @@
// This creates a so-called "holy grail" layout using the CSS Grid layout algorithm
// See: https://en.wikipedia.org/wiki/Holy_grail_(web_design)
// NOTE: This example requires the `grid` feature flag to be enabled.
#[cfg(not(feature = "grid"))]
fn main() {
println!("Error: this example requires the 'grid' feature to be enabled");
println!("Try:");
println!(" cargo run --example grid_holy_grail --features grid")
}
#[cfg(feature = "grid")]
fn default<T: Default>() -> T {
Default::default()
}
#[cfg(feature = "grid")]
fn main() -> Result<(), taffy::TaffyError> {
use taffy::prelude::*;
let mut taffy: TaffyTree<()> = TaffyTree::new();
// Setup the grid
let root_style = Style {
display: Display::Grid,
size: Size { width: length(800.0), height: length(600.0) },
grid_template_columns: vec![length(250.0), fr(1.0), length(250.0)],
grid_template_rows: vec![length(150.0), fr(1.0), length(150.0)],
..default()
};
// Define the child nodes
let header = taffy.new_leaf(Style { grid_row: line(1), grid_column: span(3), ..default() })?;
let left_sidebar = taffy.new_leaf(Style { grid_row: line(2), grid_column: line(1), ..default() })?;
let content_area = taffy.new_leaf(Style { grid_row: line(2), grid_column: line(2), ..default() })?;
let right_sidebar = taffy.new_leaf(Style { grid_row: line(2), grid_column: line(3), ..default() })?;
let footer = taffy.new_leaf(Style { grid_row: line(3), grid_column: span(3), ..default() })?;
// Create the container with the children
let root = taffy.new_with_children(root_style, &[header, left_sidebar, content_area, right_sidebar, footer])?;
// Compute layout and print result
taffy.compute_layout(root, Size { width: length(800.0), height: length(600.0) })?;
taffy.print_tree(root);
Ok(())
}

69
vendor/taffy/examples/measure.rs vendored Normal file
View File

@@ -0,0 +1,69 @@
mod common {
pub mod image;
pub mod text;
}
use common::image::{image_measure_function, ImageContext};
use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, LOREM_IPSUM};
use taffy::prelude::*;
enum NodeContext {
Text(TextContext),
Image(ImageContext),
}
fn measure_function(
known_dimensions: taffy::geometry::Size<Option<f32>>,
available_space: taffy::geometry::Size<taffy::style::AvailableSpace>,
node_context: Option<&mut NodeContext>,
font_metrics: &FontMetrics,
) -> Size<f32> {
if let Size { width: Some(width), height: Some(height) } = known_dimensions {
return Size { width, height };
}
match node_context {
None => Size::ZERO,
Some(NodeContext::Text(text_context)) => {
text_measure_function(known_dimensions, available_space, &*text_context, font_metrics)
}
Some(NodeContext::Image(image_context)) => image_measure_function(known_dimensions, image_context),
}
}
fn main() -> Result<(), taffy::TaffyError> {
let mut taffy: TaffyTree<NodeContext> = TaffyTree::new();
let font_metrics = FontMetrics { char_width: 10.0, char_height: 10.0 };
let text_node = taffy.new_leaf_with_context(
Style::default(),
NodeContext::Text(TextContext { text_content: LOREM_IPSUM.into(), writing_mode: WritingMode::Horizontal }),
)?;
let image_node = taffy
.new_leaf_with_context(Style::default(), NodeContext::Image(ImageContext { width: 400.0, height: 300.0 }))?;
let root = taffy.new_with_children(
Style {
display: Display::Flex,
flex_direction: FlexDirection::Column,
size: Size { width: length(200.0), height: auto() },
..Default::default()
},
&[text_node, image_node],
)?;
// Compute layout and print result
taffy.compute_layout_with_measure(
root,
Size::MAX_CONTENT,
// Note: this closure is a FnMut closure and can be used to borrow external context for the duration of layout
// For example, you may wish to borrow a global font registry and pass it into your text measuring function
|known_dimensions, available_space, _node_id, node_context, _style| {
measure_function(known_dimensions, available_space, node_context, &font_metrics)
},
)?;
taffy.print_tree(root);
Ok(())
}

55
vendor/taffy/examples/nested.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
use taffy::prelude::*;
fn main() -> Result<(), taffy::TaffyError> {
let mut taffy: TaffyTree<()> = TaffyTree::new();
// left
let child_t1 = taffy.new_leaf(Style {
size: Size { width: Dimension::Length(5.0), height: Dimension::Length(5.0) },
..Default::default()
})?;
let div1 = taffy.new_with_children(
Style {
size: Size { width: Dimension::Percent(0.5), height: Dimension::Percent(1.0) },
// justify_content: JustifyContent::Center,
..Default::default()
},
&[child_t1],
)?;
// right
let child_t2 = taffy.new_leaf(Style {
size: Size { width: Dimension::Length(5.0), height: Dimension::Length(5.0) },
..Default::default()
})?;
let div2 = taffy.new_with_children(
Style {
size: Size { width: Dimension::Percent(0.5), height: Dimension::Percent(1.0) },
// justify_content: JustifyContent::Center,
..Default::default()
},
&[child_t2],
)?;
let container = taffy.new_with_children(
Style { size: Size { width: Dimension::Percent(1.0), height: Dimension::Percent(1.0) }, ..Default::default() },
&[div1, div2],
)?;
taffy.compute_layout(
container,
Size { height: AvailableSpace::Definite(100.0), width: AvailableSpace::Definite(100.0) },
)?;
println!("node: {:#?}", taffy.layout(container)?);
println!("div1: {:#?}", taffy.layout(div1)?);
println!("div2: {:#?}", taffy.layout(div2)?);
println!("child1: {:#?}", taffy.layout(child_t1)?);
println!("child2: {:#?}", taffy.layout(child_t2)?);
Ok(())
}