Skip to main content

fission_core/ui/widgets/
row.rs

1use crate::{Lower, LoweringContext, Node, NodeBuilder};
2use fission_ir::{FlexDirection, LayoutOp, NodeId, Op, Semantics};
3use fission_ir::op::{FlexWrap, AlignItems, JustifyContent};
4use serde::{Deserialize, Serialize};
5
6/// A horizontal flex container that lays out children in a row.
7///
8/// Children are arranged left-to-right (in LTR locales). Use `align_items` to
9/// control cross-axis (vertical) alignment and `justify_content` for main-axis
10/// (horizontal) distribution.
11///
12/// # Example
13///
14/// ```rust,ignore
15/// Row {
16///     children: vec![
17///         Icon::path("M12 2L2 22h20L12 2z").into_node().into(),
18///         Text::new("Warning").into_node().into(),
19///     ],
20///     gap: Some(8.0),
21///     align_items: AlignItems::Center,
22///     justify_content: JustifyContent::Start,
23///     ..Default::default()
24/// }
25/// ```
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct Row {
28    /// Explicit node identity.
29    pub id: Option<NodeId>,
30    /// The child widgets laid out left-to-right.
31    pub children: Vec<Node>,
32    /// Custom semantics for accessibility.
33    pub semantics: Option<Semantics>,
34    /// Flex grow factor.
35    pub flex_grow: f32,
36    /// Flex shrink factor.
37    pub flex_shrink: f32,
38    /// Spacing between children in layout points.
39    pub gap: Option<f32>,
40    /// Whether children wrap to a new line when they overflow.
41    pub wrap: FlexWrap,
42    /// Cross-axis (vertical) alignment of children (default: `Center`).
43    pub align_items: AlignItems,
44    /// Main-axis (horizontal) distribution of children (default: `Start`).
45    pub justify_content: JustifyContent,
46}
47
48impl Default for Row {
49    fn default() -> Self {
50        Self {
51            id: None,
52            children: Vec::new(),
53            semantics: None,
54            flex_grow: 0.0,
55            flex_shrink: 1.0,
56            gap: None,
57            wrap: FlexWrap::NoWrap,
58            align_items: AlignItems::Center,
59            justify_content: JustifyContent::Start,
60        }
61    }
62}
63
64impl Row {
65    pub fn children(mut self, children: Vec<Node>) -> Self {
66        self.children = children;
67        self
68    }
69
70    pub fn flex_grow(mut self, flex_grow: f32) -> Self {
71        self.flex_grow = flex_grow;
72        self
73    }
74
75    pub fn gap(mut self, gap: f32) -> Self {
76        self.gap = Some(gap);
77        self
78    }
79
80    pub fn align_items(mut self, align: AlignItems) -> Self {
81        self.align_items = align;
82        self
83    }
84
85    pub fn justify_content(mut self, justify: JustifyContent) -> Self {
86        self.justify_content = justify;
87        self
88    }
89
90    pub fn into_node(self) -> Node {
91        Node::Row(self)
92    }
93}
94
95impl Lower for Row {
96    fn lower(&self, cx: &mut LoweringContext) -> NodeId {
97        let layout_id = self.id.unwrap_or_else(|| cx.next_node_id());
98        
99        cx.push_scope(layout_id);
100        
101        let mut builder = NodeBuilder::new(
102            layout_id,
103            Op::Layout(LayoutOp::Flex {
104                direction: FlexDirection::Row,
105                wrap: self.wrap,
106                flex_grow: self.flex_grow,
107                flex_shrink: self.flex_shrink,
108                padding: [0.0; 4],
109                gap: self.gap,
110                align_items: self.align_items,
111                justify_content: self.justify_content,
112            }),
113        );
114        for child in &self.children {
115            builder.add_child(child.lower(cx));
116        }
117        
118        cx.pop_scope();
119        
120        let layout_id = builder.build(cx);
121
122        if let Some(s) = &self.semantics {
123            let mut semantics_builder =
124                NodeBuilder::new(cx.next_node_id(), Op::Semantics(s.clone()));
125            semantics_builder.add_child(layout_id);
126            return semantics_builder.build(cx);
127        }
128
129        layout_id
130    }
131}