Skip to main content

cranpose_ui/widgets/
box_widget.rs

1//! Box widget implementation
2
3use cranpose_core::NodeId;
4use cranpose_ui_layout::Alignment;
5
6use super::layout::{LayoutEnvironment, compose_layout};
7use crate::{composable, layout::policies::BoxMeasurePolicy, modifier::Modifier};
8
9/// Specification for Box layout behavior.
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub struct BoxSpec {
12    /// Where children sit inside the box. Defaults to top start.
13    pub content_alignment: Alignment,
14    /// Whether the box's minimum constraints pass on to its children. Defaults to `false`.
15    pub propagate_min_constraints: bool,
16}
17
18impl BoxSpec {
19    /// Creates a spec with top start alignment and no minimum constraint propagation.
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    /// Sets where children sit inside the box.
25    pub fn content_alignment(mut self, alignment: Alignment) -> Self {
26        self.content_alignment = alignment;
27        self
28    }
29
30    /// Sets whether the box's minimum constraints pass on to its children.
31    pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
32        self.propagate_min_constraints = propagate;
33        self
34    }
35}
36
37impl Default for BoxSpec {
38    fn default() -> Self {
39        Self {
40            content_alignment: Alignment::TOP_START,
41            propagate_min_constraints: false,
42        }
43    }
44}
45
46/// Places children over the same area. `content_alignment` selects each child's
47/// position within the box; later children draw above earlier children.
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 Badge() {
58///     Box(
59///         Modifier::empty()
60///             .size_points(100.0, 100.0)
61///             .background(Color(0.1, 0.3, 0.9, 1.0)),
62///         BoxSpec::default().content_alignment(Alignment::CENTER),
63///         || {
64///             Text("Centered", Modifier::empty(), TextStyle::default());
65///         },
66///     );
67/// }
68/// ```
69#[composable(no_skip)]
70pub fn Box<F>(modifier: Modifier, spec: BoxSpec, content: F) -> NodeId
71where
72    F: FnMut() + 'static,
73{
74    let environment = LayoutEnvironment::current();
75    let mut policy = BoxMeasurePolicy::new(spec.content_alignment, spec.propagate_min_constraints);
76    policy.layout_direction = environment.direction;
77    compose_layout(modifier, policy, environment, content)
78}