Introduce Expanded element

Max Brunsfeld and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/gpui/src/elements.rs          |  9 +++
crates/gpui/src/elements/expanded.rs | 90 ++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)

Detailed changes

crates/gpui/src/elements.rs 🔗

@@ -4,6 +4,7 @@ mod constrained_box;
 mod container;
 mod empty;
 mod event_handler;
+mod expanded;
 mod flex;
 mod hook;
 mod image;
@@ -16,6 +17,7 @@ mod svg;
 mod text;
 mod uniform_list;
 
+use self::expanded::Expanded;
 pub use self::{
     align::*, canvas::*, constrained_box::*, container::*, empty::*, event_handler::*, flex::*,
     hook::*, image::*, label::*, list::*, mouse_event_handler::*, overlay::*, stack::*, svg::*,
@@ -130,6 +132,13 @@ pub trait Element {
         Container::new(self.boxed())
     }
 
+    fn expanded(self) -> Expanded
+    where
+        Self: 'static + Sized,
+    {
+        Expanded::new(self.boxed())
+    }
+
     fn flexible(self, flex: f32, expanded: bool) -> Flexible
     where
         Self: 'static + Sized,

crates/gpui/src/elements/expanded.rs 🔗

@@ -0,0 +1,90 @@
+use crate::{
+    geometry::{rect::RectF, vector::Vector2F},
+    json, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
+    SizeConstraint,
+};
+use serde_json::json;
+
+pub struct Expanded {
+    child: ElementBox,
+    full_width: bool,
+    full_height: bool,
+}
+
+impl Expanded {
+    pub fn new(child: ElementBox) -> Self {
+        Self {
+            child,
+            full_width: true,
+            full_height: true,
+        }
+    }
+
+    pub fn to_full_width(mut self) -> Self {
+        self.full_width = true;
+        self.full_height = false;
+        self
+    }
+
+    pub fn to_full_height(mut self) -> Self {
+        self.full_width = false;
+        self.full_height = true;
+        self
+    }
+}
+
+impl Element for Expanded {
+    type LayoutState = ();
+    type PaintState = ();
+
+    fn layout(
+        &mut self,
+        mut constraint: SizeConstraint,
+        cx: &mut LayoutContext,
+    ) -> (Vector2F, Self::LayoutState) {
+        if self.full_width {
+            constraint.min.set_x(constraint.max.x());
+        }
+        if self.full_height {
+            constraint.min.set_y(constraint.max.y());
+        }
+        let size = self.child.layout(constraint, cx);
+        (size, ())
+    }
+
+    fn paint(
+        &mut self,
+        bounds: RectF,
+        visible_bounds: RectF,
+        _: &mut Self::LayoutState,
+        cx: &mut PaintContext,
+    ) -> Self::PaintState {
+        self.child.paint(bounds.origin(), visible_bounds, cx);
+    }
+
+    fn dispatch_event(
+        &mut self,
+        event: &Event,
+        _: RectF,
+        _: &mut Self::LayoutState,
+        _: &mut Self::PaintState,
+        cx: &mut EventContext,
+    ) -> bool {
+        self.child.dispatch_event(event, cx)
+    }
+
+    fn debug(
+        &self,
+        _: RectF,
+        _: &Self::LayoutState,
+        _: &Self::PaintState,
+        cx: &DebugContext,
+    ) -> json::Value {
+        json!({
+            "type": "Expanded",
+            "full_width": self.full_width,
+            "full_height": self.full_height,
+            "child": self.child.debug(cx)
+        })
+    }
+}