Simplify AnyView
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
6a3974ddbb
commit
7b6514b178
5 changed files with 112 additions and 138 deletions
|
@ -829,7 +829,7 @@ impl MainThread<AppContext> {
|
||||||
let handle = WindowHandle::new(id);
|
let handle = WindowHandle::new(id);
|
||||||
let mut window = Window::new(handle.into(), options, cx);
|
let mut window = Window::new(handle.into(), options, cx);
|
||||||
let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window));
|
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);
|
cx.windows.get_mut(id).unwrap().replace(window);
|
||||||
handle
|
handle
|
||||||
})
|
})
|
||||||
|
|
|
@ -328,7 +328,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
||||||
);
|
);
|
||||||
self.stateful_interaction().drag_listener =
|
self.stateful_interaction().drag_listener =
|
||||||
Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
|
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,
|
cursor_offset,
|
||||||
}));
|
}));
|
||||||
self
|
self
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
ViewContext, VisualContext, WeakModel, WindowContext,
|
ViewContext, VisualContext, WeakModel, WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::{any::TypeId, marker::PhantomData, sync::Arc};
|
use std::{any::TypeId, marker::PhantomData};
|
||||||
|
|
||||||
pub trait Render: 'static + Sized {
|
pub trait Render: 'static + Sized {
|
||||||
type Element: Element<Self> + 'static + Send;
|
type Element: Element<Self> + 'static + Send;
|
||||||
|
@ -18,12 +18,6 @@ pub struct View<V> {
|
||||||
|
|
||||||
impl<V> Sealed for View<V> {}
|
impl<V> Sealed for View<V> {}
|
||||||
|
|
||||||
impl<V: Render> View<V> {
|
|
||||||
pub fn into_any(self) -> AnyView {
|
|
||||||
AnyView(Arc::new(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: 'static> Entity<V> for View<V> {
|
impl<V: 'static> Entity<V> for View<V> {
|
||||||
type Weak = WeakView<V>;
|
type Weak = WeakView<V>;
|
||||||
|
|
||||||
|
@ -265,94 +259,110 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AnyView(Arc<dyn ViewObject>);
|
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 {
|
impl AnyView {
|
||||||
pub fn downcast<V: 'static + Send>(self) -> Result<View<V>, AnyView> {
|
pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
|
||||||
self.0
|
match self.model.downcast() {
|
||||||
.model()
|
Ok(model) => Ok(View { model }),
|
||||||
.downcast()
|
Err(model) => Err(Self {
|
||||||
.map(|model| View { model })
|
model,
|
||||||
.map_err(|_| self)
|
initialize: self.initialize,
|
||||||
|
layout: self.layout,
|
||||||
|
paint: self.paint,
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn entity_type(&self) -> TypeId {
|
pub(crate) fn entity_type(&self) -> TypeId {
|
||||||
self.0.entity_type()
|
self.model.entity_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
|
pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
|
||||||
let mut rendered_element = self.0.initialize(cx);
|
let mut rendered_element = (self.initialize)(self, cx);
|
||||||
let layout_id = self.0.layout(&mut rendered_element, cx);
|
let layout_id = (self.layout)(self, &mut rendered_element, cx);
|
||||||
cx.window
|
cx.window
|
||||||
.layout_engine
|
.layout_engine
|
||||||
.compute_layout(layout_id, available_space);
|
.compute_layout(layout_id, available_space);
|
||||||
let bounds = cx.window.layout_engine.layout_bounds(layout_id);
|
(self.paint)(self, &mut rendered_element, cx);
|
||||||
self.0.paint(bounds, &mut rendered_element, cx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ParentV: 'static> Component<ParentV> for AnyView {
|
impl<V: 'static> Component<V> for AnyView {
|
||||||
fn render(self) -> AnyElement<ParentV> {
|
fn render(self) -> AnyElement<V> {
|
||||||
AnyElement::new(EraseAnyViewState {
|
AnyElement::new(self)
|
||||||
view: self,
|
|
||||||
parent_view_state_type: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element<()> for AnyView {
|
impl<V: Render> From<View<V>> for AnyView {
|
||||||
|
fn from(value: View<V>) -> Self {
|
||||||
|
AnyView {
|
||||||
|
model: value.model.into_any(),
|
||||||
|
initialize: |view, cx| {
|
||||||
|
cx.with_element_id(view.model.entity_id, |_, cx| {
|
||||||
|
let view = view.clone().downcast::<V>().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::<V>().unwrap();
|
||||||
|
let element = element.downcast_mut::<AnyElement<V>>().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::<V>().unwrap();
|
||||||
|
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
||||||
|
view.update(cx, |view, cx| element.paint(view, cx))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
|
||||||
type ElementState = AnyBox;
|
type ElementState = AnyBox;
|
||||||
|
|
||||||
fn id(&self) -> Option<crate::ElementId> {
|
fn id(&self) -> Option<ElementId> {
|
||||||
Some(ElementId::View(self.0.entity_id()))
|
Some(self.model.entity_id.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(
|
fn initialize(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut (),
|
_view_state: &mut ParentViewState,
|
||||||
_: Option<Self::ElementState>,
|
_element_state: Option<Self::ElementState>,
|
||||||
cx: &mut ViewContext<()>,
|
cx: &mut ViewContext<ParentViewState>,
|
||||||
) -> Self::ElementState {
|
) -> Self::ElementState {
|
||||||
self.0.initialize(cx)
|
(self.initialize)(self, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut (),
|
_view_state: &mut ParentViewState,
|
||||||
element: &mut Self::ElementState,
|
rendered_element: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<()>,
|
cx: &mut ViewContext<ParentViewState>,
|
||||||
) -> LayoutId {
|
) -> LayoutId {
|
||||||
self.0.layout(element, cx)
|
(self.layout)(self, rendered_element, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_: &mut (),
|
_view_state: &mut ParentViewState,
|
||||||
element: &mut AnyBox,
|
rendered_element: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<()>,
|
cx: &mut ViewContext<ParentViewState>,
|
||||||
) {
|
) {
|
||||||
self.0.paint(bounds, element, cx)
|
(self.paint)(self, rendered_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<ParentViewState> {
|
|
||||||
view: AnyView,
|
|
||||||
parent_view_state_type: PhantomData<ParentViewState>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<ParentV> Send for EraseAnyViewState<ParentV> {}
|
|
||||||
|
|
||||||
impl<ParentV: 'static> Component<ParentV> for EraseAnyViewState<ParentV> {
|
|
||||||
fn render(self) -> AnyElement<ParentV> {
|
|
||||||
AnyElement::new(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,39 +377,3 @@ where
|
||||||
(self)(cx)
|
(self)(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ParentV: 'static> Element<ParentV> for EraseAnyViewState<ParentV> {
|
|
||||||
type ElementState = AnyBox;
|
|
||||||
|
|
||||||
fn id(&self) -> Option<crate::ElementId> {
|
|
||||||
Element::id(&self.view)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initialize(
|
|
||||||
&mut self,
|
|
||||||
_: &mut ParentV,
|
|
||||||
_: Option<Self::ElementState>,
|
|
||||||
cx: &mut ViewContext<ParentV>,
|
|
||||||
) -> Self::ElementState {
|
|
||||||
self.view.0.initialize(cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout(
|
|
||||||
&mut self,
|
|
||||||
_: &mut ParentV,
|
|
||||||
element: &mut Self::ElementState,
|
|
||||||
cx: &mut ViewContext<ParentV>,
|
|
||||||
) -> LayoutId {
|
|
||||||
self.view.0.layout(element, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(
|
|
||||||
&mut self,
|
|
||||||
bounds: Bounds<Pixels>,
|
|
||||||
_: &mut ParentV,
|
|
||||||
element: &mut Self::ElementState,
|
|
||||||
cx: &mut ViewContext<ParentV>,
|
|
||||||
) {
|
|
||||||
self.view.0.paint(bounds, element, cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -967,7 +967,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
self.window.mouse_position = position;
|
self.window.mouse_position = position;
|
||||||
if self.active_drag.is_none() {
|
if self.active_drag.is_none() {
|
||||||
self.active_drag = Some(AnyDrag {
|
self.active_drag = Some(AnyDrag {
|
||||||
view: self.build_view(|_| files).into_any(),
|
view: self.build_view(|_| files).into(),
|
||||||
cursor_offset: position,
|
cursor_offset: position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,17 @@ pub enum ElementStory {
|
||||||
impl ElementStory {
|
impl ElementStory {
|
||||||
pub fn story(&self, cx: &mut WindowContext) -> AnyView {
|
pub fn story(&self, cx: &mut WindowContext) -> AnyView {
|
||||||
match self {
|
match self {
|
||||||
Self::Colors => cx.build_view(|_| ColorsStory).into_any(),
|
Self::Colors => cx.build_view(|_| ColorsStory).into(),
|
||||||
Self::Avatar => cx.build_view(|_| AvatarStory).into_any(),
|
Self::Avatar => cx.build_view(|_| AvatarStory).into(),
|
||||||
Self::Button => cx.build_view(|_| ButtonStory).into_any(),
|
Self::Button => cx.build_view(|_| ButtonStory).into(),
|
||||||
Self::Details => cx.build_view(|_| DetailsStory).into_any(),
|
Self::Details => cx.build_view(|_| DetailsStory).into(),
|
||||||
Self::Focus => FocusStory::view(cx).into_any(),
|
Self::Focus => FocusStory::view(cx).into(),
|
||||||
Self::Icon => cx.build_view(|_| IconStory).into_any(),
|
Self::Icon => cx.build_view(|_| IconStory).into(),
|
||||||
Self::Input => cx.build_view(|_| InputStory).into_any(),
|
Self::Input => cx.build_view(|_| InputStory).into(),
|
||||||
Self::Label => cx.build_view(|_| LabelStory).into_any(),
|
Self::Label => cx.build_view(|_| LabelStory).into(),
|
||||||
Self::Scroll => ScrollStory::view(cx).into_any(),
|
Self::Scroll => ScrollStory::view(cx).into(),
|
||||||
Self::Text => TextStory::view(cx).into_any(),
|
Self::Text => TextStory::view(cx).into(),
|
||||||
Self::ZIndex => cx.build_view(|_| ZIndexStory).into_any(),
|
Self::ZIndex => cx.build_view(|_| ZIndexStory).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,32 +77,32 @@ pub enum ComponentStory {
|
||||||
impl ComponentStory {
|
impl ComponentStory {
|
||||||
pub fn story(&self, cx: &mut WindowContext) -> AnyView {
|
pub fn story(&self, cx: &mut WindowContext) -> AnyView {
|
||||||
match self {
|
match self {
|
||||||
Self::AssistantPanel => cx.build_view(|_| ui::AssistantPanelStory).into_any(),
|
Self::AssistantPanel => cx.build_view(|_| ui::AssistantPanelStory).into(),
|
||||||
Self::Buffer => cx.build_view(|_| ui::BufferStory).into_any(),
|
Self::Buffer => cx.build_view(|_| ui::BufferStory).into(),
|
||||||
Self::Breadcrumb => cx.build_view(|_| ui::BreadcrumbStory).into_any(),
|
Self::Breadcrumb => cx.build_view(|_| ui::BreadcrumbStory).into(),
|
||||||
Self::ChatPanel => cx.build_view(|_| ui::ChatPanelStory).into_any(),
|
Self::ChatPanel => cx.build_view(|_| ui::ChatPanelStory).into(),
|
||||||
Self::CollabPanel => cx.build_view(|_| ui::CollabPanelStory).into_any(),
|
Self::CollabPanel => cx.build_view(|_| ui::CollabPanelStory).into(),
|
||||||
Self::CommandPalette => cx.build_view(|_| ui::CommandPaletteStory).into_any(),
|
Self::CommandPalette => cx.build_view(|_| ui::CommandPaletteStory).into(),
|
||||||
Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into_any(),
|
Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into(),
|
||||||
Self::Facepile => cx.build_view(|_| ui::FacepileStory).into_any(),
|
Self::Facepile => cx.build_view(|_| ui::FacepileStory).into(),
|
||||||
Self::Keybinding => cx.build_view(|_| ui::KeybindingStory).into_any(),
|
Self::Keybinding => cx.build_view(|_| ui::KeybindingStory).into(),
|
||||||
Self::LanguageSelector => cx.build_view(|_| ui::LanguageSelectorStory).into_any(),
|
Self::LanguageSelector => cx.build_view(|_| ui::LanguageSelectorStory).into(),
|
||||||
Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into_any(),
|
Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into(),
|
||||||
Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into_any(),
|
Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into(),
|
||||||
Self::Palette => cx.build_view(|cx| ui::PaletteStory).into_any(),
|
Self::Palette => cx.build_view(|cx| ui::PaletteStory).into(),
|
||||||
Self::Panel => cx.build_view(|cx| ui::PanelStory).into_any(),
|
Self::Panel => cx.build_view(|cx| ui::PanelStory).into(),
|
||||||
Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into_any(),
|
Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into(),
|
||||||
Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into_any(),
|
Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into(),
|
||||||
Self::Tab => cx.build_view(|_| ui::TabStory).into_any(),
|
Self::Tab => cx.build_view(|_| ui::TabStory).into(),
|
||||||
Self::TabBar => cx.build_view(|_| ui::TabBarStory).into_any(),
|
Self::TabBar => cx.build_view(|_| ui::TabBarStory).into(),
|
||||||
Self::Terminal => cx.build_view(|_| ui::TerminalStory).into_any(),
|
Self::Terminal => cx.build_view(|_| ui::TerminalStory).into(),
|
||||||
Self::ThemeSelector => cx.build_view(|_| ui::ThemeSelectorStory).into_any(),
|
Self::ThemeSelector => cx.build_view(|_| ui::ThemeSelectorStory).into(),
|
||||||
Self::Toast => cx.build_view(|_| ui::ToastStory).into_any(),
|
Self::Toast => cx.build_view(|_| ui::ToastStory).into(),
|
||||||
Self::Toolbar => cx.build_view(|_| ui::ToolbarStory).into_any(),
|
Self::Toolbar => cx.build_view(|_| ui::ToolbarStory).into(),
|
||||||
Self::TrafficLights => cx.build_view(|_| ui::TrafficLightsStory).into_any(),
|
Self::TrafficLights => cx.build_view(|_| ui::TrafficLightsStory).into(),
|
||||||
Self::Copilot => cx.build_view(|_| ui::CopilotModalStory).into_any(),
|
Self::Copilot => cx.build_view(|_| ui::CopilotModalStory).into(),
|
||||||
Self::TitleBar => ui::TitleBarStory::view(cx).into_any(),
|
Self::TitleBar => ui::TitleBarStory::view(cx).into(),
|
||||||
Self::Workspace => ui::WorkspaceStory::view(cx).into_any(),
|
Self::Workspace => ui::WorkspaceStory::view(cx).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ impl StorySelector {
|
||||||
match self {
|
match self {
|
||||||
Self::Element(element_story) => element_story.story(cx),
|
Self::Element(element_story) => element_story.story(cx),
|
||||||
Self::Component(component_story) => component_story.story(cx),
|
Self::Component(component_story) => component_story.story(cx),
|
||||||
Self::KitchenSink => KitchenSinkStory::view(cx).into_any(),
|
Self::KitchenSink => KitchenSinkStory::view(cx).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue