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}