Skip to main content

fission_core/ui/widgets/
row.rs

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