Checkpoint

Nathan Sobo created

Change summary

crates/gpui3/src/element.rs           |  16 --
crates/gpui3/src/elements/div.rs      | 157 +++++++---------------------
crates/gpui3/src/elements/img.rs      |   4 
crates/gpui3/src/elements/svg.rs      |   4 
crates/gpui3/src/elements/text.rs     |   4 
crates/gpui3/src/view.rs              |   8 +
crates/storybook2/src/collab_panel.rs |   4 
7 files changed, 67 insertions(+), 130 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -1,4 +1,4 @@
-use crate::{BorrowWindow, Bounds, ElementId, Identified, LayoutId, Pixels, Point, ViewContext};
+use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
 
@@ -6,9 +6,7 @@ pub trait Element: 'static + Send + Sync {
     type ViewState: 'static + Send + Sync;
     type ElementState: 'static + Send + Sync;
 
-    fn element_id(&self) -> Option<ElementId> {
-        None
-    }
+    fn element_id(&self) -> Option<ElementId>;
 
     fn layout(
         &mut self,
@@ -24,16 +22,6 @@ pub trait Element: 'static + Send + Sync {
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<Self::ViewState>,
     );
-
-    fn id(self, id: impl Into<ElementId>) -> Identified<Self>
-    where
-        Self: Sized,
-    {
-        Identified {
-            element: self,
-            id: id.into(),
-        }
-    }
 }
 
 pub trait StatefulElement: Element {

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

@@ -1,30 +1,41 @@
 use crate::{
-    AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
-    ParentElement, Pixels, Point, Refineable, RefinementCascade, Style, Styled, ViewContext,
+    AnyElement, Bounds, Element, ElementId, Interactive, LayoutId, MouseEventListeners, Overflow,
+    ParentElement, Pixels, Point, Refineable, RefinementCascade, StatefulElement, Style, Styled,
+    ViewContext,
 };
 use parking_lot::Mutex;
 use smallvec::SmallVec;
-use std::sync::Arc;
+use std::{marker::PhantomData, sync::Arc};
 
-pub struct Div<S: 'static> {
+pub enum HasId {}
+
+pub struct Div<S: 'static, I = ()> {
     styles: RefinementCascade<Style>,
+    id: Option<ElementId>,
     listeners: MouseEventListeners<S>,
     children: SmallVec<[AnyElement<S>; 2]>,
     scroll_state: Option<ScrollState>,
+    identified: PhantomData<I>,
 }
 
 pub fn div<S>() -> Div<S> {
     Div {
         styles: Default::default(),
+        id: None,
         listeners: Default::default(),
         children: Default::default(),
         scroll_state: None,
+        identified: PhantomData,
     }
 }
 
-impl<S: 'static + Send + Sync> Element for Div<S> {
+impl<S: 'static + Send + Sync, Marker: 'static + Send + Sync> Element for Div<S, Marker> {
     type ViewState = S;
-    type ElementState = Vec<LayoutId>;
+    type ElementState = ();
+
+    fn element_id(&self) -> Option<ElementId> {
+        self.id.clone()
+    }
 
     fn layout(
         &mut self,
@@ -35,14 +46,14 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
         let style = self.computed_style();
         let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx));
         let layout_id = cx.request_layout(style.into(), child_layout_ids.clone());
-        (layout_id, child_layout_ids)
+        (layout_id, ())
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
         state: &mut S,
-        child_layout_ids: &mut Self::ElementState,
+        _: &mut (),
         cx: &mut ViewContext<S>,
     ) {
         let style = self.computed_style();
@@ -57,17 +68,30 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
                 })
             })
         });
-        self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
+    }
+}
 
-        // todo!("enable inspector")
-        // if cx.is_inspector_enabled() {
-        //     self.paint_inspector(parent_origin, layout, cx);
-        // }
-        //
+impl<S> Div<S, ()>
+where
+    S: 'static + Send + Sync,
+{
+    pub fn id(self, id: impl Into<ElementId>) -> Div<S, HasId> {
+        Div {
+            styles: self.styles,
+            id: Some(id.into()),
+            listeners: self.listeners,
+            children: self.children,
+            scroll_state: self.scroll_state,
+            identified: PhantomData,
+        }
     }
 }
 
-impl<S: 'static + Send + Sync> Div<S> {
+impl<S, Marker> Div<S, Marker>
+where
+    S: 'static + Send + Sync,
+    Marker: 'static + Send + Sync,
+{
     pub fn overflow_hidden(mut self) -> Self {
         self.declared_style().overflow.x = Some(Overflow::Hidden);
         self.declared_style().overflow.y = Some(Overflow::Hidden);
@@ -133,106 +157,9 @@ impl<S: 'static + Send + Sync> Div<S> {
             child.paint(state, Some(scroll_offset), cx);
         }
     }
