Checkpoint

Nathan Sobo created

Change summary

crates/gpui3/src/elements/div.rs |  3 -
crates/gpui3/src/elements/img.rs |  3 +
crates/gpui3/src/geometry.rs     | 44 +++++++++++++++++++++++++++++----
crates/gpui3/src/style.rs        | 44 +++++++++++++++------------------
crates/gpui3/src/window.rs       |  4 +++
5 files changed, 65 insertions(+), 33 deletions(-)

Detailed changes

crates/gpui3/src/elements/div.rs 🔗

@@ -55,7 +55,7 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
         let Layout { order, bounds } = layout;
 
         let style = self.computed_style();
-        style.paint_background(bounds, cx);
+        style.paint(order, bounds, cx);
         let overflow = &style.overflow;
         // // todo!("support only one dimension being hidden")
         // if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
@@ -69,7 +69,6 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
         } else {
             self.paint_children(overflow, state, cx)?;
         }
-        style.paint_foreground(bounds, cx);
 
         self.handle_scroll(order, bounds, style.overflow.clone(), child_layouts, cx);
 

crates/gpui3/src/elements/img.rs 🔗

@@ -49,9 +49,10 @@ impl<S: 'static> Element for Img<S> {
         cx: &mut crate::ViewContext<Self::State>,
     ) -> Result<()> {
         let style = self.computed_style();
+        let order = layout.order;
         let bounds = layout.bounds;
 
-        style.paint_background(bounds, cx);
+        style.paint(order, bounds, cx);
 
         // if let Some(uri) = &self.uri {
         //     let image_future = cx.image_cache.get(uri.clone());

crates/gpui3/src/geometry.rs 🔗

@@ -307,6 +307,24 @@ unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Edges<T> {}
 
 unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Edges<T> {}
 
+impl<T: Clone + Debug> Edges<T> {
+    pub fn map<U: Clone + Debug, F: Fn(&T) -> U>(&self, f: F) -> Edges<U> {
+        Edges {
+            top: f(&self.top),
+            right: f(&self.right),
+            bottom: f(&self.bottom),
+            left: f(&self.left),
+        }
+    }
+
+    pub fn any<F: Fn(&T) -> bool>(&self, predicate: F) -> bool {
+        predicate(&self.top)
+            || predicate(&self.right)
+            || predicate(&self.bottom)
+            || predicate(&self.left)
+    }
+}
+
 impl Edges<Length> {
     pub fn auto() -> Self {
         Self {
@@ -358,12 +376,6 @@ impl Edges<AbsoluteLength> {
     }
 }
 
-impl Edges<Pixels> {
-    pub fn is_empty(&self) -> bool {
-        self.top == px(0.) && self.right == px(0.) && self.bottom == px(0.) && self.left == px(0.)
-    }
-}
-
 #[derive(Refineable, Clone, Default, Debug)]
 #[refineable(debug)]
 #[repr(C)]
@@ -374,6 +386,17 @@ pub struct Corners<T: Clone + Debug> {
     pub bottom_left: T,
 }
 
+impl<T: Clone + Debug> Corners<T> {
+    pub fn map<U: Clone + Debug, F: Fn(&T) -> U>(&self, f: F) -> Corners<U> {
+        Corners {
+            top_left: f(&self.top_left),
+            top_right: f(&self.top_right),
+            bottom_right: f(&self.bottom_right),
+            bottom_left: f(&self.bottom_left),
+        }
+    }
+}
+
 impl<T: Clone + Debug + Mul<Output = T>> Mul for Corners<T> {
     type Output = Self;
 
@@ -537,6 +560,15 @@ pub enum AbsoluteLength {
     Rems(Rems),
 }
 
+impl AbsoluteLength {
+    pub fn is_zero(&self) -> bool {
+        match self {
+            AbsoluteLength::Pixels(px) => px.0 == 0.,
+            AbsoluteLength::Rems(rems) => rems.0 == 0.,
+        }
+    }
+}
+
 impl From<Pixels> for AbsoluteLength {
     fn from(pixels: Pixels) -> Self {
         AbsoluteLength::Pixels(pixels)

crates/gpui3/src/style.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
     phi, rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges,
     EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point,
-    PointRefinement, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext,
+    PointRefinement, Quad, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext,
     WindowContext,
 };
 use refineable::Refineable;
@@ -180,24 +180,29 @@ impl Style {
     }
 
     /// Paints the background of an element styled with this style.
-    pub fn paint_background<V: 'static>(&self, _bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
-        let _rem_size = cx.rem_size();
-        if let Some(_color) = self.fill.as_ref().and_then(Fill::color) {
-            todo!();
-        }
-    }
-
-    /// Paints the foreground of an element styled with this style.
-    pub fn paint_foreground<V: 'static>(&self, _bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
+    pub fn paint<V: 'static>(&self, order: u32, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
         let rem_size = cx.rem_size();
 
-        if let Some(_color) = self.border_color {
-            let border = self.border_widths.to_pixels(rem_size);
-            if !border.is_empty() {
-                todo!();
-            }
+        let background_color = self.fill.as_ref().and_then(Fill::color);
+        if background_color.is_some() || self.is_border_visible() {
+            cx.scene().insert(Quad {
+                order,
+                bounds,
+                clip_bounds: bounds, // todo!
+                clip_corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
+                background: background_color.unwrap_or_default(),
+                border_color: self.border_color.unwrap_or_default(),
+                corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
+                border_widths: self.border_widths.map(|length| length.to_pixels(rem_size)),
+            });
         }
     }
+
+    fn is_border_visible(&self) -> bool {
+        self.border_color
+            .map_or(false, |color| !color.is_transparent())
+            && self.border_widths.any(|length| !length.is_zero())
+    }
 }
 
 impl Default for Style {
@@ -271,15 +276,6 @@ impl From<Hsla> for Fill {
     }
 }
 
-#[derive(Clone, Refineable, Default, Debug)]
-#[refineable(debug)]
-pub struct CornerRadii {
-    pub top_left: AbsoluteLength,
-    pub top_right: AbsoluteLength,
-    pub bottom_left: AbsoluteLength,
-    pub bottom_right: AbsoluteLength,
-}
-
 impl From<TextStyle> for HighlightStyle {
     fn from(other: TextStyle) -> Self {
         Self::from(&other)

crates/gpui3/src/window.rs 🔗

@@ -121,6 +121,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         self.window.mouse_position
     }
 
+    pub fn scene(&mut self) -> &mut Scene {
+        &mut self.window.scene
+    }
+
     pub(crate) fn draw(&mut self) -> Result<()> {
         let unit_entity = self.unit_entity.clone();
         self.update_entity(&unit_entity, |_, cx| {