Checkpoint

Nathan Sobo created

Change summary

crates/gpui3/src/app.rs                 |   9 
crates/gpui3/src/element.rs             | 120 +++++---
crates/gpui3/src/elements/div.rs        |  43 +-
crates/gpui3/src/elements/hoverable.rs  |  47 ++-
crates/gpui3/src/elements/identified.rs |  24 
crates/gpui3/src/elements/img.rs        |  30 +-
crates/gpui3/src/elements/pressable.rs  | 362 ++++++++++++++------------
crates/gpui3/src/elements/svg.rs        |  26 
crates/gpui3/src/elements/text.rs       |  44 +-
crates/gpui3/src/gpui3.rs               |   3 
crates/gpui3/src/styled.rs              |   6 
crates/gpui3/src/taffy.rs               |  46 +-
crates/gpui3/src/view.rs                |  76 ++---
crates/gpui3/src/window.rs              | 151 +++++++---
crates/storybook2/src/collab_panel.rs   |   6 
crates/storybook2/src/theme.rs          |  20 
crates/storybook2/src/workspace.rs      |  22 +
17 files changed, 565 insertions(+), 470 deletions(-)

Detailed changes

crates/gpui3/src/app.rs 🔗

@@ -23,10 +23,7 @@ use std::{
     mem,
     sync::{Arc, Weak},
 };
-use util::{
-    http::{self, HttpClient},
-    ResultExt,
-};
+use util::http::{self, HttpClient};
 
 #[derive(Clone)]
 pub struct App(Arc<Mutex<AppContext>>);
@@ -169,9 +166,7 @@ impl AppContext {
             .collect::<Vec<_>>();
 
         for dirty_window_id in dirty_window_ids {
-            self.update_window(dirty_window_id, |cx| cx.draw())
-                .unwrap()
-                .log_err();
+            self.update_window(dirty_window_id, |cx| cx.draw()).unwrap();
         }
     }
 

crates/gpui3/src/element.rs 🔗

@@ -1,11 +1,10 @@
-use crate::{Bounds, Identified, LayoutId, Pixels, Point, Result, ViewContext};
+use crate::{BorrowWindow, Bounds, ElementId, Identified, LayoutId, Pixels, Point, ViewContext};
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
-use util::arc_cow::ArcCow;
 
-pub trait Element: 'static {
-    type State;
-    type FrameState;
+pub trait Element: 'static + Send + Sync {
+    type ViewState: 'static + Send + Sync;
+    type ElementState: 'static + Send + Sync;
 
     fn element_id(&self) -> Option<ElementId> {
         None
@@ -13,17 +12,18 @@ pub trait Element: 'static {
 
     fn layout(
         &mut self,
-        state: &mut Self::State,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<(LayoutId, Self::FrameState)>;
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (LayoutId, Self::ElementState);
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        state: &mut Self::State,
-        frame_state: &mut Self::FrameState,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<()>;
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    );
 
     fn id(self, id: ElementId) -> Identified<Self>
     where
@@ -39,10 +39,7 @@ pub trait StatefulElement: Element {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub struct ElementId(ArcCow<'static, [u8]>);
-
-#[derive(Deref, DerefMut, Default, Clone, Debug)]
+#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
 
 pub trait ParentElement {
@@ -68,19 +65,14 @@ pub trait ParentElement {
     }
 }
 
-trait ElementObject<S> {
-    fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
-    fn paint(
-        &mut self,
-        state: &mut S,
-        offset: Option<Point<Pixels>>,
-        cx: &mut ViewContext<S>,
-    ) -> Result<()>;
+trait ElementObject<S>: 'static + Send + Sync {
+    fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
+    fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
 }
 
 struct RenderedElement<E: Element> {
     element: E,
-    phase: ElementRenderPhase<E::FrameState>,
+    phase: ElementRenderPhase<E::ElementState>,
 }
 
 #[derive(Default)]
@@ -89,15 +81,15 @@ enum ElementRenderPhase<S> {
     Rendered,
     LayoutRequested {
         layout_id: LayoutId,
-        frame_state: S,
+        frame_state: Option<S>,
     },
     Painted {
         bounds: Bounds<Pixels>,
-        frame_state: S,
+        frame_state: Option<S>,
     },
 }
 
-/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
+/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
 /// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
 /// improved usability.
 impl<E: Element> RenderedElement<E> {
@@ -107,24 +99,58 @@ impl<E: Element> RenderedElement<E> {
             phase: ElementRenderPhase::Rendered,
         }
     }
+
+    fn paint_with_element_state(
+        &mut self,
+        bounds: Bounds<Pixels>,
+        view_state: &mut E::ViewState,
+        frame_state: &mut Option<E::ElementState>,
+        cx: &mut ViewContext<E::ViewState>,
+    ) {
+        if let Some(id) = self.element.element_id() {
+            cx.with_element_state(id, |element_state, cx| {
+                let mut element_state = element_state.unwrap();
+                self.element
+                    .paint(bounds, view_state, &mut element_state, cx);
+                ((), element_state)
+            });
+        } else {
+            self.element
+                .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
+        }
+    }
 }
 
-impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
-    fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
-        let (layout_id, frame_state) = self.element.layout(state, cx)?;
+impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
+where
+    E: Element<ElementState = S>,
+    S: 'static + Send + Sync,
+{
+    fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
+        let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
+            let layout_id = cx.with_element_state(id, |element_state, cx| {
+                self.element.layout(state, element_state, cx)
+            });
+            (layout_id, None)
+        } else {
+            let (layout_id, frame_state) = self.element.layout(state, None, cx);
+            (layout_id, Some(frame_state))
+        };
+
         self.phase = ElementRenderPhase::LayoutRequested {
             layout_id,
             frame_state,
         };
-        Ok(layout_id)
+
+        layout_id
     }
 
     fn paint(
         &mut self,
-        state: &mut E::State,
+        view_state: &mut E::ViewState,
         offset: Option<Point<Pixels>>,
-        cx: &mut ViewContext<E::State>,
-    ) -> Result<()> {
+        cx: &mut ViewContext<E::ViewState>,
+    ) {
         self.phase = match std::mem::take(&mut self.phase) {
             ElementRenderPhase::Rendered => panic!("must call layout before paint"),
 
@@ -132,9 +158,9 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
                 layout_id,
                 mut frame_state,
             } => {
-                let mut bounds = cx.layout_bounds(layout_id)?.clone();
+                let mut bounds = cx.layout_bounds(layout_id);
                 offset.map(|offset| bounds.origin += offset);
-                self.element.paint(bounds, state, &mut frame_state, cx)?;
+                self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
                 ElementRenderPhase::Painted {
                     bounds,
                     frame_state,
@@ -145,32 +171,24 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
                 bounds,
                 mut frame_state,
             } => {
-                self.element
-                    .paint(bounds.clone(), state, &mut frame_state, cx)?;
+                self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
                 ElementRenderPhase::Painted {
                     bounds,
                     frame_state,
                 }
             }
         };
-
-        Ok(())
     }
 }
 
 pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
 
