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