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