-impl<S> AnyElement<S> {
-    pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
+impl<S: 'static + Send + Sync> AnyElement<S> {
+    pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
         self.0.layout(state, cx)
     }
 
-    pub fn paint(
-        &mut self,
-        state: &mut S,
-        offset: Option<Point<Pixels>>,
-        cx: &mut ViewContext<S>,
-    ) -> Result<()> {
+    pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
         self.0.paint(state, offset, cx)
     }
 }
@@ -179,8 +197,8 @@ pub trait IntoAnyElement<S> {
     fn into_any(self) -> AnyElement<S>;
 }
 
-impl<E: Element> IntoAnyElement<E::State> for E {
-    fn into_any(self) -> AnyElement<E::State> {
+impl<E: Element> IntoAnyElement<E::ViewState> for E {
+    fn into_any(self) -> AnyElement<E::ViewState> {
         AnyElement(Box::new(RenderedElement::new(self)))
     }
 }

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

@@ -1,12 +1,10 @@
 use crate::{
     AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
-    ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, Styled,
-    ViewContext,
+    ParentElement, Pixels, Point, Refineable, RefinementCascade, Style, Styled, ViewContext,
 };
 use parking_lot::Mutex;
 use smallvec::SmallVec;
 use std::sync::Arc;
-use util::ResultExt;
 
 pub struct Div<S: 'static> {
     styles: RefinementCascade<Style>,
@@ -25,27 +23,28 @@ pub fn div<S>() -> Div<S> {
 }
 
 impl<S: 'static + Send + Sync> Element for Div<S> {
-    type State = S;
-    type FrameState = Vec<LayoutId>;
+    type ViewState = S;
+    type ElementState = Vec<LayoutId>;
 
     fn layout(
         &mut self,
         view: &mut S,
+        _: Option<Self::ElementState>,
         cx: &mut ViewContext<S>,
-    ) -> Result<(LayoutId, Self::FrameState)> {
+    ) -> (LayoutId, Self::ElementState) {
         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())?;
-        Ok((layout_id, child_layout_ids))
+        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)
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
         state: &mut S,
-        child_layout_ids: &mut Self::FrameState,
+        child_layout_ids: &mut Self::ElementState,
         cx: &mut ViewContext<S>,
-    ) -> Result<()> {
+    ) {
         let style = self.computed_style();
         cx.stack(0, |cx| style.paint(bounds, cx));
 
@@ -57,7 +56,7 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
                     self.paint_children(overflow, state, cx)
                 })
             })
-        })?;
+        });
         self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
 
         // todo!("enable inspector")
@@ -65,12 +64,10 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
         //     self.paint_inspector(parent_origin, layout, cx);
         // }
         //
-
-        Ok(())
     }
 }
 
-impl<S: 'static> Div<S> {
+impl<S: 'static + Send + Sync> Div<S> {
     pub fn overflow_hidden(mut self) -> Self {
         self.declared_style().overflow.x = Some(Overflow::Hidden);
         self.declared_style().overflow.y = Some(Overflow::Hidden);
@@ -118,11 +115,11 @@ impl<S: 'static> Div<S> {
         offset
     }
 
