Skip to main content

guise/flex/
flexible.rs

1//! Flex helpers: `Expanded`, `Flexible`, `Spacer`, and `SizedBox`.
2
3use gpui::prelude::*;
4use gpui::{div, px, relative, App, IntoElement, Window};
5
6use crate::style::FlexExt;
7
8/// Fills the available main-axis space inside a Row/Column, by `flex` weight.
9/// Flutter's `Expanded`.
10#[derive(IntoElement)]
11pub struct Expanded {
12    child: gpui::AnyElement,
13    flex: f32,
14}
15
16impl Expanded {
17    pub fn new(child: impl IntoElement) -> Self {
18        Expanded {
19            child: child.into_any_element(),
20            flex: 1.0,
21        }
22    }
23
24    /// The flex weight relative to sibling `Expanded`/`Flexible` (default 1).
25    pub fn flex(mut self, flex: f32) -> Self {
26        self.flex = flex;
27        self
28    }
29}
30
31impl RenderOnce for Expanded {
32    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
33        // grow by weight, shrink, zero basis — the child takes its flex share.
34        div()
35            .grow(self.flex)
36            .shrink(1.0)
37            .flex_basis(relative(0.0))
38            .child(self.child)
39    }
40}
41
42/// Takes available space up to its content, by `flex` weight. Flutter's
43/// `Flexible`.
44#[derive(IntoElement)]
45pub struct Flexible {
46    child: gpui::AnyElement,
47    flex: f32,
48}
49
50impl Flexible {
51    pub fn new(child: impl IntoElement) -> Self {
52        Flexible {
53            child: child.into_any_element(),
54            flex: 1.0,
55        }
56    }
57
58    pub fn flex(mut self, flex: f32) -> Self {
59        self.flex = flex;
60        self
61    }
62}
63
64impl RenderOnce for Flexible {
65    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
66        div().grow(self.flex).child(self.child)
67    }
68}
69
70/// An empty element that expands to push siblings apart. Flutter's `Spacer`.
71#[derive(IntoElement)]
72pub struct Spacer {
73    flex: f32,
74}
75
76impl Spacer {
77    pub fn new() -> Self {
78        Spacer { flex: 1.0 }
79    }
80
81    pub fn flex(mut self, flex: f32) -> Self {
82        self.flex = flex;
83        self
84    }
85}
86
87impl Default for Spacer {
88    fn default() -> Self {
89        Spacer::new()
90    }
91}
92
93impl RenderOnce for Spacer {
94    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
95        div().grow(self.flex).flex_basis(relative(0.0))
96    }
97}
98
99/// A fixed-size box, optionally wrapping a child. Flutter's `SizedBox`.
100#[derive(IntoElement)]
101pub struct SizedBox {
102    width: Option<f32>,
103    height: Option<f32>,
104    expand: bool,
105    child: Option<gpui::AnyElement>,
106}
107
108impl SizedBox {
109    pub fn new() -> Self {
110        SizedBox {
111            width: None,
112            height: None,
113            expand: false,
114            child: None,
115        }
116    }
117
118    pub fn width(width: f32) -> Self {
119        SizedBox::new().with_width(width)
120    }
121
122    pub fn height(height: f32) -> Self {
123        SizedBox::new().with_height(height)
124    }
125
126    pub fn square(size: f32) -> Self {
127        SizedBox::new().with_width(size).with_height(size)
128    }
129
130    /// Fills its parent on both axes.
131    pub fn expand() -> Self {
132        SizedBox {
133            expand: true,
134            ..SizedBox::new()
135        }
136    }
137
138    pub fn with_width(mut self, width: f32) -> Self {
139        self.width = Some(width);
140        self
141    }
142
143    pub fn with_height(mut self, height: f32) -> Self {
144        self.height = Some(height);
145        self
146    }
147
148    pub fn child(mut self, child: impl IntoElement) -> Self {
149        self.child = Some(child.into_any_element());
150        self
151    }
152}
153
154impl Default for SizedBox {
155    fn default() -> Self {
156        SizedBox::new()
157    }
158}
159
160impl RenderOnce for SizedBox {
161    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
162        let mut el = div();
163        if self.expand {
164            el = el.size_full();
165        }
166        if let Some(w) = self.width {
167            el = el.w(px(w));
168        }
169        if let Some(h) = self.height {
170            el = el.h(px(h));
171        }
172        if let Some(child) = self.child {
173            el = el.child(child);
174        }
175        el
176    }
177}