cosmic/widget/flex_row/
layout.rs
1use crate::{Element, Renderer};
5use iced_core::layout::{Limits, Node};
6use iced_core::widget::Tree;
7use iced_core::{Length, Padding, Point, Size};
8use taffy::geometry::Rect;
9use taffy::style::{AlignItems, Dimension, Display, Style};
10use taffy::style_helpers::length;
11use taffy::{AlignContent, TaffyTree};
12
13#[allow(clippy::too_many_arguments)]
14#[allow(clippy::too_many_lines)]
15pub fn resolve<Message>(
16 renderer: &Renderer,
17 limits: &Limits,
18 items: &[Element<'_, Message>],
19 padding: Padding,
20 column_spacing: f32,
21 row_spacing: f32,
22 min_item_width: Option<f32>,
23 justify_items: Option<AlignItems>,
24 align_items: Option<AlignItems>,
25 justify_content: Option<AlignContent>,
26 tree: &mut [Tree],
27) -> Node {
28 let max_size = limits.max();
29
30 let mut leafs = Vec::with_capacity(items.len());
31 let mut nodes = Vec::with_capacity(items.len());
32
33 let mut taffy_tree = TaffyTree::<()>::with_capacity(items.len() + 1);
34
35 let style = taffy::Style {
36 display: Display::Flex,
37 flex_direction: taffy::FlexDirection::Row,
38 flex_wrap: taffy::FlexWrap::Wrap,
39
40 gap: taffy::geometry::Size {
41 width: length(column_spacing),
42 height: length(row_spacing),
43 },
44
45 min_size: taffy::geometry::Size {
46 width: length(max_size.width),
47 height: Dimension::Auto,
48 },
49
50 align_items,
51 justify_items,
52 justify_content,
53
54 padding: Rect {
55 left: length(padding.left),
56 right: length(padding.right),
57 top: length(padding.top),
58 bottom: length(padding.bottom),
59 },
60
61 ..taffy::Style::default()
62 };
63
64 for (child, tree) in items.iter().zip(tree.iter_mut()) {
65 let child_widget = child.as_widget();
66 let child_node = child_widget.layout(tree, renderer, limits);
67 let size = child_node.size();
68
69 nodes.push(child_node);
70
71 let c_size = child_widget.size();
72 let (width, flex_grow, justify_self) = match c_size.width {
73 Length::Fill | Length::FillPortion(_) => {
74 (Dimension::Auto, 1.0, Some(AlignItems::Stretch))
75 }
76 _ => (length(size.width), 0.0, None),
77 };
78
79 let child_style = Style {
80 flex_grow,
81
82 min_size: taffy::geometry::Size {
83 width: match min_item_width {
84 Some(width) => length(size.width.min(width)),
85 None => Dimension::Auto,
86 },
87 height: Dimension::Auto,
88 },
89
90 size: taffy::geometry::Size {
91 width,
92 height: match c_size.height {
93 Length::Fill | Length::FillPortion(_) => Dimension::Auto,
94 _ => length(size.height),
95 },
96 },
97
98 justify_self,
99
100 ..Style::default()
101 };
102
103 leafs.push(match taffy_tree.new_leaf(child_style) {
104 Ok(leaf) => leaf,
105 Err(why) => {
106 tracing::error!(?why, "failed to add child element to flex row");
107 continue;
108 }
109 });
110 }
111
112 let root = match taffy_tree.new_with_children(style, &leafs) {
113 Ok(root) => root,
114 Err(why) => {
115 tracing::error!(?why, "flex row style is invalid");
116 return Node::new(Size::ZERO);
117 }
118 };
119
120 if let Err(why) = taffy_tree.compute_layout(
121 root,
122 taffy::geometry::Size {
123 width: length(max_size.width),
124 height: length(max_size.height),
125 },
126 ) {
127 tracing::error!(?why, "flex row layout invalid");
128 return Node::new(Size::ZERO);
129 }
130
131 let flex_layout = match taffy_tree.layout(root) {
132 Ok(layout) => layout,
133 Err(why) => {
134 tracing::error!(?why, "cannot get flex row layout");
135 return Node::new(Size::ZERO);
136 }
137 };
138
139 leafs
140 .into_iter()
141 .zip(items.iter())
142 .zip(nodes.iter_mut())
143 .zip(tree)
144 .for_each(|(((leaf, child), node), tree)| {
145 let Ok(leaf_layout) = taffy_tree.layout(leaf) else {
146 return;
147 };
148
149 let child_widget = child.as_widget();
150 let c_size = child_widget.size();
151 match c_size.width {
152 Length::Fill | Length::FillPortion(_) => {
153 *node =
154 child_widget.layout(tree, renderer, &limits.width(leaf_layout.size.width));
155 }
156 _ => (),
157 }
158
159 *node = node.clone().move_to(Point {
160 x: leaf_layout.location.x,
161 y: leaf_layout.location.y,
162 });
163 });
164
165 let size = Size {
166 width: flex_layout.content_size.width,
167 height: flex_layout.content_size.height,
168 };
169
170 Node::with_children(size, nodes)
171}