-    fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Result<Vec<LayoutId>> {
+    fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Vec<LayoutId> {
         self.children
             .iter_mut()
             .map(|child| child.layout(view, cx))
-            .collect::<Result<Vec<LayoutId>>>()
+            .collect()
     }
 
     fn paint_children(
@@ -130,12 +127,11 @@ impl<S: 'static> Div<S> {
         overflow: &Point<Overflow>,
         state: &mut S,
         cx: &mut ViewContext<S>,
-    ) -> Result<()> {
+    ) {
         let scroll_offset = self.scroll_offset(overflow);
         for child in &mut self.children {
-            child.paint(state, Some(scroll_offset), cx)?;
+            child.paint(state, Some(scroll_offset), cx);
         }
-        Ok(())
     }
 
     fn handle_scroll(
@@ -148,9 +144,8 @@ impl<S: 'static> Div<S> {
         if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
             let mut scroll_max = Point::default();
             for child_layout_id in child_layout_ids {
-                if let Some(child_bounds) = cx.layout_bounds(*child_layout_id).log_err() {
-                    scroll_max = scroll_max.max(&child_bounds.lower_right());
-                }
+                let child_bounds = cx.layout_bounds(*child_layout_id);
+                scroll_max = scroll_max.max(&child_bounds.lower_right());
             }
             scroll_max -= bounds.size;
 
@@ -237,7 +232,7 @@ impl<S: 'static> Div<S> {
     //
 }
 
-impl<V> Styled for Div<V> {
+impl<V: 'static + Send + Sync> Styled for Div<V> {
     type Style = Style;
 
     fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {

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

@@ -2,7 +2,6 @@ use crate::{
     AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
     MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
 };
-use anyhow::Result;
 use refineable::{CascadeSlot, Refineable, RefinementCascade};
 use smallvec::SmallVec;
 use std::sync::{
@@ -10,7 +9,10 @@ use std::sync::{
     Arc,
 };
 
-pub struct Hoverable<E: Styled> {
+pub struct Hoverable<E: Styled>
+// where
+// <E::Style as Refineable>::Refinement: 'static + Send + Sync,
+{
     hovered: Arc<AtomicBool>,
     cascade_slot: CascadeSlot,
     hovered_style: <E::Style as Refineable>::Refinement,
@@ -49,9 +51,14 @@ impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Ho
     }
 }
 
-impl<E: Element + Styled> Element for Hoverable<E> {
-    type State = E::State;
-    type FrameState = E::FrameState;
+impl<E> Element for Hoverable<E>
+where
+    E: Element + Styled,
+    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
+    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+{
+    type ViewState = E::ViewState;
+    type ElementState = E::ElementState;
 
     fn element_id(&self) -> Option<ElementId> {
         self.child.element_id()
@@ -59,19 +66,20 @@ impl<E: Element + Styled> Element for Hoverable<E> {
 
     fn layout(
         &mut self,
-        state: &mut Self::State,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<(crate::LayoutId, Self::FrameState)> {
-        Ok(self.child.layout(state, cx)?)
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (crate::LayoutId, Self::ElementState) {
+        self.child.layout(state, element_state, cx)
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        state: &mut Self::State,
-        frame_state: &mut Self::FrameState,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<()> {
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
         let hovered = bounds.contains_point(cx.mouse_position());
         let slot = self.cascade_slot;
         let style = hovered.then_some(self.hovered_style.clone());
@@ -79,7 +87,7 @@ impl<E: Element + Styled> Element for Hoverable<E> {
         self.hovered.store(hovered, SeqCst);
 
         let hovered = self.hovered.clone();
-        cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
+        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
             if phase == DispatchPhase::Capture {
                 if bounds.contains_point(event.position) != hovered.load(SeqCst) {
                     cx.notify();
@@ -87,8 +95,7 @@ impl<E: Element + Styled> Element for Hoverable<E> {
             }
         });
 
-        self.child.paint(bounds, state, frame_state, cx)?;
-        Ok(())
+        self.child.paint(bounds, state, element_state, cx);
     }
 }
 
@@ -100,4 +107,10 @@ impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
     }
 }
 
-impl<E: StatefulElement + Styled> StatefulElement for Hoverable<E> {}
+impl<E> StatefulElement for Hoverable<E>
+where
+    E: StatefulElement + Styled,
+    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
+    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+{
+}

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

@@ -1,5 +1,4 @@
 use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext};
-use anyhow::Result;
 
 pub struct Identified<E> {
     pub(crate) element: E,
@@ -7,8 +6,8 @@ pub struct Identified<E> {
 }
 
 impl<E: Element> Element for Identified<E> {
-    type State = E::State;
-    type FrameState = E::FrameState;
+    type ViewState = E::ViewState;
+    type ElementState = E::ElementState;
 
     fn element_id(&self) -> Option<ElementId> {
         Some(self.id.clone())
@@ -16,21 +15,22 @@ impl<E: Element> Element for Identified<E> {
 
     fn layout(
         &mut self,
-        state: &mut Self::State,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<(LayoutId, Self::FrameState)> {
-        self.element.layout(state, cx)
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (LayoutId, Self::ElementState) {
+        self.element.layout(state, element_state, cx)
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<crate::Pixels>,
-        state: &mut Self::State,
-        frame_state: &mut Self::FrameState,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<()> {
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
         cx.with_element_id(self.id.clone(), |cx| {
-            self.element.paint(bounds, state, frame_state, cx)
+            self.element.paint(bounds, state, element_state, cx)
         })
     }
 }

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

@@ -1,6 +1,5 @@
 use crate::{
-    BorrowWindow, Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled,
-    ViewContext,
+    BorrowWindow, Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled, ViewContext,
 };
 use futures::FutureExt;
 use refineable::RefinementCascade;
@@ -36,29 +35,30 @@ impl<S> Img<S> {
 }
 
 impl<S: Send + Sync + 'static> Element for Img<S> {
-    type State = S;
-    type FrameState = ();
+    type ViewState = S;
+    type ElementState = ();
 
     fn layout(
         &mut self,
-        _: &mut Self::State,
-        cx: &mut ViewContext<Self::State>,
-    ) -> anyhow::Result<(LayoutId, Self::FrameState)>
+        _: &mut Self::ViewState,
+        _: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (LayoutId, Self::ElementState)
     where
         Self: Sized,
     {
         let style = self.computed_style();
-        let layout_id = cx.request_layout(style, [])?;
-        Ok((layout_id, ()))
+        let layout_id = cx.request_layout(style, []);
+        (layout_id, ())
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        _: &mut Self::State,
-        _: &mut Self::FrameState,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<()> {
+        _: &mut Self::ViewState,
+        _: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
         let style = self.computed_style();
 
         style.paint(bounds, cx);
@@ -73,7 +73,8 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
                 let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
                 cx.stack(1, |cx| {
                     cx.paint_image(bounds, corner_radii, data, self.grayscale)
-                })?;
+                        .log_err()
+                });
             } else {
                 cx.spawn(|_, mut cx| async move {
                     if image_future.await.log_err().is_some() {
@@ -83,7 +84,6 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
                 .detach()
             }
         }
-        Ok(())
     }
 }
 

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

@@ -1,211 +1,237 @@
+use crate::{
+    AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseDownEvent, MouseEventListeners,
+    MouseUpEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
+};
+use refineable::{CascadeSlot, Refineable, RefinementCascade};
+use smallvec::SmallVec;
+use std::sync::{
+    atomic::{AtomicBool, Ordering::SeqCst},
+    Arc,
+};
+
+pub struct Pressable<E: Styled> {
+    cascade_slot: CascadeSlot,
+    pressed_style: <E::Style as Refineable>::Refinement,
+    child: E,
+}
+
+pub struct PressableState<S> {
+    pressed: Arc<AtomicBool>,
+    child_state: S,
+}
+
+impl<E: Styled> Pressable<E> {
+    pub fn new(mut child: E) -> Self {
+        Self {
+            cascade_slot: child.style_cascade().reserve(),
+            pressed_style: Default::default(),
+            child,
+        }
+    }
+}
+
+impl<E> Styled for Pressable<E>
+where
+    E: Styled,
+{
+    type Style = E::Style;
+
+    fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
+        self.child.style_cascade()
+    }
+
+    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
+        &mut self.pressed_style
+    }
+}
+
+impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pressable<E> {
+    fn listeners(&mut self) -> &mut MouseEventListeners<S> {
+        self.child.listeners()
+    }
+}
+
+impl<E> Element for Pressable<E>
+where
+    E: Styled + StatefulElement,
+    <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
+    <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+{
+    type ViewState = E::ViewState;
+    type ElementState = PressableState<E::ElementState>;
+
+    fn layout(
+        &mut self,
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (crate::LayoutId, Self::ElementState) {
+        if let Some(element_state) = element_state {
+            let (id, child_state) = self
+                .child
+                .layout(state, Some(element_state.child_state), cx);
+            let element_state = PressableState {
+                pressed: element_state.pressed,
+                child_state,
+            };
+            (id, element_state)
+        } else {
+            let (id, child_state) = self.child.layout(state, None, cx);
+            let element_state = PressableState {
+                pressed: Default::default(),
+                child_state,
+            };
+            (id, element_state)
+        }
+    }
+
+    fn paint(
+        &mut self,
+        bounds: Bounds<Pixels>,
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
+        let slot = self.cascade_slot;
+        let style = element_state
+            .pressed
+            .load(SeqCst)
+            .then_some(self.pressed_style.clone());
+        self.style_cascade().set(slot, style);
+
+        let pressed = element_state.pressed.clone();
+        cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
+            if phase == DispatchPhase::Capture {
+                if bounds.contains_point(event.position) != pressed.load(SeqCst) {
+                    cx.notify();
+                }
+            }
+        });
+        let hovered = element_state.pressed.clone();
+        cx.on_mouse_event(move |_, event: &MouseUpEvent, phase, cx| {
+            if phase == DispatchPhase::Capture {
+                if bounds.contains_point(event.position) != hovered.load(SeqCst) {
+                    cx.notify();
+                }
+            }
+        });
+
+        self.child
+            .paint(bounds, state, &mut element_state.child_state, cx);
+    }
+}
+
+impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
+    type State = E::State;
+
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+        self.child.children_mut()
+    }
+}
+
 // use crate::{
-//     AnyElement, Bounds, DispatchPhase, Element, Identified, Interactive, MouseDownEvent,
-//     MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
+//     element::{AnyElement, Element, IntoElement, Layout, ParentElement},
+//     interactive::{InteractionHandlers, Interactive},
+//     style::{Style, StyleHelpers, Styleable},
+//     ViewContext,
 // };
 // use anyhow::Result;
+// use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
 // use refineable::{CascadeSlot, Refineable, RefinementCascade};
 // use smallvec::SmallVec;
-// use std::sync::{
-//     atomic::{AtomicBool, Ordering::SeqCst},
-//     Arc,
-// };
+// use std::{cell::Cell, rc::Rc};
 
-// pub struct Pressable<E: Styled> {
-//     pressed: Arc<AtomicBool>,
-//     cascade_slot: CascadeSlot,
+// pub struct Pressable<E: Styleable> {
+//     pressed: Rc<Cell<bool>>,
 //     pressed_style: <E::Style as Refineable>::Refinement,
+//     cascade_slot: CascadeSlot,
 //     child: E,
 // }
 
-// impl<E: Identified + Styled> Pressable<E> {
-//     pub fn new(mut child: E) -> Self {
-//         Self {
-//             pressed: Arc::new(AtomicBool::new(false)),
-//             cascade_slot: child.style_cascade().reserve(),
-//             pressed_style: Default::default(),
-//             child,
-//         }
+// pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
+//     Pressable {
+//         pressed: Rc::new(Cell::new(false)),
+//         pressed_style: Default::default(),
+//         cascade_slot: child.style_cascade().reserve(),
+//         child,
 //     }
 // }
 
-// impl<E> Styled for Pressable<E>
-// where
-//     E: Styled,
-// {
+// impl<E: Styleable> Styleable for Pressable<E> {
 //     type Style = E::Style;
 
-//     fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
-//         self.child.style_cascade()
-//     }
-
-//     fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
+//     fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
 //         &mut self.pressed_style
 //     }
-// }
 
-// impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pressable<E> {
-//     fn listeners(&mut self) -> &mut MouseEventListeners<S> {
-//         self.child.listeners()
+//     fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
+//         self.child.style_cascade()
 //     }
 // }
 
-// impl<E: Element + Identified + Styled> Element for Pressable<E> {
-//     type State = E::State;
-//     type FrameState = E::FrameState;
+// impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
+//     type PaintState = E::PaintState;
 
 //     fn layout(
 //         &mut self,
-//         state: &mut Self::State,
-//         cx: &mut ViewContext<Self::State>,
-//     ) -> Result<(crate::LayoutId, Self::FrameState)> {
-//         Ok(self.child.layout(state, cx)?)
+//         view: &mut V,
+//         cx: &mut ViewContext<V>,
+//     ) -> Result<(LayoutId, Self::PaintState)>
+//     where
+//         Self: Sized,
+//     {
+//         self.child.layout(view, cx)
 //     }
 
 //     fn paint(
 //         &mut self,
-//         bounds: Bounds<Pixels>,
-//         state: &mut Self::State,
-//         frame_state: &mut Self::FrameState,
-//         cx: &mut ViewContext<Self::State>,
-//     ) -> Result<()> {
-//         let pressed = bounds.contains_point(cx.mouse_position());
+//         view: &mut V,
+//         parent_origin: Vector2F,
+//         layout: &Layout,
+//         paint_state: &mut Self::PaintState,
+//         cx: &mut ViewContext<V>,
+//     ) where
+//         Self: Sized,
+//     {
 //         let slot = self.cascade_slot;
-//         let style = pressed.then_some(self.pressed_style.clone());
+//         let style = self.pressed.get().then_some(self.pressed_style.clone());
 //         self.style_cascade().set(slot, style);
-//         self.pressed.store(pressed, SeqCst);
 
-//         let hovered = self.pressed.clone();
-//         cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
-//             if phase == DispatchPhase::Capture {
-//                 if bounds.contains_point(event.position) != hovered.load(SeqCst) {
-//                     cx.notify();
-//                 }
-//             }
-//         });
-//         cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
-//             if phase == DispatchPhase::Capture {
-//                 if bounds.contains_point(event.position) != hovered.load(SeqCst) {
-//                     cx.notify();
+//         let pressed = self.pressed.clone();
+//         let bounds = layout.bounds + parent_origin;
+//         cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| {
+//             if event.is_down {
+//                 if bounds.contains_point(event.position) {
+//                     pressed.set(true);
+//                     cx.repaint();
 //                 }
+//             } else if pressed.get() {
+//                 pressed.set(false);
+//                 cx.repaint();
 //             }
 //         });
 
-//         self.child.paint(bounds, state, frame_state, cx)?;
-//         Ok(())
+//         self.child
+//             .paint(view, parent_origin, layout, paint_state, cx);
 //     }
 // }
 
-// impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
-//     type State = E::State;
+// impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
+//     fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
+//         self.child.interaction_handlers()
+//     }
+// }
 
-//     fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+// impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
+//     fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
 //         self.child.children_mut()
 //     }
 // }
 
-// // use crate::{
-// //     element::{AnyElement, Element, IntoElement, Layout, ParentElement},
-// //     interactive::{InteractionHandlers, Interactive},
-// //     style::{Style, StyleHelpers, Styleable},
-// //     ViewContext,
-// // };
-// // use anyhow::Result;
-// // use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
-// // use refineable::{CascadeSlot, Refineable, RefinementCascade};
-// // use smallvec::SmallVec;
-// // use std::{cell::Cell, rc::Rc};
-
-// // pub struct Pressable<E: Styleable> {
-// //     pressed: Rc<Cell<bool>>,
-// //     pressed_style: <E::Style as Refineable>::Refinement,
-// //     cascade_slot: CascadeSlot,
-// //     child: E,
-// // }
-
-// // pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
-// //     Pressable {
-// //         pressed: Rc::new(Cell::new(false)),
-// //         pressed_style: Default::default(),
-// //         cascade_slot: child.style_cascade().reserve(),
-// //         child,
-// //     }
-// // }
-
-// // impl<E: Styleable> Styleable for Pressable<E> {
-// //     type Style = E::Style;
-
-// //     fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
-// //         &mut self.pressed_style
-// //     }
-
-// //     fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
-// //         self.child.style_cascade()
-// //     }
-// // }
-
-// // impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
-// //     type PaintState = E::PaintState;
-
-// //     fn layout(
-// //         &mut self,
-// //         view: &mut V,
-// //         cx: &mut ViewContext<V>,
-// //     ) -> Result<(LayoutId, Self::PaintState)>
-// //     where
-// //         Self: Sized,
-// //     {
-// //         self.child.layout(view, cx)
-// //     }
-
-// //     fn paint(
-// //         &mut self,
-// //         view: &mut V,
-// //         parent_origin: Vector2F,
-// //         layout: &Layout,
-// //         paint_state: &mut Self::PaintState,
-// //         cx: &mut ViewContext<V>,
-// //     ) where
-// //         Self: Sized,
-// //     {
-// //         let slot = self.cascade_slot;
-// //         let style = self.pressed.get().then_some(self.pressed_style.clone());
-// //         self.style_cascade().set(slot, style);
-
-// //         let pressed = self.pressed.clone();
-// //         let bounds = layout.bounds + parent_origin;
-// //         cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| {
-// //             if event.is_down {
-// //                 if bounds.contains_point(event.position) {
-// //                     pressed.set(true);
-// //                     cx.repaint();
-// //                 }
-// //             } else if pressed.get() {
-// //                 pressed.set(false);
-// //                 cx.repaint();
-// //             }
-// //         });
-
-// //         self.child
-// //             .paint(view, parent_origin, layout, paint_state, cx);
-// //     }
-// // }
-
-// // impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
-// //     fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
-// //         self.child.interaction_handlers()
-// //     }
-// // }
-
-// // impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
-// //     fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
-// //         self.child.children_mut()
-// //     }
-// // }
-
-// // impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
-// //     type Element = Self;
-
-// //     fn into_element(self) -> Self::Element {
-// //         self
-// //     }
-// // }
+// impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
+//     type Element = Self;
+
+//     fn into_element(self) -> Self::Element {
+//         self
+//     }
+// }

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

@@ -1,6 +1,7 @@
-use crate::{Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled};
+use crate::{Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled};
 use refineable::RefinementCascade;
 use std::marker::PhantomData;
+use util::ResultExt;
 
 pub struct Svg<S> {
     path: Option<SharedString>,
@@ -23,41 +24,40 @@ impl<S> Svg<S> {
     }
 }
 
-impl<S: 'static> Element for Svg<S> {
-    type State = S;
-    type FrameState = ();
+impl<S: 'static + Send + Sync> Element for Svg<S> {
+    type ViewState = S;
+    type ElementState = ();
 
     fn layout(
         &mut self,
         _: &mut S,
+        _: Option<Self::ElementState>,
         cx: &mut crate::ViewContext<S>,
-    ) -> anyhow::Result<(LayoutId, Self::FrameState)>
+    ) -> (LayoutId, Self::ElementState)
     where
         Self: Sized,
     {
         let style = self.computed_style();
-        Ok((cx.request_layout(style, [])?, ()))
+        (cx.request_layout(style, []), ())
     }
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        _: &mut Self::State,
-        _: &mut Self::FrameState,
+        _: &mut Self::ViewState,
+        _: &mut Self::ElementState,
         cx: &mut crate::ViewContext<S>,
-    ) -> Result<()>
-    where
+    ) where
         Self: Sized,
     {
         let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
         if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
-            cx.paint_svg(bounds, path.clone(), fill_color)?;
+            cx.paint_svg(bounds, path.clone(), fill_color).log_err();
         }
-        Ok(())
     }
 }
 
-impl<S> Styled for Svg<S> {
+impl<S: 'static + Send + Sync> Styled for Svg<S> {
     type Style = Style;
 
     fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {

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

@@ -1,11 +1,11 @@
 use crate::{
-    AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Result, Size, ViewContext,
+    AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
 };
 use parking_lot::Mutex;
 use std::{marker::PhantomData, sync::Arc};
 use util::{arc_cow::ArcCow, ResultExt};
 
-impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
+impl<S: 'static + Send + Sync> IntoAnyElement<S> for ArcCow<'static, str> {
     fn into_any(self) -> AnyElement<S> {
         Text {
             text: self,
@@ -15,7 +15,7 @@ impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
     }
 }
 
-impl<V: 'static> IntoAnyElement<V> for &'static str {
+impl<V: 'static + Send + Sync> IntoAnyElement<V> for &'static str {
     fn into_any(self) -> AnyElement<V> {
         Text {
             text: ArcCow::from(self),
@@ -30,15 +30,16 @@ pub struct Text<S> {
     state_type: PhantomData<S>,
 }
 
-impl<S: 'static> Element for Text<S> {
-    type State = S;
-    type FrameState = Arc<Mutex<Option<TextFrameState>>>;
+impl<S: 'static + Send + Sync> Element for Text<S> {
+    type ViewState = S;
+    type ElementState = Arc<Mutex<Option<TextElementState>>>;
 
     fn layout(
         &mut self,
         _view: &mut S,
+        _element_state: Option<Self::ElementState>,
         cx: &mut ViewContext<S>,
-    ) -> Result<(LayoutId, Self::FrameState)> {
+    ) -> (LayoutId, Self::ElementState) {
         let text_system = cx.text_system().clone();
         let text_style = cx.text_style();
         let font_size = text_style.font_size * cx.rem_size();
@@ -46,11 +47,11 @@ impl<S: 'static> Element for Text<S> {
             .line_height
             .to_pixels(font_size.into(), cx.rem_size());
         let text = self.text.clone();
-        let frame_state = Arc::new(Mutex::new(None));
+        let element_state = Arc::new(Mutex::new(None));
 
         let rem_size = cx.rem_size();
         let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
-            let frame_state = frame_state.clone();
+            let element_state = element_state.clone();
             move |_, _| {
                 let Some(line_layout) = text_system
                     .layout_line(
@@ -68,7 +69,7 @@ impl<S: 'static> Element for Text<S> {
                     height: line_height,
                 };
 
-                frame_state.lock().replace(TextFrameState {
+                element_state.lock().replace(TextElementState {
                     line: Arc::new(line_layout),
                     line_height,
                 });
@@ -77,35 +78,32 @@ impl<S: 'static> Element for Text<S> {
             }
         });
 
-        Ok((layout_id?, frame_state))
+        (layout_id, element_state)
     }
 
     fn paint<'a>(
         &mut self,
         bounds: Bounds<Pixels>,
-        _: &mut Self::State,
-        frame_state: &mut Self::FrameState,
+        _: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
         cx: &mut ViewContext<S>,
-    ) -> Result<()> {
+    ) {
         let line;
         let line_height;
         {
-            let frame_state = frame_state.lock();
-            let frame_state = frame_state
+            let element_state = element_state.lock();
+            let element_state = element_state
                 .as_ref()
                 .expect("measurement has not been performed");
-            line = frame_state.line.clone();
-            line_height = frame_state.line_height;
+            line = element_state.line.clone();
+            line_height = element_state.line_height;
         }
 
-        // todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
-        line.paint(bounds, bounds, line_height, cx)?;
-
-        Ok(())
+        line.paint(bounds, bounds, line_height, cx).log_err();
     }
 }
 
-pub struct TextFrameState {
+pub struct TextElementState {
     line: Arc<Line>,
     line_height: Pixels,
 }

crates/gpui3/src/gpui3.rs 🔗

@@ -50,12 +50,15 @@ pub use view::*;
 pub use window::*;
 
 use std::{
+    any::Any,
     mem,
     ops::{Deref, DerefMut},
     sync::Arc,
 };
 use taffy::TaffyLayoutEngine;
 
+type AnyBox = Box<dyn Any + Send + Sync + 'static>;
+
 pub trait Context {
     type EntityContext<'a, 'w, T: 'static + Send + Sync>;
     type Result<T>;

crates/gpui3/src/styled.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{Hoverable, Refineable, RefinementCascade};
 
 pub trait Styled {
-    type Style: Refineable + Default;
+    type Style: 'static + Refineable + Send + Sync + Default;
 
     fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
     fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
@@ -12,7 +12,9 @@ pub trait Styled {
 
     fn hover(self) -> Hoverable<Self>
     where
-        Self: Sized,
+        Self: 'static + Sized + Send + Sync,
+        Self::Style: 'static + Refineable + Default + Send + Sync,
+        <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
     {
         Hoverable::new(self)
     }

crates/gpui3/src/taffy.rs 🔗

@@ -1,6 +1,4 @@
-use super::{
-    AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Result, Size, Style,
-};
+use super::{AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style};
 use collections::HashMap;
 use std::fmt::Debug;
 use taffy::{
@@ -16,6 +14,9 @@ pub struct TaffyLayoutEngine {
     absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>,
 }
 
+static EXPECT_MESSAGE: &'static str =
+    "we should avoid taffy layout errors by construction if possible";
+
 impl TaffyLayoutEngine {
     pub fn new() -> Self {
         TaffyLayoutEngine {
@@ -30,20 +31,21 @@ impl TaffyLayoutEngine {
         style: Style,
         rem_size: Pixels,
         children: &[LayoutId],
-    ) -> Result<LayoutId> {
+    ) -> LayoutId {
         let style = style.to_taffy(rem_size);
         if children.is_empty() {
-            Ok(self.taffy.new_leaf(style)?.into())
+            self.taffy.new_leaf(style).expect(EXPECT_MESSAGE).into()
         } else {
             let parent_id = self
                 .taffy
                 // This is safe because LayoutId is repr(transparent) to taffy::tree::NodeId.
-                .new_with_children(style, unsafe { std::mem::transmute(children) })?
+                .new_with_children(style, unsafe { std::mem::transmute(children) })
+                .expect(EXPECT_MESSAGE)
                 .into();
             for child_id in children {
                 self.children_to_parents.insert(*child_id, parent_id);
             }
-            Ok(parent_id)
+            parent_id
         }
     }
 
@@ -55,44 +57,40 @@ impl TaffyLayoutEngine {
             + Send
             + Sync
             + 'static,
-    ) -> Result<LayoutId> {
+    ) -> LayoutId {
         let style = style.to_taffy(rem_size);
 
         let measurable = Box::new(Measureable(measure)) as Box<dyn Measurable>;
-        Ok(self
-            .taffy
-            .new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))?
-            .into())
+        self.taffy
+            .new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))
+            .expect(EXPECT_MESSAGE)
+            .into()
     }
 
-    pub fn compute_layout(
-        &mut self,
-        id: LayoutId,
-        available_space: Size<AvailableSpace>,
-    ) -> Result<()> {
+    pub fn compute_layout(&mut self, id: LayoutId, available_space: Size<AvailableSpace>) {
         self.taffy
-            .compute_layout(id.into(), available_space.into())?;
-        Ok(())
+            .compute_layout(id.into(), available_space.into())
+            .expect(EXPECT_MESSAGE);
     }
 
-    pub fn layout_bounds(&mut self, id: LayoutId) -> Result<Bounds<Pixels>> {
+    pub fn layout_bounds(&mut self, id: LayoutId) -> Bounds<Pixels> {
         if let Some(layout) = self.absolute_layout_bounds.get(&id).cloned() {
-            return Ok(layout);
+            return layout;
         }
 
-        let layout = self.taffy.layout(id.into())?;
+        let layout = self.taffy.layout(id.into()).expect(EXPECT_MESSAGE);
         let mut bounds = Bounds {
             origin: layout.location.into(),
             size: layout.size.into(),
         };
 
         if let Some(parent_id) = self.children_to_parents.get(&id).copied() {
-            let parent_bounds = self.layout_bounds(parent_id)?;
+            let parent_bounds = self.layout_bounds(parent_id);
             bounds.origin += parent_bounds.origin;
         }
         self.absolute_layout_bounds.insert(id, bounds);
 
-        Ok(bounds)
+        bounds
     }
 }
 

crates/gpui3/src/view.rs 🔗

@@ -1,7 +1,7 @@
 use parking_lot::Mutex;
 
 use crate::{
-    AnyElement, Bounds, Element, Handle, IntoAnyElement, LayoutId, Pixels, Result, ViewContext,
+    AnyBox, AnyElement, Bounds, Element, Handle, IntoAnyElement, LayoutId, Pixels, ViewContext,
     WindowContext,
 };
 use std::{any::Any, marker::PhantomData, sync::Arc};
@@ -40,7 +40,7 @@ pub fn view<S, P, E>(
 where
     S: 'static + Send + Sync,
     P: 'static,
-    E: Element<State = S>,
+    E: Element<ViewState = S>,
 {
     View {
         state,
@@ -49,64 +49,55 @@ where
     }
 }
 
-impl<S: Send + Sync + 'static, P: Send + 'static> Element for View<S, P> {
-    type State = P;
-    type FrameState = AnyElement<S>;
+impl<S: 'static + Send + Sync, P: 'static + Send + Sync> Element for View<S, P> {
+    type ViewState = P;
+    type ElementState = AnyElement<S>;
 
     fn layout(
         &mut self,
-        _: &mut Self::State,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<(LayoutId, Self::FrameState)> {
+        _: &mut Self::ViewState,
+        _: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (LayoutId, Self::ElementState) {
         self.state.update(cx, |state, cx| {
             let mut element = (self.render)(state, cx);
-            let layout_id = element.layout(state, cx)?;
-            Ok((layout_id, element))
+            let layout_id = element.layout(state, cx);
+            (layout_id, element)
         })
     }
 
     fn paint(
         &mut self,
         _: Bounds<Pixels>,
-        _: &mut Self::State,
-        element: &mut Self::FrameState,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<()> {
+        _: &mut Self::ViewState,
+        element: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
         self.state
             .update(cx, |state, cx| element.paint(state, None, cx))
     }
 }
 
 trait ViewObject: Send + 'static {
-    fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
-    fn paint(
-        &mut self,
-        bounds: Bounds<Pixels>,
-        element: &mut dyn Any,
-        cx: &mut WindowContext,
-    ) -> Result<()>;
+    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
+    fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext);
 }
 
 impl<S: Send + Sync + 'static, P: Send + 'static> ViewObject for View<S, P> {
-    fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
+    fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
         self.state.update(cx, |state, cx| {
             let mut element = (self.render)(state, cx);
-            let layout_id = element.layout(state, cx)?;
-            let element = Box::new(element) as Box<dyn Any>;
-            Ok((layout_id, element))
+            let layout_id = element.layout(state, cx);
+            let element = Box::new(element) as AnyBox;
+            (layout_id, element)
         })
     }
 
-    fn paint(
-        &mut self,
-        _: Bounds<Pixels>,
-        element: &mut dyn Any,
-        cx: &mut WindowContext,
-    ) -> Result<()> {
+    fn paint(&mut self, _: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext) {
         self.state.update(cx, |state, cx| {
             let element = element.downcast_mut::<AnyElement<S>>().unwrap();
-            element.paint(state, None, cx)
-        })
+            element.paint(state, None, cx);
+        });
     }
 }
 
@@ -115,15 +106,16 @@ pub struct AnyView<S> {
     parent_state_type: PhantomData<S>,
 }
 
-impl<S: 'static> Element for AnyView<S> {
-    type State = ();
-    type FrameState = Box<dyn Any>;
+impl<S: 'static + Send + Sync> Element for AnyView<S> {
+    type ViewState = ();
+    type ElementState = AnyBox;
 
     fn layout(
         &mut self,
-        _: &mut Self::State,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<(LayoutId, Self::FrameState)> {
+        _: &mut Self::ViewState,
+        _: Option<Self::ElementState>,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) -> (LayoutId, Self::ElementState) {
         self.view.lock().layout(cx)
     }
 
@@ -131,9 +123,9 @@ impl<S: 'static> Element for AnyView<S> {
         &mut self,
         bounds: Bounds<Pixels>,
         _: &mut (),
-        element: &mut Box<dyn Any>,
-        cx: &mut ViewContext<Self::State>,
-    ) -> Result<()> {
+        element: &mut AnyBox,
+        cx: &mut ViewContext<Self::ViewState>,
+    ) {
         self.view.lock().paint(bounds, element.as_mut(), cx)
     }
 }

crates/gpui3/src/window.rs 🔗

@@ -1,12 +1,12 @@
 use crate::{
-    image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext,
-    AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId,
-    Edges, Effect, Element, ElementId, EntityId, Event, FontId, GlobalElementId, GlyphId, Handle,
-    Hsla, ImageData, IsZero, LayoutId, MainThread, MainThreadOnly, MonochromeSprite,
-    MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad,
-    Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
-    SharedString, Size, Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
-    WindowOptions, SUBPIXEL_VARIANTS,
+    px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
+    Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
+    Event, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread,
+    MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow,
+    Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
+    RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style,
+    TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
+    SUBPIXEL_VARIANTS,
 };
 use anyhow::Result;
 use collections::HashMap;
@@ -21,7 +21,7 @@ use std::{
     mem,
     sync::Arc,
 };
-use util::ResultExt;
+use util::{arc_cow::ArcCow, ResultExt};
 
 #[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
 pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
@@ -52,6 +52,8 @@ pub struct Window {
     layout_engine: TaffyLayoutEngine,
     pub(crate) root_view: Option<AnyView<()>>,
     pub(crate) element_id_stack: GlobalElementId,
+    prev_element_states: HashMap<GlobalElementId, AnyBox>,
+    element_states: HashMap<GlobalElementId, AnyBox>,
     z_index_stack: StackingOrder,
     content_mask_stack: Vec<ContentMask<Pixels>>,
     mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
@@ -114,6 +116,8 @@ impl Window {
             layout_engine: TaffyLayoutEngine::new(),
             root_view: None,
             element_id_stack: GlobalElementId::default(),
+            prev_element_states: HashMap::default(),
+            element_states: HashMap::default(),
             z_index_stack: StackingOrder(SmallVec::new()),
             content_mask_stack: Vec::new(),
             mouse_event_handlers: HashMap::default(),
@@ -147,7 +151,7 @@ impl ContentMask<Pixels> {
 
 pub struct WindowContext<'a, 'w> {
     app: Reference<'a, AppContext>,
-    window: Reference<'w, Window>,
+    pub(crate) window: Reference<'w, Window>,
 }
 
 impl<'a, 'w> WindowContext<'a, 'w> {
@@ -242,7 +246,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         &mut self,
         style: Style,
         children: impl IntoIterator<Item = LayoutId>,
-    ) -> Result<LayoutId> {
+    ) -> LayoutId {
         self.app.layout_id_buffer.clear();
         self.app.layout_id_buffer.extend(children.into_iter());
         let rem_size = self.rem_size();
@@ -259,18 +263,17 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         style: Style,
         rem_size: Pixels,
         measure: F,
-    ) -> Result<LayoutId> {
+    ) -> LayoutId {
         self.window
             .layout_engine
             .request_measured_layout(style, rem_size, measure)
     }
 
-    pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Result<Bounds<Pixels>> {
-        Ok(self
-            .window
+    pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
+        self.window
             .layout_engine
             .layout_bounds(layout_id)
-            .map(Into::into)?)
+            .map(Into::into)
     }
 
     pub fn scale_factor(&self) -> f32 {
@@ -586,27 +589,25 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         Ok(())
     }
 
-    pub(crate) fn draw(&mut self) -> Result<()> {
+    pub(crate) fn draw(&mut self) {
         let unit_entity = self.unit_entity.clone();
         self.update_entity(&unit_entity, |view, cx| {
-            cx.window
-                .mouse_event_handlers
-                .values_mut()
-                .for_each(Vec::clear);
+            cx.start_frame();
 
             let mut root_view = cx.window.root_view.take().unwrap();
-            let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
-            let available_space = cx.window.content_size.map(Into::into);
 
-            cx.window
-                .layout_engine
-                .compute_layout(root_layout_id, available_space)?;
-            let layout = cx.window.layout_engine.layout_bounds(root_layout_id)?;
+            if let Some(element_id) = root_view.element_id() {
+                cx.with_element_state(element_id, |element_state, cx| {
+                    let element_state = draw_with_element_state(&mut root_view, element_state, cx);
+                    ((), element_state)
+                });
+            } else {
+                draw_with_element_state(&mut root_view, None, cx);
+            };
 
-            root_view.paint(layout, &mut (), &mut frame_state, cx)?;
             cx.window.root_view = Some(root_view);
-            let scene = cx.window.scene_builder.build();
 
+            let scene = cx.window.scene_builder.build();
             cx.run_on_main(view, |_, cx| {
                 cx.window
                     .platform_window
@@ -615,9 +616,38 @@ impl<'a, 'w> WindowContext<'a, 'w> {
                 cx.window.dirty = false;
             })
             .detach();
+        });
 
-            Ok(())
-        })
+        fn draw_with_element_state(
+            root_view: &mut AnyView<()>,
+            element_state: Option<AnyBox>,
+            cx: &mut ViewContext<()>,
+        ) -> AnyBox {
+            let (layout_id, mut element_state) = root_view.layout(&mut (), element_state, cx);
+            let available_space = cx.window.content_size.map(Into::into);
+            cx.window
+                .layout_engine
+                .compute_layout(layout_id, available_space);
+            let bounds = cx.window.layout_engine.layout_bounds(layout_id);
+            root_view.paint(bounds, &mut (), &mut element_state, cx);
+            element_state
+        }
+    }
+
+    fn start_frame(&mut self) {
+        // Make the current element states the previous, and then clear the current.
+        // The empty element states map will be populated for any element states we
+        // reference during the upcoming frame.
+        let window = &mut *self.window;
+        mem::swap(&mut window.element_states, &mut window.prev_element_states);
+        self.window.element_states.clear();
+
+        // Clear mouse event listeners, because elements add new element listeners
+        // when the upcoming frame is painted.
+        self.window
+            .mouse_event_handlers
+            .values_mut()
+            .for_each(Vec::clear);
     }
 
     fn dispatch_event(&mut self, event: Event) -> bool {
@@ -753,6 +783,42 @@ pub trait BorrowWindow: BorrowAppContext {
         result
     }
 
+    fn with_element_state<S: 'static + Send + Sync, R>(
+        &mut self,
+        id: ElementId,
+        f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
+    ) -> R {
+        self.window_mut().element_id_stack.push(id);
+        let global_id = self.window_mut().element_id_stack.clone();
+
+        if let Some(any) = self
+            .window_mut()
+            .element_states
+            .remove(&global_id)
+            .or_else(|| self.window_mut().prev_element_states.remove(&global_id))
+        {
+            // Using the extra inner option to avoid needing to reallocate a new box.
+            let mut state_box = any
+                .downcast::<Option<S>>()
+                .expect("invalid element state type for id");
+            let state = state_box
+                .take()
+                .expect("element state is already on the stack");
+            let (result, state) = f(Some(state), self);
+            state_box.replace(state);
+            self.window_mut()
+                .element_states
+                .insert(global_id, state_box);
+            result
+        } else {
+            let (result, state) = f(None, self);
+            self.window_mut()
+                .element_states
+                .insert(global_id, Box::new(Some(state)));
+            result
+        }
+    }
+
     fn content_mask(&self) -> ContentMask<Pixels> {
         self.window()
             .content_mask_stack
@@ -791,26 +857,6 @@ impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
     fn app_mut(&mut self) -> &mut AppContext {
         &mut *self.window_cx.app
     }
-
-    fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
-    where
-        F: FnOnce(&mut Self) -> R,
-    {
-        self.window_cx.app.push_text_style(style);
-        let result = f(self);
-        self.window_cx.app.pop_text_style();
-        result
-    }
-
-    fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
-    where
-        F: FnOnce(&mut Self) -> R,
-    {
-        self.window_cx.app.push_state(state);
-        let result = f(self);
-        self.window_cx.app.pop_state::<T>();
-        result
-    }
 }
 
 impl<S> BorrowWindow for ViewContext<'_, '_, S> {
@@ -1012,3 +1058,6 @@ impl From<SmallVec<[u32; 16]>> for StackingOrder {
         StackingOrder(small_vec)
     }
 }
+
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+pub struct ElementId(ArcCow<'static, [u8]>);

crates/storybook2/src/collab_panel.rs 🔗

@@ -22,7 +22,7 @@ impl CollabPanel {
 }
 
 impl CollabPanel {
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
         let theme = theme(cx);
 
         // Panel
@@ -123,7 +123,7 @@ impl CollabPanel {
         label: impl IntoAnyElement<Self>,
         expanded: bool,
         theme: &Theme,
-    ) -> impl Element<State = Self> {
+    ) -> impl Element<ViewState = Self> {
         div()
             .h_7()
             .px_2()
@@ -153,7 +153,7 @@ impl CollabPanel {
         avatar_uri: impl Into<SharedString>,
         label: impl IntoAnyElement<Self>,
         theme: &Theme,
-    ) -> impl Element<State = Self> {
+    ) -> impl Element<ViewState = Self> {
         div()
             .h_7()
             .px_2()

crates/storybook2/src/theme.rs 🔗

@@ -129,10 +129,10 @@ where
     deserializer.deserialize_map(SyntaxVisitor)
 }
 
-pub fn themed<E, F>(theme: Theme, cx: &mut ViewContext<E::State>, build_child: F) -> Themed<E>
+pub fn themed<E, F>(theme: Theme, cx: &mut ViewContext<E::ViewState>, build_child: F) -> Themed<E>
 where
     E: Element,
-    F: FnOnce(&mut ViewContext<E::State>) -> E,
+    F: FnOnce(&mut ViewContext<E::ViewState>) -> E,
 {
     let child = cx.with_state(theme.clone(), |cx| build_child(cx));
     Themed { theme, child }
@@ -144,14 +144,14 @@ pub struct Themed<E> {
 }
 
 impl<E: Element> Element for Themed<E> {
-    type State = E::State;
-    type FrameState = E::FrameState;
+    type ViewState = E::ViewState;
+    type ElementState = E::ElementState;
 
     fn layout(
         &mut self,
-        state: &mut E::State,
-        cx: &mut ViewContext<E::State>,
-    ) -> anyhow::Result<(LayoutId, Self::FrameState)>
+        state: &mut E::ViewState,
+        cx: &mut ViewContext<E::ViewState>,
+    ) -> anyhow::Result<(LayoutId, Self::ElementState)>
     where
         Self: Sized,
     {
@@ -161,9 +161,9 @@ impl<E: Element> Element for Themed<E> {
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        state: &mut Self::State,
-        frame_state: &mut Self::FrameState,
-        cx: &mut ViewContext<Self::State>,
+        state: &mut Self::ViewState,
+        frame_state: &mut Self::ElementState,
+        cx: &mut ViewContext<Self::ViewState>,
     ) -> Result<()>
     where
         Self: Sized,

crates/storybook2/src/workspace.rs 🔗

@@ -25,7 +25,7 @@ impl Workspace {
         }
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
         themed(rose_pine_dawn(), cx, |cx| {
             let theme = theme(cx);
             div()
@@ -57,7 +57,7 @@ impl Workspace {
 
 struct Titlebar;
 
-pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
+pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
     let ref mut this = Titlebar;
     let theme = theme(cx);
     div()
@@ -75,7 +75,7 @@ impl Titlebar {
     fn render<V: 'static + Send + Sync>(
         &mut self,
         cx: &mut ViewContext<V>,
-    ) -> impl Element<State = V> {
+    ) -> impl Element<ViewState = V> {
         let theme = theme(cx);
         div()
             .flex()
@@ -91,7 +91,7 @@ impl Titlebar {
     fn left_group<S: 'static + Send + Sync>(
         &mut self,
         cx: &mut ViewContext<S>,
-    ) -> impl Element<State = S> {
+    ) -> impl Element<ViewState = S> {
         let theme = theme(cx);
         div()
             .flex()
@@ -174,7 +174,7 @@ impl Titlebar {
     fn right_group<S: 'static + Send + Sync>(
         &mut self,
         cx: &mut ViewContext<S>,
-    ) -> impl Element<State = S> {
+    ) -> impl Element<ViewState = S> {
         let theme = theme(cx);
         div()
             .flex()
@@ -306,7 +306,9 @@ mod statusbar {
 
     use super::*;
 
-    pub fn statusbar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
+    pub fn statusbar<S: 'static + Send + Sync>(
+        cx: &mut ViewContext<S>,
+    ) -> impl Element<ViewState = S> {
         let theme = theme(cx);
         div()
             .flex()
@@ -319,7 +321,9 @@ mod statusbar {
         // .child(right_group(cx))
     }
 
-    fn left_group<V: 'static + Send + Sync>(cx: &mut ViewContext<V>) -> impl Element<State = V> {
+    fn left_group<V: 'static + Send + Sync>(
+        cx: &mut ViewContext<V>,
+    ) -> impl Element<ViewState = V> {
         let theme = theme(cx);
         div()
             .flex()
@@ -416,7 +420,9 @@ mod statusbar {
             )
     }
 
-    fn right_group<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
+    fn right_group<S: 'static + Send + Sync>(
+        cx: &mut ViewContext<S>,
+    ) -> impl Element<ViewState = S> {
         let theme = theme(cx);
         div()
             .flex()