-
-    fn handle_scroll(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        overflow: Point<Overflow>,
-        child_layout_ids: &[LayoutId],
-        cx: &mut ViewContext<S>,
-    ) {
-        if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
-            let mut scroll_max = Point::default();
-            for child_layout_id in child_layout_ids {
-                let child_bounds = cx.layout_bounds(*child_layout_id);
-                scroll_max = scroll_max.max(&child_bounds.lower_right());
-            }
-            scroll_max -= bounds.size;
-
-            // todo!("handle scroll")
-            // let scroll_state = self.scroll_state.as_ref().unwrap().clone();
-            // cx.on_event(order, move |_, event: &ScrollWheelEvent, cx| {
-            //     if bounds.contains_point(event.position) {
-            //         let scroll_delta = match event.delta {
-            //             ScrollDelta::Pixels(delta) => delta,
-            //             ScrollDelta::Lines(delta) => cx.text_style().font_size * delta,
-            //         };
-            //         if overflow.x == Overflow::Scroll {
-            //             scroll_state.set_x(
-            //                 (scroll_state.x() - scroll_delta.x())
-            //                     .max(px(0.))
-            //                     .min(scroll_max.x),
-            //             );
-            //         }
-            //         if overflow.y == Overflow::Scroll {
-            //             scroll_state.set_y(
-            //                 (scroll_state.y() - scroll_delta.y())
-            //                     .max(px(0.))
-            //                     .min(scroll_max.y),
-            //             );
-            //         }
-            //         cx.repaint();
-            //     } else {
-            //         cx.bubble_event();
-            //     }
-            // })
-        }
-    }
-
-    // fn paint_inspector(
-    //     &self,
-    //     parent_origin: Point<Pixels>,
-    //     layout: &Layout,
-    //     cx: &mut ViewContext<V>,
-    // ) {
-    //     let style = self.styles.merged();
-    //     let bounds = layout.bounds;
-
-    //     let hovered = bounds.contains_point(cx.mouse_position());
-    //     if hovered {
-    //         let rem_size = cx.rem_size();
-    //         // cx.scene().push_quad(scene::Quad {
-    //         //     bounds,
-    //         //     background: Some(hsla(0., 0., 1., 0.05).into()),
-    //         //     border: gpui::Border {
-    //         //         color: hsla(0., 0., 1., 0.2).into(),
-    //         //         top: 1.,
-    //         //         right: 1.,
-    //         //         bottom: 1.,
-    //         //         left: 1.,
-    //         //     },
-    //         //     corner_radii: CornerRadii::default()
-    //         //         .refined(&style.corner_radii)
-    //         //         .to_gpui(bounds.size(), rem_size),
-    //         // })
-    //     }
-
-    //     // let pressed = Cell::new(hovered && cx.is_mouse_down(MouseButton::Left));
-    //     // cx.on_event(layout.order, move |_, event: &MouseButtonEvent, _| {
-    //     //     if bounds.contains_point(event.position) {
-    //     //         if event.is_down {
-    //     //             pressed.set(true);
-    //     //         } else if pressed.get() {
-    //     //             pressed.set(false);
-    //     //             eprintln!("clicked div {:?} {:#?}", bounds, style);
-    //     //         }
-    //     //     }
-    //     // });
-
-    //     // let hovered = Cell::new(hovered);
-    //     // cx.on_event(layout.order, move |_, event: &MouseMovedEvent, cx| {
-    //     //     cx.bubble_event();
-    //     //     let hovered_now = bounds.contains_point(event.position);
-    //     //     if hovered.get() != hovered_now {
-    //     //         hovered.set(hovered_now);
-    //     //         cx.repaint();
-    //     //     }
-    //     // });
-    // }
-    //
 }
 
-impl<V: 'static + Send + Sync> Styled for Div<V> {
+impl<V: 'static + Send + Sync, Marker: 'static + Send + Sync> Styled for Div<V, Marker> {
     type Style = Style;
 
     fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
@@ -244,7 +171,9 @@ impl<V: 'static + Send + Sync> Styled for Div<V> {
     }
 }
 
-impl<V: Send + Sync + 'static> Interactive<V> for Div<V> {
+impl<V: Send + Sync + 'static> StatefulElement for Div<V, HasId> {}
+
+impl<V: Send + Sync + 'static> Interactive<V> for Div<V, HasId> {
     fn listeners(&mut self) -> &mut MouseEventListeners<V> {
         &mut self.listeners
     }

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

@@ -38,6 +38,10 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
     type ViewState = S;
     type ElementState = ();
 
+    fn element_id(&self) -> Option<crate::ElementId> {
+        None
+    }
+
     fn layout(
         &mut self,
         _: &mut Self::ViewState,

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

@@ -28,6 +28,10 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
     type ViewState = S;
     type ElementState = ();
 
+    fn element_id(&self) -> Option<crate::ElementId> {
+        None
+    }
+
     fn layout(
         &mut self,
         _: &mut S,

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

@@ -34,6 +34,10 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
     type ViewState = S;
     type ElementState = Arc<Mutex<Option<TextElementState>>>;
 
+    fn element_id(&self) -> Option<crate::ElementId> {
+        None
+    }
+
     fn layout(
         &mut self,
         _view: &mut S,

crates/gpui3/src/view.rs 🔗

@@ -53,6 +53,10 @@ impl<S: 'static + Send + Sync, P: 'static + Send + Sync> Element for View<S, P>
     type ViewState = P;
     type ElementState = AnyElement<S>;
 
+    fn element_id(&self) -> Option<crate::ElementId> {
+        None
+    }
+
     fn layout(
         &mut self,
         _: &mut Self::ViewState,
@@ -110,6 +114,10 @@ impl<S: 'static + Send + Sync> Element for AnyView<S> {
     type ViewState = ();
     type ElementState = AnyBox;
 
+    fn element_id(&self) -> Option<crate::ElementId> {
+        None
+    }
+
     fn layout(
         &mut self,
         _: &mut Self::ViewState,

crates/storybook2/src/collab_panel.rs 🔗

@@ -1,7 +1,7 @@
 use crate::theme::{theme, Theme};
 use gpui3::{
-    div, img, svg, view, AppContext, Context, Element, ElementId, Interactive, IntoAnyElement,
-    MouseButton, ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
+    div, img, svg, view, AppContext, Context, Element, ElementId, IntoAnyElement, MouseButton,
+    ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
     WindowContext,
 };