diff --git a/crates/gpui2/src/app/entity_map.rs b/crates/gpui2/src/app/entity_map.rs index f3ae67836d22edd3c5da0de5d83999b8b4a981b8..a1a070a91175c6bb08e28f78767dff8131a50ba5 100644 --- a/crates/gpui2/src/app/entity_map.rs +++ b/crates/gpui2/src/app/entity_map.rs @@ -1,4 +1,4 @@ -use crate::{AnyBox, AppContext, Context}; +use crate::{AnyBox, AppContext, Context, EntityHandle}; use anyhow::{anyhow, Result}; use derive_more::{Deref, DerefMut}; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; @@ -329,7 +329,26 @@ impl Eq for Handle {} impl PartialEq> for Handle { fn eq(&self, other: &WeakHandle) -> bool { - self.entity_id() == other.entity_id() + self.entity_id == other.entity_id + } +} + +impl EntityHandle for Handle { + type Weak = WeakHandle; + + fn entity_id(&self) -> EntityId { + self.entity_id + } + + fn downgrade(&self) -> Self::Weak { + self.downgrade() + } + + fn upgrade_from(weak: &Self::Weak) -> Option + where + Self: Sized, + { + weak.upgrade() } } @@ -457,6 +476,6 @@ impl Eq for WeakHandle {} impl PartialEq> for WeakHandle { fn eq(&self, other: &Handle) -> bool { - self.entity_id() == other.entity_id() + self.entity_id == other.entity_id } } diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index f6fa280c760b9a883aba3d816370f9ac7217e613..824236d3406334eac9f7f5af433b491661a5763b 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -106,6 +106,16 @@ pub trait VisualContext: Context { ) -> Self::Result; } +pub trait EntityHandle { + type Weak: 'static + Send; + + fn entity_id(&self) -> EntityId; + fn downgrade(&self) -> Self::Weak; + fn upgrade_from(weak: &Self::Weak) -> Option + where + Self: Sized; +} + pub enum GlobalKey { Numeric(usize), View(EntityId), diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 897026267f970e19f47453dd69592b14602c6be6..a61fd104412cf3288eca461bc0b96d1c83815dda 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,7 @@ use crate::{ - AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId, - EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle, - WindowContext, + AnyBox, AnyElement, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, Element, + ElementId, EntityHandle, EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, + VisualContext, WeakHandle, WindowContext, }; use anyhow::{Context, Result}; use parking_lot::Mutex; @@ -31,9 +31,7 @@ impl View { )), } } -} -impl View { pub fn into_any(self) -> AnyView { AnyView(Arc::new(self)) } @@ -44,9 +42,7 @@ impl View { render: Arc::downgrade(&self.render), } } -} -impl View { pub fn update( &self, cx: &mut C, @@ -58,11 +54,8 @@ impl View { cx.update_view(self, f) } - pub fn read(&self, cx: &mut C) -> &V - where - C: VisualContext, - { - todo!() + pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V { + cx.entities.read(&self.state) } } @@ -124,6 +117,25 @@ impl Element<()> for View { } } +impl EntityHandle for View { + type Weak = WeakView; + + fn entity_id(&self) -> EntityId { + self.state.entity_id + } + + fn downgrade(&self) -> Self::Weak { + self.downgrade() + } + + fn upgrade_from(weak: &Self::Weak) -> Option + where + Self: Sized, + { + weak.upgrade() + } +} + pub struct WeakView { pub(crate) state: WeakHandle, render: Weak) -> AnyElement + Send + 'static>>, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index e89c713d9383ce7a8b812b8d6ef8ccfe5a661490..0f2dcc7049b7455fb51b27fb8e9ef5297aded2e5 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,14 +1,14 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, - EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId, - GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, - Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, MonochromeSprite, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, - PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, - RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, - TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakHandle, WeakView, - WindowOptions, SUBPIXEL_VARIANTS, + EntityHandle, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, + GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, + KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, + MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, + PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, + RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, + Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, + WeakHandle, WeakView, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use collections::HashMap; @@ -376,6 +376,35 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.notify(); } + pub fn subscribe( + &mut self, + handle: &H, + mut on_event: impl FnMut(H, &E::Event, &mut WindowContext<'_, '_>) + Send + 'static, + ) -> Subscription + where + E: EventEmitter, + H: EntityHandle, + { + let entity_id = handle.entity_id(); + let handle = handle.downgrade(); + let window_handle = self.window.handle; + self.app.event_listeners.insert( + entity_id, + Box::new(move |event, cx| { + cx.update_window(window_handle, |cx| { + if let Some(handle) = H::upgrade_from(&handle) { + let event = event.downcast_ref().expect("invalid event type"); + on_event(handle, event, cx); + true + } else { + false + } + }) + .unwrap_or(false) + }), + ) + } + /// Schedule the given closure to be run on the main thread. It will be invoked with /// a `MainThread`, which provides access to platform-specific functionality /// of the window. @@ -1600,21 +1629,24 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { ) } - pub fn subscribe( + pub fn subscribe( &mut self, - handle: &Handle, - mut on_event: impl FnMut(&mut V, Handle, &E::Event, &mut ViewContext<'_, '_, V>) - + Send - + 'static, - ) -> Subscription { + handle: &H, + mut on_event: impl FnMut(&mut V, H, &E::Event, &mut ViewContext<'_, '_, V>) + Send + 'static, + ) -> Subscription + where + E: EventEmitter, + H: EntityHandle, + { let view = self.view(); + let entity_id = handle.entity_id(); let handle = handle.downgrade(); let window_handle = self.window.handle; self.app.event_listeners.insert( - handle.entity_id, + entity_id, Box::new(move |event, cx| { cx.update_window(window_handle, |cx| { - if let Some(handle) = handle.upgrade() { + if let Some(handle) = H::upgrade_from(&handle) { let event = event.downcast_ref().expect("invalid event type"); view.update(cx, |this, cx| on_event(this, handle, event, cx)) .is_ok() diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index aedbcd83939a97d75d0de6b1e04a7ba9d6d92ad9..90d08d6c4ad4fd2fed2acd598f1918abd088c6a5 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -104,30 +104,26 @@ pub trait Item: EventEmitter + Sized { // fn navigate(&mut self, _: Box, _: &mut ViewContext) -> bool { // false // } - // fn tab_tooltip_text(&self, _: &AppContext) -> Option> { - // None - // } - // fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option> { - // None - // } - // fn tab_content( - // &self, - // detail: Option, - // style: &theme2::Tab, - // cx: &AppContext, - // ) -> AnyElement; - // fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project2::Item)) { - // } // (model id, Item) + fn tab_tooltip_text(&self, _: &AppContext) -> Option { + None + } + fn tab_description(&self, _: usize, _: &AppContext) -> Option { + None + } + fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement; + + fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project2::Item)) { + } // (model id, Item) fn is_singleton(&self, _cx: &AppContext) -> bool { false } // fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext) {} - // fn clone_on_split(&self, _workspace_id: WorkspaceId, _: &mut ViewContext) -> Option - // where - // Self: Sized, - // { - // None - // } + fn clone_on_split(&self, _workspace_id: WorkspaceId, _: &mut ViewContext) -> Option + where + Self: Sized, + { + None + } // fn is_dirty(&self, _: &AppContext) -> bool { // false // } @@ -221,7 +217,6 @@ pub trait Item: EventEmitter + Sized { use std::{ any::Any, - borrow::Cow, cell::RefCell, ops::Range, path::PathBuf, @@ -235,7 +230,7 @@ use std::{ use gpui2::{ AnyElement, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, Point, - Task, View, ViewContext, WindowContext, + SharedString, Task, View, ViewContext, VisualContext, WindowContext, }; use project2::{Project, ProjectEntryId, ProjectPath}; use smallvec::SmallVec; @@ -252,10 +247,10 @@ pub trait ItemHandle: 'static + Send { fn subscribe_to_item_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> gpui2::Subscription; - fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option>; - fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option>; + fn tab_tooltip_text(&self, cx: &AppContext) -> Option; + fn tab_description(&self, detail: usize, cx: &AppContext) -> Option; fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement; fn dragged_tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement; fn project_path(&self, cx: &AppContext) -> Option; @@ -329,7 +324,7 @@ impl ItemHandle for View { fn subscribe_to_item_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> gpui2::Subscription { cx.subscribe(self, move |_, event, cx| { for item_event in T::to_item_events(event) { @@ -338,11 +333,11 @@ impl ItemHandle for View { }) } - fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, cx: &AppContext) -> Option { self.read(cx).tab_tooltip_text(cx) } - fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { + fn tab_description(&self, detail: usize, cx: &AppContext) -> Option { self.read(cx).tab_description(detail, cx) }