diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 88edcb457f..a49b2aaa1c 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -829,7 +829,7 @@ impl MainThread { let handle = WindowHandle::new(id); let mut window = Window::new(handle.into(), options, cx); let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); - window.root_view.replace(root_view.into_any()); + window.root_view.replace(root_view.into()); cx.windows.get_mut(id).unwrap().replace(window); handle }) diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 317d7cea61..5a37c3ee7a 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -328,7 +328,7 @@ pub trait StatefulInteractive: StatelessInteractive { ); self.stateful_interaction().drag_listener = Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag { - view: listener(view_state, cx).into_any(), + view: listener(view_state, cx).into(), cursor_offset, })); self diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 3c3ad034b4..e702fcb274 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -4,7 +4,7 @@ use crate::{ ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; -use std::{any::TypeId, marker::PhantomData, sync::Arc}; +use std::{any::TypeId, marker::PhantomData}; pub trait Render: 'static + Sized { type Element: Element + 'static + Send; @@ -18,12 +18,6 @@ pub struct View { impl Sealed for View {} -impl View { - pub fn into_any(self) -> AnyView { - AnyView(Arc::new(self)) - } -} - impl Entity for View { type Weak = WeakView; @@ -265,94 +259,110 @@ where } } -#[derive(Clone)] -pub struct AnyView(Arc); +#[derive(Clone, Debug)] +pub struct AnyView { + model: AnyModel, + initialize: fn(&Self, &mut WindowContext) -> AnyBox, + layout: fn(&Self, &mut AnyBox, &mut WindowContext) -> LayoutId, + paint: fn(&Self, &mut AnyBox, &mut WindowContext), +} impl AnyView { - pub fn downcast(self) -> Result, AnyView> { - self.0 - .model() - .downcast() - .map(|model| View { model }) - .map_err(|_| self) + pub fn downcast(self) -> Result, Self> { + match self.model.downcast() { + Ok(model) => Ok(View { model }), + Err(model) => Err(Self { + model, + initialize: self.initialize, + layout: self.layout, + paint: self.paint, + }), + } } pub(crate) fn entity_type(&self) -> TypeId { - self.0.entity_type() + self.model.entity_type } pub(crate) fn draw(&self, available_space: Size, cx: &mut WindowContext) { - let mut rendered_element = self.0.initialize(cx); - let layout_id = self.0.layout(&mut rendered_element, cx); + let mut rendered_element = (self.initialize)(self, cx); + let layout_id = (self.layout)(self, &mut rendered_element, cx); cx.window .layout_engine .compute_layout(layout_id, available_space); - let bounds = cx.window.layout_engine.layout_bounds(layout_id); - self.0.paint(bounds, &mut rendered_element, cx); + (self.paint)(self, &mut rendered_element, cx); } } -impl Component for AnyView { - fn render(self) -> AnyElement { - AnyElement::new(EraseAnyViewState { - view: self, - parent_view_state_type: PhantomData, - }) +impl Component for AnyView { + fn render(self) -> AnyElement { + AnyElement::new(self) } } -impl Element<()> for AnyView { +impl From> for AnyView { + fn from(value: View) -> Self { + AnyView { + model: value.model.into_any(), + initialize: |view, cx| { + cx.with_element_id(view.model.entity_id, |_, cx| { + let view = view.clone().downcast::().unwrap(); + Box::new(AnyElement::new( + view.update(cx, |view, cx| Render::render(view, cx)), + )) + }) + }, + layout: |view, element, cx| { + cx.with_element_id(view.model.entity_id, |_, cx| { + let view = view.clone().downcast::().unwrap(); + let element = element.downcast_mut::>().unwrap(); + view.update(cx, |view, cx| element.layout(view, cx)) + }) + }, + paint: |view, element, cx| { + cx.with_element_id(view.model.entity_id, |_, cx| { + let view = view.clone().downcast::().unwrap(); + let element = element.downcast_mut::>().unwrap(); + view.update(cx, |view, cx| element.paint(view, cx)) + }) + }, + } + } +} + +impl Element for AnyView { type ElementState = AnyBox; - fn id(&self) -> Option { - Some(ElementId::View(self.0.entity_id())) + fn id(&self) -> Option { + Some(self.model.entity_id.into()) } fn initialize( &mut self, - _: &mut (), - _: Option, - cx: &mut ViewContext<()>, + _view_state: &mut ParentViewState, + _element_state: Option, + cx: &mut ViewContext, ) -> Self::ElementState { - self.0.initialize(cx) + (self.initialize)(self, cx) } fn layout( &mut self, - _: &mut (), - element: &mut Self::ElementState, - cx: &mut ViewContext<()>, + _view_state: &mut ParentViewState, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, ) -> LayoutId { - self.0.layout(element, cx) + (self.layout)(self, rendered_element, cx) } fn paint( &mut self, - bounds: Bounds, - _: &mut (), - element: &mut AnyBox, - cx: &mut ViewContext<()>, + _bounds: Bounds, + _view_state: &mut ParentViewState, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, ) { - self.0.paint(bounds, element, cx) - } -} - -impl std::fmt::Debug for AnyView { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.debug(f) - } -} - -struct EraseAnyViewState { - view: AnyView, - parent_view_state_type: PhantomData, -} - -unsafe impl Send for EraseAnyViewState {} - -impl Component for EraseAnyViewState { - fn render(self) -> AnyElement { - AnyElement::new(self) + (self.paint)(self, rendered_element, cx) } } @@ -367,39 +377,3 @@ where (self)(cx) } } - -impl Element for EraseAnyViewState { - type ElementState = AnyBox; - - fn id(&self) -> Option { - Element::id(&self.view) - } - - fn initialize( - &mut self, - _: &mut ParentV, - _: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - self.view.0.initialize(cx) - } - - fn layout( - &mut self, - _: &mut ParentV, - element: &mut Self::ElementState, - cx: &mut ViewContext, - ) -> LayoutId { - self.view.0.layout(element, cx) - } - - fn paint( - &mut self, - bounds: Bounds, - _: &mut ParentV, - element: &mut Self::ElementState, - cx: &mut ViewContext, - ) { - self.view.0.paint(bounds, element, cx) - } -} diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 7898ac34fc..3997a3197f 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -967,7 +967,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.window.mouse_position = position; if self.active_drag.is_none() { self.active_drag = Some(AnyDrag { - view: self.build_view(|_| files).into_any(), + view: self.build_view(|_| files).into(), cursor_offset: position, }); } diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 30d31f8cf3..968309bd8a 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -28,17 +28,17 @@ pub enum ElementStory { impl ElementStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - Self::Colors => cx.build_view(|_| ColorsStory).into_any(), - Self::Avatar => cx.build_view(|_| AvatarStory).into_any(), - Self::Button => cx.build_view(|_| ButtonStory).into_any(), - Self::Details => cx.build_view(|_| DetailsStory).into_any(), - Self::Focus => FocusStory::view(cx).into_any(), - Self::Icon => cx.build_view(|_| IconStory).into_any(), - Self::Input => cx.build_view(|_| InputStory).into_any(), - Self::Label => cx.build_view(|_| LabelStory).into_any(), - Self::Scroll => ScrollStory::view(cx).into_any(), - Self::Text => TextStory::view(cx).into_any(), - Self::ZIndex => cx.build_view(|_| ZIndexStory).into_any(), + Self::Colors => cx.build_view(|_| ColorsStory).into(), + Self::Avatar => cx.build_view(|_| AvatarStory).into(), + Self::Button => cx.build_view(|_| ButtonStory).into(), + Self::Details => cx.build_view(|_| DetailsStory).into(), + Self::Focus => FocusStory::view(cx).into(), + Self::Icon => cx.build_view(|_| IconStory).into(), + Self::Input => cx.build_view(|_| InputStory).into(), + Self::Label => cx.build_view(|_| LabelStory).into(), + Self::Scroll => ScrollStory::view(cx).into(), + Self::Text => TextStory::view(cx).into(), + Self::ZIndex => cx.build_view(|_| ZIndexStory).into(), } } } @@ -77,32 +77,32 @@ pub enum ComponentStory { impl ComponentStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - Self::AssistantPanel => cx.build_view(|_| ui::AssistantPanelStory).into_any(), - Self::Buffer => cx.build_view(|_| ui::BufferStory).into_any(), - Self::Breadcrumb => cx.build_view(|_| ui::BreadcrumbStory).into_any(), - Self::ChatPanel => cx.build_view(|_| ui::ChatPanelStory).into_any(), - Self::CollabPanel => cx.build_view(|_| ui::CollabPanelStory).into_any(), - Self::CommandPalette => cx.build_view(|_| ui::CommandPaletteStory).into_any(), - Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into_any(), - Self::Facepile => cx.build_view(|_| ui::FacepileStory).into_any(), - Self::Keybinding => cx.build_view(|_| ui::KeybindingStory).into_any(), - Self::LanguageSelector => cx.build_view(|_| ui::LanguageSelectorStory).into_any(), - Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into_any(), - Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into_any(), - Self::Palette => cx.build_view(|cx| ui::PaletteStory).into_any(), - Self::Panel => cx.build_view(|cx| ui::PanelStory).into_any(), - Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into_any(), - Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into_any(), - Self::Tab => cx.build_view(|_| ui::TabStory).into_any(), - Self::TabBar => cx.build_view(|_| ui::TabBarStory).into_any(), - Self::Terminal => cx.build_view(|_| ui::TerminalStory).into_any(), - Self::ThemeSelector => cx.build_view(|_| ui::ThemeSelectorStory).into_any(), - Self::Toast => cx.build_view(|_| ui::ToastStory).into_any(), - Self::Toolbar => cx.build_view(|_| ui::ToolbarStory).into_any(), - Self::TrafficLights => cx.build_view(|_| ui::TrafficLightsStory).into_any(), - Self::Copilot => cx.build_view(|_| ui::CopilotModalStory).into_any(), - Self::TitleBar => ui::TitleBarStory::view(cx).into_any(), - Self::Workspace => ui::WorkspaceStory::view(cx).into_any(), + Self::AssistantPanel => cx.build_view(|_| ui::AssistantPanelStory).into(), + Self::Buffer => cx.build_view(|_| ui::BufferStory).into(), + Self::Breadcrumb => cx.build_view(|_| ui::BreadcrumbStory).into(), + Self::ChatPanel => cx.build_view(|_| ui::ChatPanelStory).into(), + Self::CollabPanel => cx.build_view(|_| ui::CollabPanelStory).into(), + Self::CommandPalette => cx.build_view(|_| ui::CommandPaletteStory).into(), + Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into(), + Self::Facepile => cx.build_view(|_| ui::FacepileStory).into(), + Self::Keybinding => cx.build_view(|_| ui::KeybindingStory).into(), + Self::LanguageSelector => cx.build_view(|_| ui::LanguageSelectorStory).into(), + Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into(), + Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into(), + Self::Palette => cx.build_view(|cx| ui::PaletteStory).into(), + Self::Panel => cx.build_view(|cx| ui::PanelStory).into(), + Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into(), + Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into(), + Self::Tab => cx.build_view(|_| ui::TabStory).into(), + Self::TabBar => cx.build_view(|_| ui::TabBarStory).into(), + Self::Terminal => cx.build_view(|_| ui::TerminalStory).into(), + Self::ThemeSelector => cx.build_view(|_| ui::ThemeSelectorStory).into(), + Self::Toast => cx.build_view(|_| ui::ToastStory).into(), + Self::Toolbar => cx.build_view(|_| ui::ToolbarStory).into(), + Self::TrafficLights => cx.build_view(|_| ui::TrafficLightsStory).into(), + Self::Copilot => cx.build_view(|_| ui::CopilotModalStory).into(), + Self::TitleBar => ui::TitleBarStory::view(cx).into(), + Self::Workspace => ui::WorkspaceStory::view(cx).into(), } } } @@ -149,7 +149,7 @@ impl StorySelector { match self { Self::Element(element_story) => element_story.story(cx), Self::Component(component_story) => component_story.story(cx), - Self::KitchenSink => KitchenSinkStory::view(cx).into_any(), + Self::KitchenSink => KitchenSinkStory::view(cx).into(), } } }