WIP

Antonio Scandurra created

Change summary

crates/gpui2/src/app.rs         |  5 +
crates/gpui2/src/element.rs     |  2 
crates/gpui2/src/interactive.rs | 15 +++++
crates/gpui2/src/view.rs        | 79 ++++++++++++++--------------------
crates/gpui2/src/window.rs      | 13 +++--
5 files changed, 57 insertions(+), 57 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -15,7 +15,7 @@ pub use test_context::*;
 use crate::{
     current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource,
     ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId,
-    KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point,
+    KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point, Render,
     SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement,
     TextSystem, View, Window, WindowContext, WindowHandle, WindowId,
 };
@@ -815,7 +815,7 @@ impl MainThread<AppContext> {
     /// Opens a new window with the given option and the root view returned by the given function.
     /// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
     /// functionality.
-    pub fn open_window<V: 'static>(
+    pub fn open_window<V: Render>(
         &mut self,
         options: crate::WindowOptions,
         build_root_view: impl FnOnce(&mut WindowContext) -> View<V> + Send + 'static,
@@ -898,6 +898,7 @@ impl<G: 'static> DerefMut for GlobalLease<G> {
 /// Contains state associated with an active drag operation, started by dragging an element
 /// within the window or by dragging into the app from the underlying platform.
 pub(crate) struct AnyDrag {
+    pub render: Box<dyn FnOnce(&mut WindowContext) -> AnyElement<()>>,
     pub drag_handle_view: Option<AnyView>,
     pub cursor_offset: Point<Pixels>,
     pub state: AnyBox,

crates/gpui2/src/element.rs 🔗

@@ -4,7 +4,7 @@ pub(crate) use smallvec::SmallVec;
 use std::{any::Any, mem};
 
 pub trait Element<V: 'static> {
-    type ElementState: 'static;
+    type ElementState: 'static + Send;
 
     fn id(&self) -> Option<ElementId>;
 

crates/gpui2/src/interactive.rs 🔗

@@ -333,12 +333,19 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
             Some(Box::new(move |view_state, cursor_offset, cx| {
                 let drag = listener(view_state, cx);
                 let drag_handle_view = Some(
-                    View::for_handle(cx.model().upgrade().unwrap(), move |view_state, cx| {
-                        (drag.render_drag_handle)(view_state, cx)
+                    cx.build_view(|cx| DragView {
+                        model: cx.model().upgrade().unwrap(),
+                        drag,
                     })
                     .into_any(),
                 );
                 AnyDrag {
+                    render: {
+                        let view = cx.view();
+                        Box::new(move |cx| {
+                            view.update(cx, |view, cx| drag.render_drag_handle(view, cx))
+                        })
+                    },
                     drag_handle_view,
                     cursor_offset,
                     state: Box::new(drag.state),
@@ -888,6 +895,10 @@ where
     }
 }
 
+// impl<S, R, V, E> Render for Drag<S, R, V, E> {
+//     // fn render(&mut self, cx: ViewContext<Self>) ->
+// }
+
 #[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
 pub enum MouseButton {
     Left,

crates/gpui2/src/view.rs 🔗

@@ -3,48 +3,31 @@ use crate::{
     EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
 };
 use anyhow::{Context, Result};
-use parking_lot::Mutex;
-use std::{
-    marker::PhantomData,
-    sync::{Arc, Weak},
-};
+use std::{marker::PhantomData, sync::Arc};
 
-pub struct View<V> {
-    pub(crate) state: Model<V>,
-    render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
+pub trait Render: 'static + Sized {
+    type Element: Element<Self> + 'static + Send;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
 }
 
-impl<V: 'static> View<V> {
-    pub fn for_handle<E>(
-        state: Model<V>,
-        render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
-    ) -> View<V>
-    where
-        E: Component<V>,
-    {
-        View {
-            state,
-            render: Arc::new(Mutex::new(
-                move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
-            )),
-        }
-    }
+pub struct View<V> {
+    pub(crate) model: Model<V>,
 }
 
-impl<V: 'static> View<V> {
+impl<V: Render> View<V> {
     pub fn into_any(self) -> AnyView {
         AnyView(Arc::new(self))
     }
+}
 
+impl<V: 'static> View<V> {
     pub fn downgrade(&self) -> WeakView<V> {
         WeakView {
-            state: self.state.downgrade(),
-            render: Arc::downgrade(&self.render),
+            model: self.model.downgrade(),
         }
     }
-}
 
-impl<V: 'static> View<V> {
     pub fn update<C, R>(
         &self,
         cx: &mut C,
@@ -60,13 +43,12 @@ impl<V: 'static> View<V> {
 impl<V> Clone for View<V> {
     fn clone(&self) -> Self {
         Self {
-            state: self.state.clone(),
-            render: self.render.clone(),
+            model: self.model.clone(),
         }
     }
 }
 
-impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V> {
+impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
     fn render(self) -> AnyElement<ParentViewState> {
         AnyElement::new(EraseViewState {
             view: self,
@@ -75,11 +57,14 @@ impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V
     }
 }
 
-impl<V: 'static> Element<()> for View<V> {
+impl<V> Element<()> for View<V>
+where
+    V: Render,
+{
     type ElementState = AnyElement<V>;
 
     fn id(&self) -> Option<crate::ElementId> {
-        Some(ElementId::View(self.state.entity_id))
+        Some(ElementId::View(self.model.entity_id))
     }
 
     fn initialize(
@@ -89,7 +74,7 @@ impl<V: 'static> Element<()> for View<V> {
         cx: &mut ViewContext<()>,
     ) -> Self::ElementState {
         self.update(cx, |state, cx| {
-            let mut any_element = (self.render.lock())(state, cx);
+            let mut any_element = AnyElement::new(state.render(cx));
             any_element.initialize(state, cx);
             any_element
         })
@@ -116,15 +101,13 @@ impl<V: 'static> Element<()> for View<V> {
 }
 
 pub struct WeakView<V> {
-    pub(crate) state: WeakModel<V>,
-    render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
+    pub(crate) model: WeakModel<V>,
 }
 
 impl<V: 'static> WeakView<V> {
     pub fn upgrade(&self) -> Option<View<V>> {
-        let state = self.state.upgrade()?;
-        let render = self.render.upgrade()?;
-        Some(View { state, render })
+        let model = self.model.upgrade()?;
+        Some(View { model })
     }
 
     pub fn update<R>(
@@ -140,8 +123,7 @@ impl<V: 'static> WeakView<V> {
 impl<V> Clone for WeakView<V> {
     fn clone(&self) -> Self {
         Self {
-            state: self.state.clone(),
-            render: self.render.clone(),
+            model: self.model.clone(),
         }
     }
 }
@@ -153,13 +135,13 @@ struct EraseViewState<V, ParentV> {
 
 unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
 
-impl<V: 'static, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
+impl<V: Render, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
     fn render(self) -> AnyElement<ParentV> {
         AnyElement::new(self)
     }
 }
 
-impl<V: 'static, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
+impl<V: Render, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
     type ElementState = AnyBox;
 
     fn id(&self) -> Option<crate::ElementId> {
@@ -202,17 +184,20 @@ trait ViewObject: Send + Sync {
     fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
 }
 
-impl<V: 'static> ViewObject for View<V> {
+impl<V> ViewObject for View<V>
+where
+    V: Render,
+{
     fn entity_id(&self) -> EntityId {
-        self.state.entity_id
+        self.model.entity_id
     }
 
     fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
         cx.with_element_id(self.entity_id(), |_global_id, cx| {
             self.update(cx, |state, cx| {
-                let mut any_element = Box::new((self.render.lock())(state, cx));
+                let mut any_element = Box::new(AnyElement::new(state.render(cx)));
                 any_element.initialize(state, cx);
-                any_element as AnyBox
+                any_element
             })
         })
     }

crates/gpui2/src/window.rs 🔗

@@ -900,6 +900,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
                     if let Some(drag_handle_view) = &mut active_drag.drag_handle_view {
                         drag_handle_view.draw(available_space, cx);
                     }
+                    if let Some(render) = &mut active_drag.render {
+                        (render)()
+                    }
                     cx.active_drag = Some(active_drag);
                 });
             });
@@ -1300,7 +1303,7 @@ impl VisualContext for WindowContext<'_, '_> {
         view: &View<T>,
         update: impl FnOnce(&mut T, &mut Self::ViewContext<'_, '_, T>) -> R,
     ) -> Self::Result<R> {
-        let mut lease = self.app.entities.lease(&view.state);
+        let mut lease = self.app.entities.lease(&view.model);
         let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade());
         let result = update(&mut *lease, &mut cx);
         cx.app.entities.end_lease(lease);
@@ -1556,7 +1559,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     }
 
     pub fn model(&self) -> WeakModel<V> {
-        self.view.state.clone()
+        self.view.model.clone()
     }
 
     pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
@@ -1635,7 +1638,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     ) -> Subscription {
         let window_handle = self.window.handle;
         self.app.release_listeners.insert(
-            self.view.state.entity_id,
+            self.view.model.entity_id,
             Box::new(move |this, cx| {
                 let this = this.downcast_mut().expect("invalid entity type");
                 // todo!("are we okay with silently swallowing the error?")
@@ -1668,7 +1671,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     pub fn notify(&mut self) {
         self.window_cx.notify();
         self.window_cx.app.push_effect(Effect::Notify {
-            emitter: self.view.state.entity_id,
+            emitter: self.view.model.entity_id,
         });
     }
 
@@ -1848,7 +1851,7 @@ where
     V::Event: Any + Send,
 {
     pub fn emit(&mut self, event: V::Event) {
-        let emitter = self.view.state.entity_id;
+        let emitter = self.view.model.entity_id;
         self.app.push_effect(Effect::Emit {
             emitter,
             event: Box::new(event),