WIP

Nathan Sobo created

Change summary

crates/gpui3/src/element.rs             |  7 ++++-
crates/gpui3/src/elements/identified.rs | 27 +++++++++++++++++++++++
crates/gpui3/src/elements/pressable.rs  | 14 ++++++++----
crates/gpui3/src/styled.rs              | 16 ++++++++------
crates/gpui3/src/window.rs              | 18 ++++++++++++++++
crates/storybook2/src/collab_panel.rs   | 14 ++++++++----
crates/storybook2/src/theme.rs          | 30 +++++++-------------------
crates/util/src/arc_cow.rs              | 12 ++++++++++
8 files changed, 96 insertions(+), 42 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -25,11 +25,14 @@ pub trait Element: 'static + Send + Sync {
         cx: &mut ViewContext<Self::ViewState>,
     );
 
-    fn id(self, id: ElementId) -> Identified<Self>
+    fn id(self, id: impl Into<ElementId>) -> Identified<Self>
     where
         Self: Sized,
     {
-        Identified { element: self, id }
+        Identified {
+            element: self,
+            id: id.into(),
+        }
     }
 }
 

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

@@ -1,4 +1,10 @@
-use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext};
+use refineable::{Refineable, RefinementCascade};
+use smallvec::SmallVec;
+
+use crate::{
+    AnyElement, BorrowWindow, Bounds, Element, ElementId, LayoutId, ParentElement, StatefulElement,
+    Styled, ViewContext,
+};
 
 pub struct Identified<E> {
     pub(crate) element: E,
@@ -36,3 +42,22 @@ impl<E: Element> Element for Identified<E> {
 }
 
 impl<E: Element> StatefulElement for Identified<E> {}
+
+impl<E: Styled> Styled for Identified<E> {
+    type Style = E::Style;
+
+    fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
+        self.element.style_cascade()
+    }
+    fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
+        self.element.declared_style()
+    }
+}
+
+impl<E: ParentElement> ParentElement for Identified<E> {
+    type State = E::State;
+
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+        self.element.children_mut()
+    }
+}

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

@@ -92,25 +92,29 @@ where
         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());
+        let slot = self.cascade_slot;
         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) {
+                if bounds.contains_point(event.position) {
+                    dbg!("pressed");
+                    pressed.store(true, SeqCst);
                     cx.notify();
                 }
             }
         });
