Skip to main content

guise/flex/
rowcolumn.rs

1//! `Row` and `Column` — Flutter's primary flex containers.
2
3use gpui::prelude::*;
4use gpui::{div, px, AnyElement, App, IntoElement, Window};
5
6use super::{apply_cross, apply_main, CrossAxisAlignment, MainAxisAlignment, MainAxisSize};
7use crate::devtools::Probed;
8
9/// A horizontal flex container. Flutter's `Row`.
10#[derive(IntoElement)]
11pub struct Row {
12    children: Vec<AnyElement>,
13    main: MainAxisAlignment,
14    cross: CrossAxisAlignment,
15    size: MainAxisSize,
16    gap: f32,
17}
18
19impl Row {
20    pub fn new() -> Self {
21        Row {
22            children: Vec::new(),
23            main: MainAxisAlignment::Start,
24            cross: CrossAxisAlignment::Center,
25            size: MainAxisSize::Max,
26            gap: 0.0,
27        }
28    }
29
30    pub fn main_axis_alignment(mut self, main: MainAxisAlignment) -> Self {
31        self.main = main;
32        self
33    }
34
35    pub fn cross_axis_alignment(mut self, cross: CrossAxisAlignment) -> Self {
36        self.cross = cross;
37        self
38    }
39
40    pub fn main_axis_size(mut self, size: MainAxisSize) -> Self {
41        self.size = size;
42        self
43    }
44
45    /// Convenience spacing between children (Flutter uses `SizedBox`).
46    pub fn gap(mut self, gap: f32) -> Self {
47        self.gap = gap;
48        self
49    }
50}
51
52impl Default for Row {
53    fn default() -> Self {
54        Row::new()
55    }
56}
57
58impl ParentElement for Row {
59    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
60        self.children.extend(elements);
61    }
62}
63
64impl RenderOnce for Row {
65    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
66        let mut base = div().flex().flex_row();
67        if self.gap > 0.0 {
68            base = base.gap(px(self.gap));
69        }
70        if self.size == MainAxisSize::Max {
71            base = base.w_full();
72        }
73        let base = apply_cross(apply_main(base, self.main), self.cross);
74        base.children(self.children).probe("Row")
75    }
76}
77
78/// A vertical flex container. Flutter's `Column`.
79#[derive(IntoElement)]
80pub struct Column {
81    children: Vec<AnyElement>,
82    main: MainAxisAlignment,
83    cross: CrossAxisAlignment,
84    size: MainAxisSize,
85    gap: f32,
86}
87
88impl Column {
89    pub fn new() -> Self {
90        Column {
91            children: Vec::new(),
92            main: MainAxisAlignment::Start,
93            cross: CrossAxisAlignment::Center,
94            // Min by default (shrink to content) — more predictable than
95            // Flutter's Max inside a scrolling page.
96            size: MainAxisSize::Min,
97            gap: 0.0,
98        }
99    }
100
101    pub fn main_axis_alignment(mut self, main: MainAxisAlignment) -> Self {
102        self.main = main;
103        self
104    }
105
106    pub fn cross_axis_alignment(mut self, cross: CrossAxisAlignment) -> Self {
107        self.cross = cross;
108        self
109    }
110
111    pub fn main_axis_size(mut self, size: MainAxisSize) -> Self {
112        self.size = size;
113        self
114    }
115
116    pub fn gap(mut self, gap: f32) -> Self {
117        self.gap = gap;
118        self
119    }
120}
121
122impl Default for Column {
123    fn default() -> Self {
124        Column::new()
125    }
126}
127
128impl ParentElement for Column {
129    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
130        self.children.extend(elements);
131    }
132}
133
134impl RenderOnce for Column {
135    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
136        let mut base = div().flex().flex_col();
137        if self.gap > 0.0 {
138            base = base.gap(px(self.gap));
139        }
140        if self.size == MainAxisSize::Max {
141            base = base.h_full();
142        }
143        let base = apply_cross(apply_main(base, self.main), self.cross);
144        base.children(self.children).probe("Column")
145    }
146}