cranpose_ui/widgets/flow.rs
1//! `FlowRow` and `FlowColumn`: children that wrap onto the next line.
2
3use cranpose_core::NodeId;
4use cranpose_ui_layout::Axis;
5
6use super::layout::{LayoutEnvironment, compose_layout};
7use crate::{composable, layout::policies::FlowMeasurePolicy, modifier::Modifier};
8
9/// The gaps of a [`FlowRow`] or a [`FlowColumn`].
10#[derive(Clone, Copy, Debug, Default, PartialEq)]
11pub struct FlowSpec {
12 /// Gap between adjacent children on the same line, in dp: horizontal in
13 /// a row, vertical in a column (Compose: the arrangement along the main
14 /// axis, `Arrangement.spacedBy(..)`).
15 pub main_axis_spacing: f32,
16 /// Gap between consecutive lines, in dp: between rows of a row, between
17 /// columns of a column (Compose: the arrangement across them).
18 pub cross_axis_spacing: f32,
19}
20
21impl FlowSpec {
22 /// Creates a spec with no gaps between children or between lines.
23 pub fn new() -> Self {
24 Self::default()
25 }
26
27 /// Sets the gap between adjacent children on one line, in logical pixels.
28 pub fn main_axis_spacing(mut self, spacing: f32) -> Self {
29 self.main_axis_spacing = spacing;
30 self
31 }
32
33 /// Sets the gap between consecutive lines, in logical pixels.
34 pub fn cross_axis_spacing(mut self, spacing: f32) -> Self {
35 self.cross_axis_spacing = spacing;
36 self
37 }
38}
39
40/// Places children across a row and starts a new row when the available width is full.
41/// The spec sets the space between children and between rows.
42///
43/// # Example
44///
45/// ```rust
46/// use cranpose_ui::{
47/// widgets::{FlowRow, FlowSpec},
48/// *,
49/// };
50///
51/// #[composable]
52/// fn Topics() {
53/// FlowRow(
54/// Modifier::empty().fill_max_width(),
55/// FlowSpec::new()
56/// .main_axis_spacing(8.0)
57/// .cross_axis_spacing(4.0),
58/// || {
59/// for label in ["Rust", "Compose", "Android"] {
60/// Text(label, Modifier::empty().padding(8.0), TextStyle::default());
61/// }
62/// },
63/// );
64/// }
65/// ```
66#[composable(no_skip)]
67pub fn FlowRow<F>(modifier: Modifier, spec: FlowSpec, content: F) -> NodeId
68where
69 F: FnMut() + 'static,
70{
71 flow_layout(modifier, Axis::Horizontal, spec, content)
72}
73
74/// Places children down a column and starts a new column when the
75/// available height is full — Compose's `FlowColumn`. The spec sets the
76/// space between children and between columns. In a right-to-left layout
77/// the first column is at the right.
78#[composable(no_skip)]
79pub fn FlowColumn<F>(modifier: Modifier, spec: FlowSpec, content: F) -> NodeId
80where
81 F: FnMut() + 'static,
82{
83 flow_layout(modifier, Axis::Vertical, spec, content)
84}
85
86fn flow_layout<F>(modifier: Modifier, axis: Axis, spec: FlowSpec, content: F) -> NodeId
87where
88 F: FnMut() + 'static,
89{
90 let environment = LayoutEnvironment::current();
91 let mut policy = FlowMeasurePolicy::new(axis, spec.main_axis_spacing, spec.cross_axis_spacing);
92 policy.layout_direction = environment.direction;
93 compose_layout(modifier, &policy, environment, content)
94}