Skip to main content

cranpose_ui/widgets/
row.rs

1//! Row widget implementation
2
3use cranpose_core::NodeId;
4use cranpose_ui_layout::{LinearArrangement, VerticalAlignment};
5
6use super::layout::{LayoutEnvironment, compose_layout};
7use crate::{composable, layout::policies::FlexMeasurePolicy, modifier::Modifier};
8
9/// Specification for Row layout behavior.
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub struct RowSpec {
12    /// How children are spaced along the horizontal axis. Defaults to `Start`.
13    pub horizontal_arrangement: LinearArrangement,
14    /// How children align on the vertical axis. Defaults to `Top`.
15    pub vertical_alignment: VerticalAlignment,
16}
17
18impl RowSpec {
19    /// Creates a spec with start arrangement and top alignment.
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    /// Sets how children are spaced along the horizontal axis.
25    pub fn horizontal_arrangement(mut self, arrangement: LinearArrangement) -> Self {
26        self.horizontal_arrangement = arrangement;
27        self
28    }
29
30    /// Sets how children align on the vertical axis.
31    pub fn vertical_alignment(mut self, alignment: VerticalAlignment) -> Self {
32        self.vertical_alignment = alignment;
33        self
34    }
35}
36
37impl Default for RowSpec {
38    fn default() -> Self {
39        Self {
40            horizontal_arrangement: LinearArrangement::Start,
41            vertical_alignment: VerticalAlignment::Top,
42        }
43    }
44}
45
46/// Places children from left to right, or right to left for an RTL layout.
47/// `spec` sets horizontal space and vertical alignment.
48/// Like Compose's, it is inline: a state its content reads recomposes the
49/// composable that called it.
50///
51/// # Example
52///
53/// ```rust
54/// use cranpose_ui::*;
55///
56/// #[composable]
57/// fn Summary() {
58///     Row(
59///         Modifier::empty().fill_max_width(),
60///         RowSpec::default().horizontal_arrangement(LinearArrangement::SpaceBetween),
61///         || {
62///             Text("Name", Modifier::empty(), TextStyle::default());
63///             Text("Value", Modifier::empty(), TextStyle::default());
64///         },
65///     );
66/// }
67/// ```
68#[composable(no_skip)]
69pub fn Row<F>(modifier: Modifier, spec: RowSpec, content: F) -> NodeId
70where
71    F: FnMut() + 'static,
72{
73    let environment = LayoutEnvironment::current();
74    let mut policy = FlexMeasurePolicy::row(
75        spec.horizontal_arrangement,
76        spec.vertical_alignment,
77        environment.density.density(),
78    );
79    policy.layout_direction = environment.direction;
80    compose_layout(modifier, policy, environment, content)
81}