-        let hovered = element_state.pressed.clone();
-        cx.on_mouse_event(move |_, event: &MouseUpEvent, phase, cx| {
+        let pressed = element_state.pressed.clone();
+        cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
             if phase == DispatchPhase::Capture {
-                if bounds.contains_point(event.position) != hovered.load(SeqCst) {
+                if pressed.load(SeqCst) {
+                    dbg!("released");
+                    pressed.store(false, SeqCst);
                     cx.notify();
                 }
             }

crates/gpui3/src/styled.rs 🔗

@@ -1,4 +1,4 @@
-use crate::{Hoverable, Refineable, RefinementCascade};
+use crate::{Hoverable, Pressable, Refineable, RefinementCascade};
 
 pub trait Styled {
     type Style: 'static + Refineable + Send + Sync + Default;
@@ -19,10 +19,12 @@ pub trait Styled {
         Hoverable::new(self)
     }
 
-    // fn active(self) -> Pressable<Self>
-    // where
-    //     Self: Sized,
-    // {
-    //     pressable(self)
-    // }
+    fn active(self) -> Pressable<Self>
+    where
+        Self: 'static + Sized + Send + Sync,
+        Self::Style: 'static + Refineable + Default + Send + Sync,
+        <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+    {
+        Pressable::new(self)
+    }
 }

crates/gpui3/src/window.rs 🔗

@@ -1061,3 +1061,21 @@ impl From<SmallVec<[u32; 16]>> for StackingOrder {
 
 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub struct ElementId(ArcCow<'static, [u8]>);
+
+impl From<usize> for ElementId {
+    fn from(id: usize) -> Self {
+        Self(id.to_ne_bytes().to_vec().into())
+    }
+}
+
+impl From<i32> for ElementId {
+    fn from(id: i32) -> Self {
+        Self(id.to_ne_bytes().to_vec().into())
+    }
+}
+
+impl From<&'static str> for ElementId {
+    fn from(id: &'static str) -> Self {
+        Self(id.into())
+    }
+}

crates/storybook2/src/collab_panel.rs 🔗

@@ -1,7 +1,7 @@
 use crate::theme::{theme, Theme};
 use gpui3::{
-    div, img, svg, view, AppContext, Context, Element, Interactive, IntoAnyElement, MouseButton,
-    ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
+    div, img, svg, view, AppContext, Context, Element, ElementId, Interactive, IntoAnyElement,
+    MouseButton, ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
     WindowContext,
 };
 
@@ -55,7 +55,7 @@ impl CollabPanel {
                             //:: https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
                             // .group()
                             // List Section Header
-                            .child(self.list_section_header("#CRDB 🗃️", true, theme))
+                            .child(self.list_section_header(0, "#CRDB 🗃️", true, theme))
                             // List Item Large
                             .child(self.list_item(
                                 "http://github.com/maxbrunsfeld.png?s=50",
@@ -68,14 +68,14 @@ impl CollabPanel {
                             .py_2()
                             .flex()
                             .flex_col()
-                            .child(self.list_section_header("CHANNELS", true, theme)),
+                            .child(self.list_section_header(1, "CHANNELS", true, theme)),
                     )
                     .child(
                         div()
                             .py_2()
                             .flex()
                             .flex_col()
-                            .child(self.list_section_header("CONTACTS", true, theme))
+                            .child(self.list_section_header(2, "CONTACTS", true, theme))
                             .children(
                                 std::iter::repeat_with(|| {
                                     vec![
@@ -120,11 +120,13 @@ impl CollabPanel {
 
     fn list_section_header(
         &self,
+        id: impl Into<ElementId>,
         label: impl IntoAnyElement<Self>,
         expanded: bool,
         theme: &Theme,
     ) -> impl Element<ViewState = Self> {
         div()
+            .id(id)
             .h_7()
             .px_2()
             .flex()
@@ -132,6 +134,8 @@ impl CollabPanel {
             .items_center()
             .hover()
             .fill(theme.lowest.base.active.background)
+            .active()
+            .fill(theme.highest.accent.default.background)
             .child(div().flex().gap_1().text_sm().child(label))
             .child(
                 div().flex().h_full().gap_1().items_center().child(

crates/storybook2/src/theme.rs 🔗

@@ -150,12 +150,15 @@ impl<E: Element> Element for Themed<E> {
     fn layout(
         &mut self,
         state: &mut E::ViewState,
+        element_state: Option<Self::ElementState>,
         cx: &mut ViewContext<E::ViewState>,
-    ) -> anyhow::Result<(LayoutId, Self::ElementState)>
+    ) -> (LayoutId, Self::ElementState)
     where
         Self: Sized,
     {
-        cx.with_state(self.theme.clone(), |cx| self.child.layout(state, cx))
+        cx.with_state(self.theme.clone(), |cx| {
+            self.child.layout(state, element_state, cx)
+        })
     }
 
     fn paint(
@@ -164,32 +167,15 @@ impl<E: Element> Element for Themed<E> {
         state: &mut Self::ViewState,
         frame_state: &mut Self::ElementState,
         cx: &mut ViewContext<Self::ViewState>,
-    ) -> Result<()>
-    where
+    ) where
         Self: Sized,
     {
         cx.with_state(self.theme.clone(), |cx| {
-            self.child.paint(bounds, state, frame_state, cx)
-        })
+            self.child.paint(bounds, state, frame_state, cx);
+        });
     }
 }
 
-// fn preferred_theme<V: 'static>(cx: &AppContext) -> Theme {
-//     settings::get::<ThemeSettings>(cx)
-//         .theme
-//         .deserialized_base_theme
-//         .lock()
-//         .get_or_insert_with(|| {
-//             let theme: Theme =
-//                 serde_json::from_value(settings::get::<ThemeSettings>(cx).theme.base_theme.clone())
-//                     .unwrap();
-//             Box::new(theme)
-//         })
-//         .downcast_ref::<Theme>()
-//         .unwrap()
-//         .clone()
-// }
-
 pub fn theme<'a>(cx: &'a WindowContext) -> &'a Theme {
     cx.state()
 }

crates/util/src/arc_cow.rs 🔗

@@ -57,6 +57,18 @@ impl<'a> From<Cow<'a, str>> for ArcCow<'a, str> {
     }
 }
 
+impl<T> From<Vec<T>> for ArcCow<'_, [T]> {
+    fn from(vec: Vec<T>) -> Self {
+        ArcCow::Owned(Arc::from(vec))
+    }
+}
+
+impl<'a> From<&'a str> for ArcCow<'a, [u8]> {
+    fn from(s: &'a str) -> Self {
+        ArcCow::Borrowed(s.as_bytes())
+    }
+}
+
 impl<'a, T: ?Sized + ToOwned> std::borrow::Borrow<T> for ArcCow<'a, T> {
     fn borrow(&self) -> &T {
         match self {