WIP

Nathan Sobo created

Change summary

crates/gpui/playground/src/adapter.rs       |  2 
crates/gpui/playground/src/components.rs    | 10 +-
crates/gpui/playground/src/element.rs       | 61 +++++++------
crates/gpui/playground/src/paint_context.rs | 95 +++++++++++++++++++++++
crates/gpui/playground/src/playground.rs    |  3 
crates/gpui/src/app.rs                      |  6 
crates/gpui/src/scene.rs                    |  1 
crates/gpui/src/scene/region.rs             |  7 +
8 files changed, 147 insertions(+), 38 deletions(-)

Detailed changes

crates/gpui/playground/src/adapter.rs 🔗

@@ -38,7 +38,7 @@ impl<V: 'static> gpui::Element<V> for Adapter<V> {
         legacy_cx: &mut gpui::PaintContext<V>,
     ) -> Self::PaintState {
         legacy_cx.push_layout_engine(layout_engine.take().unwrap());
-        let mut cx = PaintContext { legacy_cx, scene };
+        let mut cx = PaintContext::new(legacy_cx, scene);
         self.0.paint(view, &mut cx).log_err();
         *layout_engine = legacy_cx.pop_layout_engine();
         debug_assert!(layout_engine.is_some());

crates/gpui/playground/src/components.rs 🔗

@@ -9,7 +9,7 @@ use playground_macros::Element;
 use std::{marker::PhantomData, rc::Rc};
 
 struct ButtonHandlers<V, D> {
-    click: Option<Rc<dyn Fn(&mut V, &D)>>,
+    click: Option<Rc<dyn Fn(&mut V, &D, &mut ViewContext<V>)>>,
 }
 
 impl<V, D> Default for ButtonHandlers<V, D> {
@@ -67,10 +67,10 @@ impl<V: 'static, D: 'static> Button<V, D> {
         self
     }
 
-    pub fn click(self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
+    pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
         let data = self.data.clone();
-        Element::click(self, move |view, _| {
-            handler(view, data.as_ref());
+        Element::left_click(self, move |view, _, cx| {
+            handler(view, data.as_ref(), cx);
         })
     }
 }
@@ -89,7 +89,7 @@ impl<V: 'static, D: 'static> Button<V, D> {
 
         if let Some(handler) = self.handlers.click.clone() {
             let data = self.data.clone();
-            button.click(move |view, event| handler(view, data.as_ref()))
+            button.left_click(move |view, event, cx| handler(view, data.as_ref(), cx))
         } else {
             button
         }

crates/gpui/playground/src/element.rs 🔗

@@ -4,38 +4,18 @@ use crate::{
     style::{Display, ElementStyle, Fill, Overflow, Position},
 };
 use anyhow::Result;
-use derive_more::{Deref, DerefMut};
 pub use gpui::LayoutContext;
 use gpui::{
     geometry::{DefinedLength, Length},
+    platform::MouseButton,
     scene::MouseClick,
-    EngineLayout, PaintContext as LegacyPaintContext, RenderContext,
+    EngineLayout, RenderContext, ViewContext, WindowContext,
 };
 use playground_macros::tailwind_lengths;
 use std::{any::Any, rc::Rc};
-pub use taffy::tree::NodeId;
-
-#[derive(Deref, DerefMut)]
-pub struct PaintContext<'a, 'b, 'c, 'd, V> {
-    #[deref]
-    #[deref_mut]
-    pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
-    pub(crate) scene: &'d mut gpui::SceneBuilder,
-}
 
-impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
-    fn text_style(&self) -> gpui::fonts::TextStyle {
-        self.legacy_cx.text_style()
-    }
-
-    fn push_text_style(&mut self, style: gpui::fonts::TextStyle) {
-        self.legacy_cx.push_text_style(style)
-    }
-
-    fn pop_text_style(&mut self) {
-        self.legacy_cx.pop_text_style()
-    }
-}
+pub use crate::paint_context::PaintContext;
+pub use taffy::tree::NodeId;
 
 pub struct Layout<'a, E: ?Sized> {
     pub from_engine: EngineLayout,
@@ -43,7 +23,7 @@ pub struct Layout<'a, E: ?Sized> {
 }
 
 pub struct ElementHandlers<V> {
-    click: Option<Rc<dyn Fn(&mut V, MouseClick)>>,
+    click: Option<Rc<dyn Fn(&mut V, MouseClick, &mut WindowContext, usize)>>,
 }
 
 pub struct ElementMetadata<V> {
@@ -99,12 +79,35 @@ pub trait Element<V: 'static>: 'static {
         Adapter(self.into_any())
     }
 
-    fn click(mut self, handler: impl Fn(&mut V, MouseClick) + 'static) -> Self
+    fn left_click(self, handler: impl Fn(&mut V, MouseClick, &mut ViewContext<V>) + 'static) -> Self
     where
         Self: Sized,
     {
-        self.handlers_mut().click = Some(Rc::new(move |view, event| {
-            handler(view, event);
+        self.click(MouseButton::Left, handler)
+    }
+
+    fn right_click(
+        self,
+        handler: impl Fn(&mut V, MouseClick, &mut ViewContext<V>) + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.click(MouseButton::Right, handler)
+    }
+
+    fn click(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut V, MouseClick, &mut ViewContext<V>) + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.handlers_mut().click = Some(Rc::new(move |view, event, window_cx, view_id| {
+            if event.button == button {
+                handler(view, event, &mut ViewContext::mutable(window_cx, view_id));
+            }
         }));
         self
     }
@@ -423,6 +426,8 @@ impl<V> AnyElement<V> {
             from_element: element_layout.as_mut(),
         };
 
+        if let Some(click_handler) = self.element.handlers_mut().click.clone() {}
+
         self.element.paint(layout, view, cx)?;
         if pushed_text_style {
             cx.pop_text_style();

crates/gpui/playground/src/paint_context.rs 🔗

@@ -0,0 +1,95 @@
+use std::{
+    any::{Any, TypeId},
+    collections::BTreeSet,
+    rc::Rc,
+};
+
+use derive_more::{Deref, DerefMut};
+use gpui::{geometry::rect::RectF, EventContext, RenderContext, ViewContext, WindowContext};
+pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
+pub use taffy::tree::NodeId;
+
+#[derive(Deref, DerefMut)]
+pub struct PaintContext<'a, 'b, 'c, 'd, V> {
+    #[deref]
+    #[deref_mut]
+    pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
+    pub(crate) scene: &'d mut gpui::SceneBuilder,
+    regions: BTreeSet<InteractiveRegion>,
+}
+
+impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
+    fn text_style(&self) -> gpui::fonts::TextStyle {
+        self.legacy_cx.text_style()
+    }
+
+    fn push_text_style(&mut self, style: gpui::fonts::TextStyle) {
+        self.legacy_cx.push_text_style(style)
+    }
+
+    fn pop_text_style(&mut self) {
+        self.legacy_cx.pop_text_style()
+    }
+}
+
+impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
+    pub fn new(
+        legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
+        scene: &'d mut gpui::SceneBuilder,
+    ) -> Self {
+        Self {
+            legacy_cx,
+            scene,
+            regions: BTreeSet::new(),
+        }
+    }
+
+    pub fn paint_interactive<E: 'static>(
+        &mut self,
+        order: u32,
+        bounds: RectF,
+        handler: impl Fn(&mut V, E, &mut EventContext<V>) + 'static,
+    ) {
+        self.regions.insert(InteractiveRegion {
+            order,
+            bounds,
+            event_handler: Rc::new(move |view, event, window_cx, view_id| {
+                let mut cx = ViewContext::mutable(window_cx, view_id);
+                let mut cx = EventContext::new(&mut cx);
+                handler(
+                    view.downcast_mut().unwrap(),
+                    *event.downcast().unwrap(),
+                    &mut cx,
+                )
+            }),
+            event_type: TypeId::of::<E>(),
+        });
+    }
+}
+
+struct InteractiveRegion {
+    order: u32,
+    bounds: RectF,
+    event_handler: Rc<dyn Fn(&mut dyn Any, Box<dyn Any>, &mut WindowContext, usize)>,
+    event_type: TypeId,
+}
+
+impl Eq for InteractiveRegion {}
+
+impl PartialEq for InteractiveRegion {
+    fn eq(&self, other: &Self) -> bool {
+        self.order == other.order
+    }
+}
+
+impl PartialOrd for InteractiveRegion {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        todo!()
+    }
+}
+
+impl Ord for InteractiveRegion {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.order.cmp(&other.order)
+    }
+}

crates/gpui/playground/src/playground.rs 🔗

@@ -18,6 +18,7 @@ mod color;
 mod components;
 mod element;
 mod frame;
+mod paint_context;
 mod style;
 mod text;
 mod themes;
@@ -48,7 +49,7 @@ fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
         .h_full()
         .w_half()
         .fill(theme.success(0.5))
-        .child(button().label("Hello").click(|_, _| (println!("hey!"))))
+        .child(button().label("Hello").click(|_, _, _| (println!("hey!"))))
 }
 
 //     todo!()

crates/gpui/src/app.rs 🔗

@@ -2879,7 +2879,7 @@ impl<'a, 'b, V> DerefMut for ViewContext<'a, 'b, V> {
 }
 
 impl<'a, 'b, V: 'static> ViewContext<'a, 'b, V> {
-    pub(crate) fn mutable(window_context: &'b mut WindowContext<'a>, view_id: usize) -> Self {
+    pub fn mutable(window_context: &'b mut WindowContext<'a>, view_id: usize) -> Self {
         Self {
             window_context: Reference::Mutable(window_context),
             view_id,
@@ -2887,7 +2887,7 @@ impl<'a, 'b, V: 'static> ViewContext<'a, 'b, V> {
         }
     }
 
-    pub(crate) fn immutable(window_context: &'b WindowContext<'a>, view_id: usize) -> Self {
+    pub fn immutable(window_context: &'b WindowContext<'a>, view_id: usize) -> Self {
         Self {
             window_context: Reference::Immutable(window_context),
             view_id,
@@ -3618,7 +3618,7 @@ pub struct EventContext<'a, 'b, 'c, V> {
 }
 
 impl<'a, 'b, 'c, V> EventContext<'a, 'b, 'c, V> {
-    pub(crate) fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
+    pub fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
         EventContext {
             view_context,
             handled: true,

crates/gpui/src/scene.rs 🔗

@@ -1,5 +1,6 @@
 mod mouse_event;
 mod mouse_region;
+mod region;
 
 #[cfg(debug_assertions)]
 use collections::HashSet;

crates/gpui/src/scene/region.rs 🔗

@@ -0,0 +1,7 @@
+// use crate::geometry::rect::RectF;
+// use crate::WindowContext;
+
+// struct Region {
+//     pub bounds: RectF,
+//     pub click_handler: Option<Rc<dyn Fn(&dyn Any, MouseEvent, &mut WindowContext)>>,
+// }