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